mirror of
https://github.com/minio/minio.git
synced 2025-04-20 02:27:50 -04:00
Add groups to policy entities (#20052)
* Add groups to policy entities * update comment --------- Co-authored-by: Harshavardhana <harsha@minio.io>
This commit is contained in:
parent
5f64658faa
commit
6c6f0987dc
@ -2088,50 +2088,64 @@ func (store *IAMStoreSys) GetAllSTSUserMappings(userPredicate func(string) bool)
|
|||||||
return stsMap, nil
|
return stsMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes store is locked by caller. If users is empty, returns all user mappings.
|
// Assumes store is locked by caller. If userMap is empty, returns all user mappings.
|
||||||
func (store *IAMStoreSys) listUserPolicyMappings(cache *iamCache, users []string,
|
func (store *IAMStoreSys) listUserPolicyMappings(cache *iamCache, userMap map[string]set.StringSet,
|
||||||
userPredicate func(string) bool,
|
userPredicate func(string) bool,
|
||||||
) []madmin.UserPolicyEntities {
|
) []madmin.UserPolicyEntities {
|
||||||
|
stsMap := xsync.NewMapOf[string, MappedPolicy]()
|
||||||
|
resMap := make(map[string]madmin.UserPolicyEntities, len(userMap))
|
||||||
|
|
||||||
|
for user, groupSet := range userMap {
|
||||||
|
// Attempt to load parent user mapping for STS accounts
|
||||||
|
store.loadMappedPolicy(context.TODO(), user, stsUser, false, stsMap)
|
||||||
|
blankEntities := madmin.UserPolicyEntities{User: user}
|
||||||
|
if !groupSet.IsEmpty() {
|
||||||
|
blankEntities.MemberOfMappings = store.listGroupPolicyMappings(cache, groupSet, nil)
|
||||||
|
}
|
||||||
|
resMap[user] = blankEntities
|
||||||
|
}
|
||||||
|
|
||||||
var r []madmin.UserPolicyEntities
|
var r []madmin.UserPolicyEntities
|
||||||
usersSet := set.CreateStringSet(users...)
|
|
||||||
cache.iamUserPolicyMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
|
cache.iamUserPolicyMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
|
||||||
if userPredicate != nil && !userPredicate(user) {
|
if userPredicate != nil && !userPredicate(user) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !usersSet.IsEmpty() && !usersSet.Contains(user) {
|
entitiesWithMemberOf, ok := resMap[user]
|
||||||
|
if !ok {
|
||||||
|
if len(userMap) > 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
entitiesWithMemberOf = madmin.UserPolicyEntities{User: user}
|
||||||
|
}
|
||||||
|
|
||||||
ps := mappedPolicy.toSlice()
|
ps := mappedPolicy.toSlice()
|
||||||
sort.Strings(ps)
|
sort.Strings(ps)
|
||||||
r = append(r, madmin.UserPolicyEntities{
|
entitiesWithMemberOf.Policies = ps
|
||||||
User: user,
|
resMap[user] = entitiesWithMemberOf
|
||||||
Policies: ps,
|
|
||||||
})
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
stsMap := xsync.NewMapOf[string, MappedPolicy]()
|
|
||||||
for _, user := range users {
|
|
||||||
// Attempt to load parent user mapping for STS accounts
|
|
||||||
store.loadMappedPolicy(context.TODO(), user, stsUser, false, stsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
stsMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
|
stsMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
|
||||||
if userPredicate != nil && !userPredicate(user) {
|
if userPredicate != nil && !userPredicate(user) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entitiesWithMemberOf := resMap[user]
|
||||||
|
|
||||||
ps := mappedPolicy.toSlice()
|
ps := mappedPolicy.toSlice()
|
||||||
sort.Strings(ps)
|
sort.Strings(ps)
|
||||||
r = append(r, madmin.UserPolicyEntities{
|
entitiesWithMemberOf.Policies = ps
|
||||||
User: user,
|
resMap[user] = entitiesWithMemberOf
|
||||||
Policies: ps,
|
|
||||||
})
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for _, v := range resMap {
|
||||||
|
if v.Policies != nil || v.MemberOfMappings != nil {
|
||||||
|
r = append(r, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sort.Slice(r, func(i, j int) bool {
|
sort.Slice(r, func(i, j int) bool {
|
||||||
return r[i].User < r[j].User
|
return r[i].User < r[j].User
|
||||||
})
|
})
|
||||||
@ -2140,11 +2154,11 @@ func (store *IAMStoreSys) listUserPolicyMappings(cache *iamCache, users []string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assumes store is locked by caller. If groups is empty, returns all group mappings.
|
// Assumes store is locked by caller. If groups is empty, returns all group mappings.
|
||||||
func (store *IAMStoreSys) listGroupPolicyMappings(cache *iamCache, groups []string,
|
func (store *IAMStoreSys) listGroupPolicyMappings(cache *iamCache, groupsSet set.StringSet,
|
||||||
groupPredicate func(string) bool,
|
groupPredicate func(string) bool,
|
||||||
) []madmin.GroupPolicyEntities {
|
) []madmin.GroupPolicyEntities {
|
||||||
var r []madmin.GroupPolicyEntities
|
var r []madmin.GroupPolicyEntities
|
||||||
groupsSet := set.CreateStringSet(groups...)
|
|
||||||
cache.iamGroupPolicyMap.Range(func(group string, mappedPolicy MappedPolicy) bool {
|
cache.iamGroupPolicyMap.Range(func(group string, mappedPolicy MappedPolicy) bool {
|
||||||
if groupPredicate != nil && !groupPredicate(group) {
|
if groupPredicate != nil && !groupPredicate(group) {
|
||||||
return true
|
return true
|
||||||
@ -2171,11 +2185,9 @@ func (store *IAMStoreSys) listGroupPolicyMappings(cache *iamCache, groups []stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assumes store is locked by caller. If policies is empty, returns all policy mappings.
|
// Assumes store is locked by caller. If policies is empty, returns all policy mappings.
|
||||||
func (store *IAMStoreSys) listPolicyMappings(cache *iamCache, policies []string,
|
func (store *IAMStoreSys) listPolicyMappings(cache *iamCache, queryPolSet set.StringSet,
|
||||||
userPredicate, groupPredicate func(string) bool,
|
userPredicate, groupPredicate func(string) bool,
|
||||||
) []madmin.PolicyEntities {
|
) []madmin.PolicyEntities {
|
||||||
queryPolSet := set.CreateStringSet(policies...)
|
|
||||||
|
|
||||||
policyToUsersMap := make(map[string]set.StringSet)
|
policyToUsersMap := make(map[string]set.StringSet)
|
||||||
cache.iamUserPolicyMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
|
cache.iamUserPolicyMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
|
||||||
if userPredicate != nil && !userPredicate(user) {
|
if userPredicate != nil && !userPredicate(user) {
|
||||||
@ -2305,7 +2317,7 @@ func (store *IAMStoreSys) listPolicyMappings(cache *iamCache, policies []string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListPolicyMappings - return users/groups mapped to policies.
|
// ListPolicyMappings - return users/groups mapped to policies.
|
||||||
func (store *IAMStoreSys) ListPolicyMappings(q madmin.PolicyEntitiesQuery,
|
func (store *IAMStoreSys) ListPolicyMappings(q cleanEntitiesQuery,
|
||||||
userPredicate, groupPredicate func(string) bool,
|
userPredicate, groupPredicate func(string) bool,
|
||||||
) madmin.PolicyEntitiesResult {
|
) madmin.PolicyEntitiesResult {
|
||||||
cache := store.rlock()
|
cache := store.rlock()
|
||||||
@ -2313,7 +2325,7 @@ func (store *IAMStoreSys) ListPolicyMappings(q madmin.PolicyEntitiesQuery,
|
|||||||
|
|
||||||
var result madmin.PolicyEntitiesResult
|
var result madmin.PolicyEntitiesResult
|
||||||
|
|
||||||
isAllPoliciesQuery := len(q.Users) == 0 && len(q.Groups) == 0 && len(q.Policy) == 0
|
isAllPoliciesQuery := len(q.Users) == 0 && len(q.Groups) == 0 && len(q.Policies) == 0
|
||||||
|
|
||||||
if len(q.Users) > 0 {
|
if len(q.Users) > 0 {
|
||||||
result.UserMappings = store.listUserPolicyMappings(cache, q.Users, userPredicate)
|
result.UserMappings = store.listUserPolicyMappings(cache, q.Users, userPredicate)
|
||||||
@ -2321,8 +2333,8 @@ func (store *IAMStoreSys) ListPolicyMappings(q madmin.PolicyEntitiesQuery,
|
|||||||
if len(q.Groups) > 0 {
|
if len(q.Groups) > 0 {
|
||||||
result.GroupMappings = store.listGroupPolicyMappings(cache, q.Groups, groupPredicate)
|
result.GroupMappings = store.listGroupPolicyMappings(cache, q.Groups, groupPredicate)
|
||||||
}
|
}
|
||||||
if len(q.Policy) > 0 || isAllPoliciesQuery {
|
if len(q.Policies) > 0 || isAllPoliciesQuery {
|
||||||
result.PolicyMappings = store.listPolicyMappings(cache, q.Policy, userPredicate, groupPredicate)
|
result.PolicyMappings = store.listPolicyMappings(cache, q.Policies, userPredicate, groupPredicate)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
57
cmd/iam.go
57
cmd/iam.go
@ -807,6 +807,57 @@ func (sys *IAMSys) ListLDAPUsers(ctx context.Context) (map[string]madmin.UserInf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cleanEntitiesQuery struct {
|
||||||
|
Users map[string]set.StringSet
|
||||||
|
Groups set.StringSet
|
||||||
|
Policies set.StringSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// createCleanEntitiesQuery - maps users to their groups and normalizes user or group DNs if ldap.
|
||||||
|
func (sys *IAMSys) createCleanEntitiesQuery(q madmin.PolicyEntitiesQuery, ldap bool) cleanEntitiesQuery {
|
||||||
|
cleanQ := cleanEntitiesQuery{
|
||||||
|
Users: make(map[string]set.StringSet),
|
||||||
|
Groups: set.CreateStringSet(q.Groups...),
|
||||||
|
Policies: set.CreateStringSet(q.Policy...),
|
||||||
|
}
|
||||||
|
|
||||||
|
if ldap {
|
||||||
|
// Validate and normalize users, then fetch and normalize their groups
|
||||||
|
// Also include unvalidated users for backward compatibility.
|
||||||
|
for _, user := range q.Users {
|
||||||
|
lookupRes, actualGroups, _ := sys.LDAPConfig.GetValidatedDNWithGroups(user)
|
||||||
|
if lookupRes != nil {
|
||||||
|
groupSet := set.CreateStringSet(actualGroups...)
|
||||||
|
|
||||||
|
// duplicates can be overwritten, fetched groups should be identical.
|
||||||
|
cleanQ.Users[lookupRes.NormDN] = groupSet
|
||||||
|
}
|
||||||
|
// Search for non-normalized DN as well for backward compatibility.
|
||||||
|
if _, ok := cleanQ.Users[user]; !ok {
|
||||||
|
cleanQ.Users[user] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and normalize groups.
|
||||||
|
for _, group := range q.Groups {
|
||||||
|
lookupRes, underDN, _ := sys.LDAPConfig.GetValidatedGroupDN(nil, group)
|
||||||
|
if lookupRes != nil && !underDN {
|
||||||
|
cleanQ.Groups.Add(lookupRes.NormDN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, user := range q.Users {
|
||||||
|
info, err := sys.store.GetUserInfo(user)
|
||||||
|
var groupSet set.StringSet
|
||||||
|
if err == nil {
|
||||||
|
groupSet = set.CreateStringSet(info.MemberOf...)
|
||||||
|
}
|
||||||
|
cleanQ.Users[user] = groupSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cleanQ
|
||||||
|
}
|
||||||
|
|
||||||
// QueryLDAPPolicyEntities - queries policy associations for LDAP users/groups/policies.
|
// QueryLDAPPolicyEntities - queries policy associations for LDAP users/groups/policies.
|
||||||
func (sys *IAMSys) QueryLDAPPolicyEntities(ctx context.Context, q madmin.PolicyEntitiesQuery) (*madmin.PolicyEntitiesResult, error) {
|
func (sys *IAMSys) QueryLDAPPolicyEntities(ctx context.Context, q madmin.PolicyEntitiesQuery) (*madmin.PolicyEntitiesResult, error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
@ -819,7 +870,8 @@ func (sys *IAMSys) QueryLDAPPolicyEntities(ctx context.Context, q madmin.PolicyE
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-sys.configLoaded:
|
case <-sys.configLoaded:
|
||||||
pe := sys.store.ListPolicyMappings(q, sys.LDAPConfig.IsLDAPUserDN, sys.LDAPConfig.IsLDAPGroupDN)
|
cleanQuery := sys.createCleanEntitiesQuery(q, true)
|
||||||
|
pe := sys.store.ListPolicyMappings(cleanQuery, sys.LDAPConfig.IsLDAPUserDN, sys.LDAPConfig.IsLDAPGroupDN)
|
||||||
pe.Timestamp = UTCNow()
|
pe.Timestamp = UTCNow()
|
||||||
return &pe, nil
|
return &pe, nil
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@ -893,6 +945,7 @@ func (sys *IAMSys) QueryPolicyEntities(ctx context.Context, q madmin.PolicyEntit
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-sys.configLoaded:
|
case <-sys.configLoaded:
|
||||||
|
cleanQuery := sys.createCleanEntitiesQuery(q, false)
|
||||||
var userPredicate, groupPredicate func(string) bool
|
var userPredicate, groupPredicate func(string) bool
|
||||||
if sys.LDAPConfig.Enabled() {
|
if sys.LDAPConfig.Enabled() {
|
||||||
userPredicate = func(s string) bool {
|
userPredicate = func(s string) bool {
|
||||||
@ -902,7 +955,7 @@ func (sys *IAMSys) QueryPolicyEntities(ctx context.Context, q madmin.PolicyEntit
|
|||||||
return !sys.LDAPConfig.IsLDAPGroupDN(s)
|
return !sys.LDAPConfig.IsLDAPGroupDN(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pe := sys.store.ListPolicyMappings(q, userPredicate, groupPredicate)
|
pe := sys.store.ListPolicyMappings(cleanQuery, userPredicate, groupPredicate)
|
||||||
pe.Timestamp = UTCNow()
|
pe.Timestamp = UTCNow()
|
||||||
return &pe, nil
|
return &pe, nil
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -733,6 +733,7 @@ func TestIAMWithLDAPServerSuite(t *testing.T) {
|
|||||||
suite.SetUpSuite(c)
|
suite.SetUpSuite(c)
|
||||||
suite.SetUpLDAP(c, ldapServer)
|
suite.SetUpLDAP(c, ldapServer)
|
||||||
suite.TestLDAPSTS(c)
|
suite.TestLDAPSTS(c)
|
||||||
|
suite.TestLDAPPolicyEntitiesLookup(c)
|
||||||
suite.TestLDAPUnicodeVariations(c)
|
suite.TestLDAPUnicodeVariations(c)
|
||||||
suite.TestLDAPSTSServiceAccounts(c)
|
suite.TestLDAPSTSServiceAccounts(c)
|
||||||
suite.TestLDAPSTSServiceAccountsWithUsername(c)
|
suite.TestLDAPSTSServiceAccountsWithUsername(c)
|
||||||
@ -764,6 +765,7 @@ func TestIAMWithLDAPNonNormalizedBaseDNConfigServerSuite(t *testing.T) {
|
|||||||
suite.SetUpSuite(c)
|
suite.SetUpSuite(c)
|
||||||
suite.SetUpLDAPWithNonNormalizedBaseDN(c, ldapServer)
|
suite.SetUpLDAPWithNonNormalizedBaseDN(c, ldapServer)
|
||||||
suite.TestLDAPSTS(c)
|
suite.TestLDAPSTS(c)
|
||||||
|
suite.TestLDAPPolicyEntitiesLookup(c)
|
||||||
suite.TestLDAPUnicodeVariations(c)
|
suite.TestLDAPUnicodeVariations(c)
|
||||||
suite.TestLDAPSTSServiceAccounts(c)
|
suite.TestLDAPSTSServiceAccounts(c)
|
||||||
suite.TestLDAPSTSServiceAccountsWithUsername(c)
|
suite.TestLDAPSTSServiceAccountsWithUsername(c)
|
||||||
@ -2096,6 +2098,86 @@ func (s *TestSuiteIAM) TestLDAPAttributesLookup(c *check) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TestSuiteIAM) TestLDAPPolicyEntitiesLookup(c *check) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
groupDN := "cn=projectb,ou=groups,ou=swengg,dc=min,dc=io"
|
||||||
|
groupPolicy := "readwrite"
|
||||||
|
groupReq := madmin.PolicyAssociationReq{
|
||||||
|
Policies: []string{groupPolicy},
|
||||||
|
Group: groupDN,
|
||||||
|
}
|
||||||
|
_, err := s.adm.AttachPolicyLDAP(ctx, groupReq)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Unable to attach group policy: %v", err)
|
||||||
|
}
|
||||||
|
type caseTemplate struct {
|
||||||
|
inDN string
|
||||||
|
expectedOutDN string
|
||||||
|
expectedGroupDN string
|
||||||
|
expectedGroupPolicy string
|
||||||
|
}
|
||||||
|
cases := []caseTemplate{
|
||||||
|
{
|
||||||
|
inDN: "uid=dillon,ou=people,ou=swengg,dc=min,dc=io",
|
||||||
|
expectedOutDN: "uid=dillon,ou=people,ou=swengg,dc=min,dc=io",
|
||||||
|
expectedGroupDN: groupDN,
|
||||||
|
expectedGroupPolicy: groupPolicy,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
policy := "readonly"
|
||||||
|
for _, testCase := range cases {
|
||||||
|
userReq := madmin.PolicyAssociationReq{
|
||||||
|
Policies: []string{policy},
|
||||||
|
User: testCase.inDN,
|
||||||
|
}
|
||||||
|
_, err := s.adm.AttachPolicyLDAP(ctx, userReq)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Unable to attach policy: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
entities, err := s.adm.GetLDAPPolicyEntities(ctx, madmin.PolicyEntitiesQuery{
|
||||||
|
Users: []string{testCase.inDN},
|
||||||
|
Policy: []string{policy},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Unable to fetch policy entities: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch statement to check all the conditions
|
||||||
|
switch {
|
||||||
|
case len(entities.UserMappings) != 1:
|
||||||
|
c.Fatalf("Expected to find exactly one user mapping")
|
||||||
|
case entities.UserMappings[0].User != testCase.expectedOutDN:
|
||||||
|
c.Fatalf("Expected user DN `%s`, found `%s`", testCase.expectedOutDN, entities.UserMappings[0].User)
|
||||||
|
case len(entities.UserMappings[0].Policies) != 1:
|
||||||
|
c.Fatalf("Expected exactly one policy attached to user")
|
||||||
|
case entities.UserMappings[0].Policies[0] != policy:
|
||||||
|
c.Fatalf("Expected attached policy `%s`, found `%s`", policy, entities.UserMappings[0].Policies[0])
|
||||||
|
case len(entities.UserMappings[0].MemberOfMappings) != 1:
|
||||||
|
c.Fatalf("Expected exactly one group attached to user")
|
||||||
|
case entities.UserMappings[0].MemberOfMappings[0].Group != testCase.expectedGroupDN:
|
||||||
|
c.Fatalf("Expected attached group `%s`, found `%s`", testCase.expectedGroupDN, entities.UserMappings[0].MemberOfMappings[0].Group)
|
||||||
|
case len(entities.UserMappings[0].MemberOfMappings[0].Policies) != 1:
|
||||||
|
c.Fatalf("Expected exactly one policy attached to group")
|
||||||
|
case entities.UserMappings[0].MemberOfMappings[0].Policies[0] != testCase.expectedGroupPolicy:
|
||||||
|
c.Fatalf("Expected attached policy `%s`, found `%s`", testCase.expectedGroupPolicy, entities.UserMappings[0].MemberOfMappings[0].Policies[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.adm.DetachPolicyLDAP(ctx, userReq)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Unable to detach policy: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.adm.DetachPolicyLDAP(ctx, groupReq)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Unable to detach group policy: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TestSuiteIAM) TestOpenIDSTS(c *check) {
|
func (s *TestSuiteIAM) TestOpenIDSTS(c *check) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -179,6 +179,54 @@ func (l *Config) GetValidatedDNUnderBaseDN(conn *ldap.Conn, dn string, baseDNLis
|
|||||||
return searchRes, false, nil
|
return searchRes, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetValidatedDNWithGroups - Gets validated DN from given DN or short username
|
||||||
|
// and returns the DN and the groups the user is a member of.
|
||||||
|
//
|
||||||
|
// If username is required in group search but a DN is passed, no groups are
|
||||||
|
// returned.
|
||||||
|
func (l *Config) GetValidatedDNWithGroups(username string) (*xldap.DNSearchResult, []string, error) {
|
||||||
|
conn, err := l.LDAP.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// Bind to the lookup user account
|
||||||
|
if err = l.LDAP.LookupBind(conn); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var lookupRes *xldap.DNSearchResult
|
||||||
|
shortUsername := ""
|
||||||
|
// Check if the passed in username is a valid DN.
|
||||||
|
if !l.ParsesAsDN(username) {
|
||||||
|
// We consider it as a login username and attempt to check it exists in
|
||||||
|
// the directory.
|
||||||
|
lookupRes, err = l.LDAP.LookupUsername(conn, username)
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "User DN not found for") {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
return nil, nil, fmt.Errorf("Unable to find user DN: %w", err)
|
||||||
|
}
|
||||||
|
shortUsername = username
|
||||||
|
} else {
|
||||||
|
// Since the username parses as a valid DN, check that it exists and is
|
||||||
|
// under a configured base DN in the LDAP directory.
|
||||||
|
var isUnderBaseDN bool
|
||||||
|
lookupRes, isUnderBaseDN, err = l.GetValidatedUserDN(conn, username)
|
||||||
|
if err == nil && !isUnderBaseDN {
|
||||||
|
return nil, nil, fmt.Errorf("Unable to find user DN: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
groups, err := l.LDAP.SearchForUserGroups(conn, shortUsername, lookupRes.ActualDN)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return lookupRes, groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Bind - binds to ldap, searches LDAP and returns the distinguished name of the
|
// Bind - binds to ldap, searches LDAP and returns the distinguished name of the
|
||||||
// user and the list of groups.
|
// user and the list of groups.
|
||||||
func (l *Config) Bind(username, password string) (*xldap.DNSearchResult, []string, error) {
|
func (l *Config) Bind(username, password string) (*xldap.DNSearchResult, []string, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user