mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
[IDP:LDAP] Cleanup creds for removed LDAP user entries (#12759)
This commit is contained in:
parent
e7a4967726
commit
0db1c94e7d
60
cmd/iam.go
60
cmd/iam.go
@ -650,14 +650,22 @@ func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer) {
|
||||
break
|
||||
}
|
||||
|
||||
if globalOpenIDConfig.ProviderEnabled() {
|
||||
// Set up polling for expired accounts and credentials purging.
|
||||
switch {
|
||||
case globalOpenIDConfig.ProviderEnabled():
|
||||
go func() {
|
||||
// Purge expired credentials
|
||||
for {
|
||||
time.Sleep(globalRefreshIAMInterval)
|
||||
sys.purgeExpiredCredentialsForExternalSSO(ctx)
|
||||
}
|
||||
}()
|
||||
case globalLDAPConfig.EnabledWithLookupBind():
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(globalRefreshIAMInterval)
|
||||
sys.purgeExpiredCredentialsForLDAP(ctx)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
go sys.store.watch(ctx, sys)
|
||||
@ -1571,6 +1579,54 @@ func (sys *IAMSys) purgeExpiredCredentialsForExternalSSO(ctx context.Context) {
|
||||
sys.store.unlock()
|
||||
}
|
||||
|
||||
// purgeExpiredCredentialsForLDAP - validates if local credentials are still
|
||||
// valid by checking LDAP server if the relevant users are still present.
|
||||
func (sys *IAMSys) purgeExpiredCredentialsForLDAP(ctx context.Context) {
|
||||
sys.store.lock()
|
||||
parentUsersMap := make(map[string][]auth.Credentials, len(sys.iamUsersMap))
|
||||
parentUsers := make([]string, 0, len(sys.iamUsersMap))
|
||||
for _, cred := range sys.iamUsersMap {
|
||||
if cred.IsServiceAccount() || cred.IsTemp() {
|
||||
if globalLDAPConfig.IsLDAPUserDN(cred.ParentUser) {
|
||||
if _, ok := parentUsersMap[cred.ParentUser]; !ok {
|
||||
parentUsers = append(parentUsers, cred.ParentUser)
|
||||
}
|
||||
parentUsersMap[cred.ParentUser] = append(parentUsersMap[cred.ParentUser], cred)
|
||||
}
|
||||
}
|
||||
}
|
||||
sys.store.unlock()
|
||||
|
||||
expiredUsers, err := globalLDAPConfig.GetNonExistentUserDNS(parentUsers)
|
||||
if err != nil {
|
||||
// Log and return on error - perhaps it'll work the next time.
|
||||
logger.LogIf(GlobalContext, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, expiredUser := range expiredUsers {
|
||||
for _, cred := range parentUsersMap[expiredUser] {
|
||||
userType := regUser
|
||||
if cred.IsServiceAccount() {
|
||||
userType = svcUser
|
||||
} else if cred.IsTemp() {
|
||||
userType = stsUser
|
||||
}
|
||||
sys.store.deleteIAMConfig(ctx, getUserIdentityPath(cred.AccessKey, userType))
|
||||
sys.store.deleteIAMConfig(ctx, getMappedPolicyPath(cred.AccessKey, userType, false))
|
||||
}
|
||||
}
|
||||
|
||||
sys.store.lock()
|
||||
for _, user := range expiredUsers {
|
||||
for _, cred := range parentUsersMap[user] {
|
||||
delete(sys.iamUsersMap, cred.AccessKey)
|
||||
delete(sys.iamUserPolicyMap, cred.AccessKey)
|
||||
}
|
||||
}
|
||||
sys.store.unlock()
|
||||
}
|
||||
|
||||
// GetUser - get user credentials
|
||||
func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) {
|
||||
if !sys.Initialized() {
|
||||
|
@ -452,6 +452,62 @@ func (l Config) testConnection() error {
|
||||
return fmt.Errorf("LDAP connection test error: %w", err)
|
||||
}
|
||||
|
||||
// IsLDAPUserDN determines if the given string could be a user DN from LDAP.
|
||||
func (l Config) IsLDAPUserDN(user string) bool {
|
||||
return strings.HasSuffix(user, ","+l.UserDNSearchBaseDN)
|
||||
}
|
||||
|
||||
// GetNonExistentUserDNS - find user accounts that are no longer present in the
|
||||
// LDAP server.
|
||||
func (l *Config) GetNonExistentUserDNS(userDNS []string) ([]string, error) {
|
||||
if !l.isUsingLookupBind {
|
||||
return nil, errors.New("current LDAP configuration does not permit looking for expired user accounts")
|
||||
}
|
||||
|
||||
conn, err := l.Connect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Bind to the lookup user account
|
||||
if err = l.lookupBind(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonExistentUsers := []string{}
|
||||
for _, dn := range userDNS {
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
dn,
|
||||
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
|
||||
"(objectclass=*)",
|
||||
[]string{}, // only need DN, so no pass no attributes here
|
||||
nil,
|
||||
)
|
||||
|
||||
searchResult, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
// Object does not exist error?
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
nonExistentUsers = append(nonExistentUsers, dn)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if len(searchResult.Entries) == 0 {
|
||||
// DN was not found - this means this user account is
|
||||
// expired.
|
||||
nonExistentUsers = append(nonExistentUsers, dn)
|
||||
}
|
||||
}
|
||||
return nonExistentUsers, nil
|
||||
}
|
||||
|
||||
// EnabledWithLookupBind - checks if ldap IDP is enabled in lookup bind mode.
|
||||
func (l Config) EnabledWithLookupBind() bool {
|
||||
return l.Enabled && l.isUsingLookupBind
|
||||
}
|
||||
|
||||
// Enabled returns if jwks is enabled.
|
||||
func Enabled(kvs config.KVS) bool {
|
||||
return kvs.Get(ServerAddr) != ""
|
||||
|
Loading…
Reference in New Issue
Block a user