diff --git a/ldap/server.go b/ldap/server.go index 3c88e54d..e3f1d12b 100644 --- a/ldap/server.go +++ b/ldap/server.go @@ -19,6 +19,7 @@ import ( "fmt" "hash/fnv" "log" + "strings" "github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/object" @@ -158,6 +159,38 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) { default: } + 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") { + isGroupSearch = true + } + + if isGroupSearch { + groups, code := GetFilteredGroups(m, string(r.BaseObject()), r.FilterString()) + if code != ldap.LDAPResultSuccess { + res.SetResultCode(code) + w.Write(res) + return + } + + for _, group := range groups { + dn := fmt.Sprintf("cn=%s,%s", group.Name, string(r.BaseObject())) + e := ldap.NewSearchResultEntry(dn) + e.AddAttribute("cn", message.AttributeValue(group.Name)) + gidNumberStr := fmt.Sprintf("%v", hash(group.Name)) + e.AddAttribute("gidNumber", message.AttributeValue(gidNumberStr)) + users := object.GetGroupUsersWithoutError(group.GetId()) + for _, user := range users { + e.AddAttribute("memberUid", message.AttributeValue(user.Name)) + } + e.AddAttribute("objectClass", "posixGroup") + w.Write(e) + } + + w.Write(res) + return + } + users, code := GetFilteredUsers(m) if code != ldap.LDAPResultSuccess { res.SetResultCode(code) diff --git a/ldap/util.go b/ldap/util.go index 1bcd0fc7..254acaaf 100644 --- a/ldap/util.go +++ b/ldap/util.go @@ -184,6 +184,10 @@ func buildUserFilterCondition(filter interface{}) (builder.Cond, error) { case message.FilterEqualityMatch: attr := string(f.AttributeDesc()) + if strings.EqualFold(attr, "objectclass") && strings.EqualFold(string(f.AssertionValue()), "posixAccount") { + return builder.Expr("1 = 1"), nil + } + if attr == ldapMemberOfAttr { var names []string groupId := string(f.AssertionValue()) @@ -324,6 +328,36 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int) } } +func GetFilteredGroups(m *ldap.Message, baseDN string, filterStr string) ([]*object.Group, int) { + name, org, code := getNameAndOrgFromFilter(baseDN, filterStr) + if code != ldap.LDAPResultSuccess { + return nil, code + } + + var groups []*object.Group + var err error + + if name == "*" { + if m.Client.IsGlobalAdmin && org == "*" { + groups, err = object.GetGlobalGroups() + if err != nil { + panic(err) + } + } else if m.Client.IsGlobalAdmin || org == m.Client.OrgName { + groups, err = object.GetGroups(org) + if err != nil { + panic(err) + } + } else { + return nil, ldap.LDAPResultInsufficientAccessRights + } + } else { + return nil, ldap.LDAPResultNoSuchObject + } + + return groups, ldap.LDAPResultSuccess +} + // get user password with hash type prefix // TODO not handle salt yet // @return {md5}5f4dcc3b5aa765d61d8327deb882cf99 diff --git a/object/group.go b/object/group.go index 2a125b80..5db775bd 100644 --- a/object/group.go +++ b/object/group.go @@ -70,6 +70,16 @@ func GetGroups(owner string) ([]*Group, error) { return groups, nil } +func GetGlobalGroups() ([]*Group, error) { + groups := []*Group{} + err := ormer.Engine.Desc("created_time").Find(&groups) + if err != nil { + return nil, err + } + + return groups, nil +} + func GetPaginationGroups(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Group, error) { groups := []*Group{} session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)