diff --git a/cmd/iam-etcd-store.go b/cmd/iam-etcd-store.go index f9e37c2f2..22e7f6ca6 100644 --- a/cmd/iam-etcd-store.go +++ b/cmd/iam-etcd-store.go @@ -143,6 +143,10 @@ func (ies *IAMEtcdStore) deleteIAMConfig(ctx context.Context, path string) error return deleteKeyEtcd(ctx, ies.client, path) } +func (ies *IAMEtcdStore) loadPolicyDocWithRetry(ctx context.Context, policy string, m map[string]PolicyDoc, _ int) error { + return ies.loadPolicyDoc(ctx, policy, m) +} + func (ies *IAMEtcdStore) loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error { data, err := ies.loadIAMConfigBytes(ctx, getPolicyDocPath(policy)) if err != nil { @@ -321,6 +325,10 @@ func (ies *IAMEtcdStore) loadGroups(ctx context.Context, m map[string]GroupInfo) return nil } +func (ies *IAMEtcdStore) loadMappedPolicyWithRetry(ctx context.Context, name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy, _ int) error { + return ies.loadMappedPolicy(ctx, name, userType, isGroup, m) +} + func (ies *IAMEtcdStore) loadMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error { var p MappedPolicy err := ies.loadIAMConfig(ctx, &p, getMappedPolicyPath(name, userType, isGroup)) diff --git a/cmd/iam-object-store.go b/cmd/iam-object-store.go index b2c6b2ca2..4c44a0115 100644 --- a/cmd/iam-object-store.go +++ b/cmd/iam-object-store.go @@ -25,6 +25,7 @@ import ( "path" "strings" "sync" + "time" "unicode/utf8" jsoniter "github.com/json-iterator/go" @@ -146,6 +147,41 @@ func (iamOS *IAMObjectStore) deleteIAMConfig(ctx context.Context, path string) e return deleteConfig(ctx, iamOS.objAPI, path) } +func (iamOS *IAMObjectStore) loadPolicyDocWithRetry(ctx context.Context, policy string, m map[string]PolicyDoc, retries int) error { + for { + retry: + data, objInfo, err := iamOS.loadIAMConfigBytesWithMetadata(ctx, getPolicyDocPath(policy)) + if err != nil { + if err == errConfigNotFound { + return errNoSuchPolicy + } + retries-- + if retries <= 0 { + return err + } + time.Sleep(500 * time.Millisecond) + goto retry + } + + var p PolicyDoc + err = p.parseJSON(data) + if err != nil { + return err + } + + if p.Version == 0 { + // This means that policy was in the old version (without any + // timestamp info). We fetch the mod time of the file and save + // that as create and update date. + p.CreateDate = objInfo.ModTime + p.UpdateDate = objInfo.ModTime + } + + m[policy] = p + return nil + } +} + func (iamOS *IAMObjectStore) loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error { data, objInfo, err := iamOS.loadIAMConfigBytesWithMetadata(ctx, getPolicyDocPath(policy)) if err != nil { @@ -289,6 +325,30 @@ func (iamOS *IAMObjectStore) loadGroups(ctx context.Context, m map[string]GroupI return nil } +func (iamOS *IAMObjectStore) loadMappedPolicyWithRetry(ctx context.Context, name string, userType IAMUserType, isGroup bool, + m map[string]MappedPolicy, retries int, +) error { + for { + retry: + var p MappedPolicy + err := iamOS.loadIAMConfig(ctx, &p, getMappedPolicyPath(name, userType, isGroup)) + if err != nil { + if err == errConfigNotFound { + return errNoSuchPolicy + } + retries-- + if retries <= 0 { + return err + } + time.Sleep(500 * time.Millisecond) + goto retry + } + + m[name] = p + return nil + } +} + func (iamOS *IAMObjectStore) loadMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy, ) error { @@ -300,6 +360,7 @@ func (iamOS *IAMObjectStore) loadMappedPolicy(ctx context.Context, name string, } return err } + m[name] = p return nil } diff --git a/cmd/iam-store.go b/cmd/iam-store.go index d2b766ec6..565425231 100644 --- a/cmd/iam-store.go +++ b/cmd/iam-store.go @@ -441,12 +441,14 @@ type IAMStorageAPI interface { runlock() getUsersSysType() UsersSysType loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error + loadPolicyDocWithRetry(ctx context.Context, policy string, m map[string]PolicyDoc, retries int) error loadPolicyDocs(ctx context.Context, m map[string]PolicyDoc) error loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]UserIdentity) error loadUsers(ctx context.Context, userType IAMUserType, m map[string]UserIdentity) error loadGroup(ctx context.Context, group string, m map[string]GroupInfo) error loadGroups(ctx context.Context, m map[string]GroupInfo) error loadMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error + loadMappedPolicyWithRetry(ctx context.Context, name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy, retries int) error loadMappedPolicies(ctx context.Context, userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error saveIAMConfig(ctx context.Context, item interface{}, path string, opts ...options) error loadIAMConfig(ctx context.Context, item interface{}, path string) error @@ -2482,22 +2484,24 @@ func (store *IAMStoreSys) LoadUser(ctx context.Context, accessKey string) { store.loadUser(ctx, accessKey, regUser, cache.iamUsersMap) if _, found = cache.iamUsersMap[accessKey]; found { // load mapped policies - store.loadMappedPolicy(ctx, accessKey, regUser, false, cache.iamUserPolicyMap) + store.loadMappedPolicyWithRetry(ctx, accessKey, regUser, false, cache.iamUserPolicyMap, 3) } } // Check for service account if !found { store.loadUser(ctx, accessKey, svcUser, cache.iamUsersMap) - if svc, found := cache.iamUsersMap[accessKey]; found { + var svc UserIdentity + svc, found = cache.iamUsersMap[accessKey] + if found { // Load parent user and mapped policies. if store.getUsersSysType() == MinIOUsersSysType { store.loadUser(ctx, svc.Credentials.ParentUser, regUser, cache.iamUsersMap) - store.loadMappedPolicy(ctx, svc.Credentials.ParentUser, regUser, false, cache.iamUserPolicyMap) + store.loadMappedPolicyWithRetry(ctx, svc.Credentials.ParentUser, regUser, false, cache.iamUserPolicyMap, 3) } else { // In case of LDAP the parent user's policy mapping needs to be // loaded into sts map - store.loadMappedPolicy(ctx, svc.Credentials.ParentUser, stsUser, false, cache.iamSTSPolicyMap) + store.loadMappedPolicyWithRetry(ctx, svc.Credentials.ParentUser, stsUser, false, cache.iamSTSPolicyMap, 3) } } } @@ -2509,7 +2513,7 @@ func (store *IAMStoreSys) LoadUser(ctx context.Context, accessKey string) { store.loadUser(ctx, accessKey, stsUser, cache.iamSTSAccountsMap) if stsUserCred, found = cache.iamSTSAccountsMap[accessKey]; found { // Load mapped policy - store.loadMappedPolicy(ctx, stsUserCred.Credentials.ParentUser, stsUser, false, cache.iamSTSPolicyMap) + store.loadMappedPolicyWithRetry(ctx, stsUserCred.Credentials.ParentUser, stsUser, false, cache.iamSTSPolicyMap, 3) stsAccountFound = true } } @@ -2518,13 +2522,13 @@ func (store *IAMStoreSys) LoadUser(ctx context.Context, accessKey string) { if !stsAccountFound { for _, policy := range cache.iamUserPolicyMap[accessKey].toSlice() { if _, found = cache.iamPolicyDocsMap[policy]; !found { - store.loadPolicyDoc(ctx, policy, cache.iamPolicyDocsMap) + store.loadPolicyDocWithRetry(ctx, policy, cache.iamPolicyDocsMap, 3) } } } else { for _, policy := range cache.iamSTSPolicyMap[stsUserCred.Credentials.AccessKey].toSlice() { if _, found = cache.iamPolicyDocsMap[policy]; !found { - store.loadPolicyDoc(ctx, policy, cache.iamPolicyDocsMap) + store.loadPolicyDocWithRetry(ctx, policy, cache.iamPolicyDocsMap, 3) } } }