mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-08 05:47:47 +08:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
941c56e69e | ||
![]() |
a28b871a46 | ||
![]() |
387f5d58f7 | ||
![]() |
7d846b2060 |
@@ -159,6 +159,11 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
default:
|
||||
}
|
||||
|
||||
if strings.EqualFold(r.FilterString(), "(objectClass=*)") && (string(r.BaseObject()) == "" || strings.EqualFold(string(r.BaseObject()), "cn=Subschema")) {
|
||||
handleRootSearch(w, &r, &res, m)
|
||||
return
|
||||
}
|
||||
|
||||
var isGroupSearch bool = false
|
||||
filter := r.Filter()
|
||||
if eq, ok := filter.(message.FilterEqualityMatch); ok && strings.EqualFold(string(eq.AttributeDesc()), "objectClass") && strings.EqualFold(string(eq.AssertionValue()), "posixGroup") {
|
||||
@@ -229,6 +234,46 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
w.Write(res)
|
||||
}
|
||||
|
||||
func handleRootSearch(w ldap.ResponseWriter, r *message.SearchRequest, res *message.SearchResultDone, m *ldap.Message) {
|
||||
if len(r.Attributes()) == 0 {
|
||||
w.Write(res)
|
||||
return
|
||||
}
|
||||
firstAttr := string(r.Attributes()[0])
|
||||
|
||||
if string(r.BaseObject()) == "" {
|
||||
// Handle special root DSE requests
|
||||
if strings.EqualFold(firstAttr, "namingContexts") {
|
||||
orgs, code := GetFilteredOrganizations(m)
|
||||
if code != ldap.LDAPResultSuccess {
|
||||
res.SetResultCode(code)
|
||||
w.Write(res)
|
||||
return
|
||||
}
|
||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
||||
dnlist := make([]message.AttributeValue, len(orgs))
|
||||
for i, org := range orgs {
|
||||
dnlist[i] = message.AttributeValue(fmt.Sprintf("ou=%s", org.Name))
|
||||
}
|
||||
e.AddAttribute("namingContexts", dnlist...)
|
||||
w.Write(e)
|
||||
} else if strings.EqualFold(firstAttr, "subschemaSubentry") {
|
||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
||||
e.AddAttribute("subschemaSubentry", message.AttributeValue("cn=Subschema"))
|
||||
w.Write(e)
|
||||
}
|
||||
} else if strings.EqualFold(firstAttr, "objectclasses") && strings.EqualFold(string(r.BaseObject()), "cn=Subschema") {
|
||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
||||
e.AddAttribute("objectClasses", []message.AttributeValue{
|
||||
"( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )",
|
||||
"( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a group of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( userPassword $ memberUid $ description ) )",
|
||||
}...)
|
||||
w.Write(e)
|
||||
}
|
||||
|
||||
w.Write(res)
|
||||
}
|
||||
|
||||
func hash(s string) uint32 {
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(s))
|
||||
|
23
ldap/util.go
23
ldap/util.go
@@ -358,6 +358,29 @@ func GetFilteredGroups(m *ldap.Message, baseDN string, filterStr string) ([]*obj
|
||||
return groups, ldap.LDAPResultSuccess
|
||||
}
|
||||
|
||||
func GetFilteredOrganizations(m *ldap.Message) ([]*object.Organization, int) {
|
||||
if m.Client.IsGlobalAdmin {
|
||||
organizations, err := object.GetOrganizations("")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return organizations, ldap.LDAPResultSuccess
|
||||
} else if m.Client.IsOrgAdmin {
|
||||
requestUserId := util.GetId(m.Client.OrgName, m.Client.UserName)
|
||||
user, err := object.GetUser(requestUserId)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
organization, err := object.GetOrganizationByUser(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return []*object.Organization{organization}, ldap.LDAPResultSuccess
|
||||
} else {
|
||||
return nil, ldap.LDAPResultInsufficientAccessRights
|
||||
}
|
||||
}
|
||||
|
||||
// get user password with hash type prefix
|
||||
// TODO not handle salt yet
|
||||
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
@@ -341,10 +342,31 @@ func getClaimsCustom(claims Claims, tokenField []string) jwt.MapClaims {
|
||||
res["provider"] = claims.Provider
|
||||
|
||||
for _, field := range tokenField {
|
||||
userField := userValue.FieldByName(field)
|
||||
if userField.IsValid() {
|
||||
newfield := util.SnakeToCamel(util.CamelToSnakeCase(field))
|
||||
res[newfield] = userField.Interface()
|
||||
if strings.HasPrefix(field, "Properties") {
|
||||
/*
|
||||
Use selected properties fields as custom claims.
|
||||
Converts `Properties.my_field` to custom claim with name `my_field`.
|
||||
*/
|
||||
parts := strings.Split(field, ".")
|
||||
if len(parts) != 2 || parts[0] != "Properties" { // Either too many segments, or not properly scoped to `Properties`, so skip.
|
||||
continue
|
||||
}
|
||||
base, fieldName := parts[0], parts[1]
|
||||
mField := userValue.FieldByName(base)
|
||||
if !mField.IsValid() { // Can't find `Properties` field, so skip.
|
||||
continue
|
||||
}
|
||||
finalField := mField.MapIndex(reflect.ValueOf(fieldName))
|
||||
if finalField.IsValid() { // // Provided field within `Properties` exists, add claim.
|
||||
res[fieldName] = finalField.Interface()
|
||||
}
|
||||
|
||||
} else { // Use selected user field as claims.
|
||||
userField := userValue.FieldByName(field)
|
||||
if userField.IsValid() {
|
||||
newfield := util.SnakeToCamel(util.CamelToSnakeCase(field))
|
||||
res[newfield] = userField.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,6 +403,14 @@ func generateJwtToken(application *Application, user *User, provider string, non
|
||||
refreshExpireTime = expireTime
|
||||
}
|
||||
|
||||
if conf.GetConfigBool("useGroupPathInToken") {
|
||||
groupPath, err := user.GetUserFullGroupPath()
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
user.Groups = groupPath
|
||||
}
|
||||
user = refineUser(user)
|
||||
|
||||
_, originBackend := getOriginFromHost(host)
|
||||
|
@@ -1331,6 +1331,56 @@ func (user *User) CheckUserFace(faceIdImage []string, provider *Provider) (bool,
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (user *User) GetUserFullGroupPath() ([]string, error) {
|
||||
if len(user.Groups) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var orgGroups []*Group
|
||||
orgGroups, err := GetGroups(user.Owner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupMap := make(map[string]Group)
|
||||
for _, group := range orgGroups {
|
||||
groupMap[group.Name] = *group
|
||||
}
|
||||
|
||||
var groupFullPath []string
|
||||
|
||||
for _, groupId := range user.Groups {
|
||||
_, groupName := util.GetOwnerAndNameFromIdNoCheck(groupId)
|
||||
group, ok := groupMap[groupName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
groupPath := groupName
|
||||
|
||||
curGroup, ok := groupMap[group.ParentId]
|
||||
if !ok {
|
||||
return []string{}, fmt.Errorf("group:Group %s not exist", group.ParentId)
|
||||
}
|
||||
for {
|
||||
groupPath = util.GetId(curGroup.Name, groupPath)
|
||||
if curGroup.IsTopGroup {
|
||||
break
|
||||
}
|
||||
|
||||
curGroup, ok = groupMap[curGroup.ParentId]
|
||||
if !ok {
|
||||
return []string{}, fmt.Errorf("group:Group %s not exist", curGroup.ParentId)
|
||||
}
|
||||
}
|
||||
|
||||
groupPath = util.GetId(curGroup.Owner, groupPath)
|
||||
groupFullPath = append(groupFullPath, groupPath)
|
||||
}
|
||||
|
||||
return groupFullPath, nil
|
||||
}
|
||||
|
||||
func GenerateIdForNewUser(application *Application) (string, error) {
|
||||
if application == nil || application.GetSignupItemRule("ID") != "Incremental" {
|
||||
return util.GenerateId(), nil
|
||||
|
@@ -88,7 +88,10 @@ class ProviderTable extends React.Component {
|
||||
}
|
||||
}} >
|
||||
{
|
||||
Setting.getDeduplicatedArray(this.props.providers, table, "name").map((provider, index) => <Option key={index} value={provider.name}>{provider.name}</Option>)
|
||||
Setting.getDeduplicatedArray(this.props.providers, table, "name").filter(provider => provider.category !== "Captcha" || !table.some(tableItem => {
|
||||
const existingProvider = Setting.getArrayItem(this.props.providers, "name", tableItem.name);
|
||||
return existingProvider && existingProvider.category === "Captcha";
|
||||
})).map((provider, index) => <Option key={index} value={provider.name}>{provider.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
);
|
||||
|
Reference in New Issue
Block a user