mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
site healing: Skip stale iam asset updates from peer. (#15203)
Allow healing to apply IAM change only when peer gave the most recent update.
This commit is contained in:
parent
63ac260bd5
commit
0ea5c9d8e8
@ -160,7 +160,7 @@ func (a adminAPIHandlers) SRPeerReplicateIAMItem(w http.ResponseWriter, r *http.
|
|||||||
err = errSRInvalidRequest(errInvalidArgument)
|
err = errSRInvalidRequest(errInvalidArgument)
|
||||||
case madmin.SRIAMItemPolicy:
|
case madmin.SRIAMItemPolicy:
|
||||||
if item.Policy == nil {
|
if item.Policy == nil {
|
||||||
err = globalSiteReplicationSys.PeerAddPolicyHandler(ctx, item.Name, nil)
|
err = globalSiteReplicationSys.PeerAddPolicyHandler(ctx, item.Name, nil, item.UpdatedAt)
|
||||||
} else {
|
} else {
|
||||||
policy, perr := iampolicy.ParseConfig(bytes.NewReader(item.Policy))
|
policy, perr := iampolicy.ParseConfig(bytes.NewReader(item.Policy))
|
||||||
if perr != nil {
|
if perr != nil {
|
||||||
@ -168,21 +168,21 @@ func (a adminAPIHandlers) SRPeerReplicateIAMItem(w http.ResponseWriter, r *http.
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if policy.IsEmpty() {
|
if policy.IsEmpty() {
|
||||||
err = globalSiteReplicationSys.PeerAddPolicyHandler(ctx, item.Name, nil)
|
err = globalSiteReplicationSys.PeerAddPolicyHandler(ctx, item.Name, nil, item.UpdatedAt)
|
||||||
} else {
|
} else {
|
||||||
err = globalSiteReplicationSys.PeerAddPolicyHandler(ctx, item.Name, policy)
|
err = globalSiteReplicationSys.PeerAddPolicyHandler(ctx, item.Name, policy, item.UpdatedAt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case madmin.SRIAMItemSvcAcc:
|
case madmin.SRIAMItemSvcAcc:
|
||||||
err = globalSiteReplicationSys.PeerSvcAccChangeHandler(ctx, item.SvcAccChange)
|
err = globalSiteReplicationSys.PeerSvcAccChangeHandler(ctx, item.SvcAccChange, item.UpdatedAt)
|
||||||
case madmin.SRIAMItemPolicyMapping:
|
case madmin.SRIAMItemPolicyMapping:
|
||||||
err = globalSiteReplicationSys.PeerPolicyMappingHandler(ctx, item.PolicyMapping)
|
err = globalSiteReplicationSys.PeerPolicyMappingHandler(ctx, item.PolicyMapping, item.UpdatedAt)
|
||||||
case madmin.SRIAMItemSTSAcc:
|
case madmin.SRIAMItemSTSAcc:
|
||||||
err = globalSiteReplicationSys.PeerSTSAccHandler(ctx, item.STSCredential)
|
err = globalSiteReplicationSys.PeerSTSAccHandler(ctx, item.STSCredential, item.UpdatedAt)
|
||||||
case madmin.SRIAMItemIAMUser:
|
case madmin.SRIAMItemIAMUser:
|
||||||
err = globalSiteReplicationSys.PeerIAMUserChangeHandler(ctx, item.IAMUser)
|
err = globalSiteReplicationSys.PeerIAMUserChangeHandler(ctx, item.IAMUser, item.UpdatedAt)
|
||||||
case madmin.SRIAMItemGroupInfo:
|
case madmin.SRIAMItemGroupInfo:
|
||||||
err = globalSiteReplicationSys.PeerGroupInfoChangeHandler(ctx, item.GroupInfo)
|
err = globalSiteReplicationSys.PeerGroupInfoChangeHandler(ctx, item.GroupInfo, item.UpdatedAt)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
|
@ -72,6 +72,7 @@ func (a adminAPIHandlers) RemoveUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
AccessKey: accessKey,
|
AccessKey: accessKey,
|
||||||
IsDeleteReq: true,
|
IsDeleteReq: true,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: UTCNow(),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -240,9 +241,9 @@ func (a adminAPIHandlers) UpdateGroupMembers(w http.ResponseWriter, r *http.Requ
|
|||||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
|
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var updatedAt time.Time
|
||||||
if updReq.IsRemove {
|
if updReq.IsRemove {
|
||||||
err = globalIAMSys.RemoveUsersFromGroup(ctx, updReq.Group, updReq.Members)
|
updatedAt, err = globalIAMSys.RemoveUsersFromGroup(ctx, updReq.Group, updReq.Members)
|
||||||
} else {
|
} else {
|
||||||
// Check if group already exists
|
// Check if group already exists
|
||||||
if _, gerr := globalIAMSys.GetGroupDescription(updReq.Group); gerr != nil {
|
if _, gerr := globalIAMSys.GetGroupDescription(updReq.Group); gerr != nil {
|
||||||
@ -253,7 +254,7 @@ func (a adminAPIHandlers) UpdateGroupMembers(w http.ResponseWriter, r *http.Requ
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = globalIAMSys.AddUsersToGroup(ctx, updReq.Group, updReq.Members)
|
updatedAt, err = globalIAMSys.AddUsersToGroup(ctx, updReq.Group, updReq.Members)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
@ -265,6 +266,7 @@ func (a adminAPIHandlers) UpdateGroupMembers(w http.ResponseWriter, r *http.Requ
|
|||||||
GroupInfo: &madmin.SRGroupInfo{
|
GroupInfo: &madmin.SRGroupInfo{
|
||||||
UpdateReq: updReq,
|
UpdateReq: updReq,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -341,12 +343,15 @@ func (a adminAPIHandlers) SetGroupStatus(w http.ResponseWriter, r *http.Request)
|
|||||||
group := vars["group"]
|
group := vars["group"]
|
||||||
status := vars["status"]
|
status := vars["status"]
|
||||||
|
|
||||||
var err error
|
var (
|
||||||
|
err error
|
||||||
|
updatedAt time.Time
|
||||||
|
)
|
||||||
switch status {
|
switch status {
|
||||||
case statusEnabled:
|
case statusEnabled:
|
||||||
err = globalIAMSys.SetGroupStatus(ctx, group, true)
|
updatedAt, err = globalIAMSys.SetGroupStatus(ctx, group, true)
|
||||||
case statusDisabled:
|
case statusDisabled:
|
||||||
err = globalIAMSys.SetGroupStatus(ctx, group, false)
|
updatedAt, err = globalIAMSys.SetGroupStatus(ctx, group, false)
|
||||||
default:
|
default:
|
||||||
err = errInvalidArgument
|
err = errInvalidArgument
|
||||||
}
|
}
|
||||||
@ -364,6 +369,7 @@ func (a adminAPIHandlers) SetGroupStatus(w http.ResponseWriter, r *http.Request)
|
|||||||
IsRemove: false,
|
IsRemove: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -391,7 +397,8 @@ func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := globalIAMSys.SetUserStatus(ctx, accessKey, madmin.AccountStatus(status)); err != nil {
|
updatedAt, err := globalIAMSys.SetUserStatus(ctx, accessKey, madmin.AccountStatus(status))
|
||||||
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -405,6 +412,7 @@ func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request)
|
|||||||
Status: madmin.AccountStatus(status),
|
Status: madmin.AccountStatus(status),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -439,8 +447,8 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userCred, exists := globalIAMSys.GetUser(ctx, accessKey)
|
user, exists := globalIAMSys.GetUser(ctx, accessKey)
|
||||||
if exists && (userCred.IsTemp() || userCred.IsServiceAccount()) {
|
if exists && (user.Credentials.IsTemp() || user.Credentials.IsServiceAccount()) {
|
||||||
// Updating STS credential is not allowed, and this API does not
|
// Updating STS credential is not allowed, and this API does not
|
||||||
// support updating service accounts.
|
// support updating service accounts.
|
||||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL)
|
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL)
|
||||||
@ -501,7 +509,8 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = globalIAMSys.CreateUser(ctx, accessKey, ureq); err != nil {
|
updatedAt, err := globalIAMSys.CreateUser(ctx, accessKey, ureq)
|
||||||
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -513,6 +522,7 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
IsDeleteReq: false,
|
IsDeleteReq: false,
|
||||||
UserReq: &ureq,
|
UserReq: &ureq,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -674,7 +684,7 @@ func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts.sessionPolicy = sp
|
opts.sessionPolicy = sp
|
||||||
newCred, err := globalIAMSys.NewServiceAccount(ctx, targetUser, targetGroups, opts)
|
newCred, updatedAt, err := globalIAMSys.NewServiceAccount(ctx, targetUser, targetGroups, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -717,6 +727,7 @@ func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Reque
|
|||||||
Status: auth.AccountOn,
|
Status: auth.AccountOn,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
@ -800,7 +811,7 @@ func (a adminAPIHandlers) UpdateServiceAccount(w http.ResponseWriter, r *http.Re
|
|||||||
status: updateReq.NewStatus,
|
status: updateReq.NewStatus,
|
||||||
sessionPolicy: sp,
|
sessionPolicy: sp,
|
||||||
}
|
}
|
||||||
err = globalIAMSys.UpdateServiceAccount(ctx, accessKey, opts)
|
updatedAt, err := globalIAMSys.UpdateServiceAccount(ctx, accessKey, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -818,6 +829,7 @@ func (a adminAPIHandlers) UpdateServiceAccount(w http.ResponseWriter, r *http.Re
|
|||||||
SessionPolicy: updateReq.NewPolicy,
|
SessionPolicy: updateReq.NewPolicy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
@ -1057,6 +1069,7 @@ func (a adminAPIHandlers) DeleteServiceAccount(w http.ResponseWriter, r *http.Re
|
|||||||
AccessKey: serviceAccount,
|
AccessKey: serviceAccount,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: UTCNow(),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -1397,6 +1410,7 @@ func (a adminAPIHandlers) RemoveCannedPolicy(w http.ResponseWriter, r *http.Requ
|
|||||||
if err := globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{
|
if err := globalSiteReplicationSys.IAMChangeHook(ctx, madmin.SRIAMItem{
|
||||||
Type: madmin.SRIAMItemPolicy,
|
Type: madmin.SRIAMItemPolicy,
|
||||||
Name: policyName,
|
Name: policyName,
|
||||||
|
UpdatedAt: UTCNow(),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -1453,7 +1467,8 @@ func (a adminAPIHandlers) AddCannedPolicy(w http.ResponseWriter, r *http.Request
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = globalIAMSys.SetPolicy(ctx, policyName, *iamPolicy); err != nil {
|
updatedAt, err := globalIAMSys.SetPolicy(ctx, policyName, *iamPolicy)
|
||||||
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1464,6 +1479,7 @@ func (a adminAPIHandlers) AddCannedPolicy(w http.ResponseWriter, r *http.Request
|
|||||||
Type: madmin.SRIAMItemPolicy,
|
Type: madmin.SRIAMItemPolicy,
|
||||||
Name: policyName,
|
Name: policyName,
|
||||||
Policy: iamPolicyBytes,
|
Policy: iamPolicyBytes,
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -1498,7 +1514,8 @@ func (a adminAPIHandlers) SetPolicyForUserOrGroup(w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := globalIAMSys.PolicyDBSet(ctx, entityName, policyName, isGroup); err != nil {
|
updatedAt, err := globalIAMSys.PolicyDBSet(ctx, entityName, policyName, isGroup)
|
||||||
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1510,6 +1527,7 @@ func (a adminAPIHandlers) SetPolicyForUserOrGroup(w http.ResponseWriter, r *http
|
|||||||
IsGroup: isGroup,
|
IsGroup: isGroup,
|
||||||
Policy: policyName,
|
Policy: policyName,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
@ -1597,22 +1615,22 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case allUsersFile:
|
case allUsersFile:
|
||||||
userCreds := make(map[string]auth.Credentials)
|
userIdentities := make(map[string]UserIdentity)
|
||||||
globalIAMSys.store.rlock()
|
globalIAMSys.store.rlock()
|
||||||
err := globalIAMSys.store.loadUsers(ctx, regUser, userCreds)
|
err := globalIAMSys.store.loadUsers(ctx, regUser, userIdentities)
|
||||||
globalIAMSys.store.runlock()
|
globalIAMSys.store.runlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userAccounts := make(map[string]madmin.AddOrUpdateUserReq)
|
userAccounts := make(map[string]madmin.AddOrUpdateUserReq)
|
||||||
for u, cred := range userCreds {
|
for u, uid := range userIdentities {
|
||||||
status := madmin.AccountDisabled
|
status := madmin.AccountDisabled
|
||||||
if cred.IsValid() {
|
if uid.Credentials.IsValid() {
|
||||||
status = madmin.AccountEnabled
|
status = madmin.AccountEnabled
|
||||||
}
|
}
|
||||||
userAccounts[u] = madmin.AddOrUpdateUserReq{
|
userAccounts[u] = madmin.AddOrUpdateUserReq{
|
||||||
SecretKey: cred.SecretKey,
|
SecretKey: uid.Credentials.SecretKey,
|
||||||
Status: status,
|
Status: status,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1646,7 +1664,7 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case allSvcAcctsFile:
|
case allSvcAcctsFile:
|
||||||
serviceAccounts := make(map[string]auth.Credentials)
|
serviceAccounts := make(map[string]UserIdentity)
|
||||||
globalIAMSys.store.rlock()
|
globalIAMSys.store.rlock()
|
||||||
err := globalIAMSys.store.loadUsers(ctx, svcUser, serviceAccounts)
|
err := globalIAMSys.store.loadUsers(ctx, svcUser, serviceAccounts)
|
||||||
globalIAMSys.store.runlock()
|
globalIAMSys.store.runlock()
|
||||||
@ -1661,12 +1679,12 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
// site replication is enabled.
|
// site replication is enabled.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
claims, err := globalIAMSys.GetClaimsForSvcAcc(ctx, acc.AccessKey)
|
claims, err := globalIAMSys.GetClaimsForSvcAcc(ctx, acc.Credentials.AccessKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, policy, err := globalIAMSys.GetServiceAccount(ctx, acc.AccessKey)
|
_, policy, err := globalIAMSys.GetServiceAccount(ctx, acc.Credentials.AccessKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
||||||
return
|
return
|
||||||
@ -1681,13 +1699,13 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
svcAccts[user] = madmin.SRSvcAccCreate{
|
svcAccts[user] = madmin.SRSvcAccCreate{
|
||||||
Parent: acc.ParentUser,
|
Parent: acc.Credentials.ParentUser,
|
||||||
AccessKey: user,
|
AccessKey: user,
|
||||||
SecretKey: acc.SecretKey,
|
SecretKey: acc.Credentials.SecretKey,
|
||||||
Groups: acc.Groups,
|
Groups: acc.Credentials.Groups,
|
||||||
Claims: claims,
|
Claims: claims,
|
||||||
SessionPolicy: json.RawMessage(policyJSON),
|
SessionPolicy: json.RawMessage(policyJSON),
|
||||||
Status: acc.Status,
|
Status: acc.Credentials.Status,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1832,7 +1850,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
if policy.IsEmpty() {
|
if policy.IsEmpty() {
|
||||||
err = globalIAMSys.DeletePolicy(ctx, policyName, true)
|
err = globalIAMSys.DeletePolicy(ctx, policyName, true)
|
||||||
} else {
|
} else {
|
||||||
err = globalIAMSys.SetPolicy(ctx, policyName, policy)
|
_, err = globalIAMSys.SetPolicy(ctx, policyName, policy)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, allPoliciesFile, policyName), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, allPoliciesFile, policyName), r.URL)
|
||||||
@ -1870,8 +1888,8 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userCred, exists := globalIAMSys.GetUser(ctx, accessKey)
|
user, exists := globalIAMSys.GetUser(ctx, accessKey)
|
||||||
if exists && (userCred.IsTemp() || userCred.IsServiceAccount()) {
|
if exists && (user.Credentials.IsTemp() || user.Credentials.IsServiceAccount()) {
|
||||||
// Updating STS credential is not allowed, and this API does not
|
// Updating STS credential is not allowed, and this API does not
|
||||||
// support updating service accounts.
|
// support updating service accounts.
|
||||||
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAddUserInvalidArgument, err, allUsersFile, accessKey), r.URL)
|
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAddUserInvalidArgument, err, allUsersFile, accessKey), r.URL)
|
||||||
@ -1910,7 +1928,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAccessDenied, err, allUsersFile, accessKey), r.URL)
|
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAccessDenied, err, allUsersFile, accessKey), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = globalIAMSys.CreateUser(ctx, accessKey, ureq); err != nil {
|
if _, err = globalIAMSys.CreateUser(ctx, accessKey, ureq); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, toAdminAPIErrCode(ctx, err), err, allUsersFile, accessKey), r.URL)
|
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, toAdminAPIErrCode(ctx, err), err, allUsersFile, accessKey), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1949,7 +1967,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if gerr := globalIAMSys.AddUsersToGroup(ctx, group, grpInfo.Members); gerr != nil {
|
if _, gerr := globalIAMSys.AddUsersToGroup(ctx, group, grpInfo.Members); gerr != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, allGroupsFile, group), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, allGroupsFile, group), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2018,7 +2036,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
status: svcAcctReq.Status,
|
status: svcAcctReq.Status,
|
||||||
sessionPolicy: sp,
|
sessionPolicy: sp,
|
||||||
}
|
}
|
||||||
err = globalIAMSys.UpdateServiceAccount(ctx, svcAcctReq.AccessKey, opts)
|
_, err = globalIAMSys.UpdateServiceAccount(ctx, svcAcctReq.AccessKey, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, allSvcAcctsFile, user), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, allSvcAcctsFile, user), r.URL)
|
||||||
return
|
return
|
||||||
@ -2044,7 +2062,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
opts.claims[ldapUser] = targetUser // username DN
|
opts.claims[ldapUser] = targetUser // username DN
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = globalIAMSys.NewServiceAccount(ctx, svcAcctReq.Parent, svcAcctReq.Groups, opts); err != nil {
|
if _, _, err = globalIAMSys.NewServiceAccount(ctx, svcAcctReq.Parent, svcAcctReq.Groups, opts); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, allSvcAcctsFile, user), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, allSvcAcctsFile, user), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2084,7 +2102,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeErrorResponseJSON(ctx, w, importError(ctx, errIAMActionNotAllowed, userPolicyMappingsFile, u), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, errIAMActionNotAllowed, userPolicyMappingsFile, u), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := globalIAMSys.PolicyDBSet(ctx, u, pm.Policies, false); err != nil {
|
if _, err := globalIAMSys.PolicyDBSet(ctx, u, pm.Policies, false); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, userPolicyMappingsFile, u), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, userPolicyMappingsFile, u), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2113,7 +2131,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for g, pm := range grpPolicyMap {
|
for g, pm := range grpPolicyMap {
|
||||||
if err := globalIAMSys.PolicyDBSet(ctx, g, pm.Policies, true); err != nil {
|
if _, err := globalIAMSys.PolicyDBSet(ctx, g, pm.Policies, true); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, groupPolicyMappingsFile, g), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, groupPolicyMappingsFile, g), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2152,7 +2170,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeErrorResponseJSON(ctx, w, importError(ctx, errIAMActionNotAllowed, stsUserPolicyMappingsFile, u), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, errIAMActionNotAllowed, stsUserPolicyMappingsFile, u), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := globalIAMSys.PolicyDBSet(ctx, u, pm.Policies, false); err != nil {
|
if _, err := globalIAMSys.PolicyDBSet(ctx, u, pm.Policies, false); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, stsUserPolicyMappingsFile, u), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, stsUserPolicyMappingsFile, u), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2181,7 +2199,7 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for g, pm := range grpPolicyMap {
|
for g, pm := range grpPolicyMap {
|
||||||
if err := globalIAMSys.PolicyDBSet(ctx, g, pm.Policies, true); err != nil {
|
if _, err := globalIAMSys.PolicyDBSet(ctx, g, pm.Policies, true); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, stsGroupPolicyMappingsFile, g), r.URL)
|
writeErrorResponseJSON(ctx, w, importError(ctx, err, stsGroupPolicyMappingsFile, g), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/minio/minio/internal/auth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type iamDummyStore struct {
|
type iamDummyStore struct {
|
||||||
@ -79,7 +77,7 @@ func (ids *iamDummyStore) loadPolicyDocs(ctx context.Context, m map[string]Polic
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ids *iamDummyStore) loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]auth.Credentials) error {
|
func (ids *iamDummyStore) loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]UserIdentity) error {
|
||||||
u, ok := ids.iamUsersMap[user]
|
u, ok := ids.iamUsersMap[user]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchUser
|
return errNoSuchUser
|
||||||
@ -88,7 +86,7 @@ func (ids *iamDummyStore) loadUser(ctx context.Context, user string, userType IA
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ids *iamDummyStore) loadUsers(ctx context.Context, userType IAMUserType, m map[string]auth.Credentials) error {
|
func (ids *iamDummyStore) loadUsers(ctx context.Context, userType IAMUserType, m map[string]UserIdentity) error {
|
||||||
for k, v := range ids.iamUsersMap {
|
for k, v := range ids.iamUsersMap {
|
||||||
m[k] = v
|
m[k] = v
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ func (ies *IAMEtcdStore) loadPolicyDocs(ctx context.Context, m map[string]Policy
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ies *IAMEtcdStore) getUserKV(ctx context.Context, userkv *mvccpb.KeyValue, userType IAMUserType, m map[string]auth.Credentials, basePrefix string) error {
|
func (ies *IAMEtcdStore) getUserKV(ctx context.Context, userkv *mvccpb.KeyValue, userType IAMUserType, m map[string]UserIdentity, basePrefix string) error {
|
||||||
var u UserIdentity
|
var u UserIdentity
|
||||||
err := getIAMConfig(&u, userkv.Value, string(userkv.Key))
|
err := getIAMConfig(&u, userkv.Value, string(userkv.Key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -349,7 +349,7 @@ func (ies *IAMEtcdStore) getUserKV(ctx context.Context, userkv *mvccpb.KeyValue,
|
|||||||
return ies.addUser(ctx, user, userType, u, m)
|
return ies.addUser(ctx, user, userType, u, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ies *IAMEtcdStore) addUser(ctx context.Context, user string, userType IAMUserType, u UserIdentity, m map[string]auth.Credentials) error {
|
func (ies *IAMEtcdStore) addUser(ctx context.Context, user string, userType IAMUserType, u UserIdentity, m map[string]UserIdentity) error {
|
||||||
if u.Credentials.IsExpired() {
|
if u.Credentials.IsExpired() {
|
||||||
// Delete expired identity.
|
// Delete expired identity.
|
||||||
deleteKeyEtcd(ctx, ies.client, getUserIdentityPath(user, userType))
|
deleteKeyEtcd(ctx, ies.client, getUserIdentityPath(user, userType))
|
||||||
@ -359,11 +359,11 @@ func (ies *IAMEtcdStore) addUser(ctx context.Context, user string, userType IAMU
|
|||||||
if u.Credentials.AccessKey == "" {
|
if u.Credentials.AccessKey == "" {
|
||||||
u.Credentials.AccessKey = user
|
u.Credentials.AccessKey = user
|
||||||
}
|
}
|
||||||
m[user] = u.Credentials
|
m[user] = u
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ies *IAMEtcdStore) loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]auth.Credentials) error {
|
func (ies *IAMEtcdStore) loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]UserIdentity) error {
|
||||||
var u UserIdentity
|
var u UserIdentity
|
||||||
err := ies.loadIAMConfig(ctx, &u, getUserIdentityPath(user, userType))
|
err := ies.loadIAMConfig(ctx, &u, getUserIdentityPath(user, userType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -375,7 +375,7 @@ func (ies *IAMEtcdStore) loadUser(ctx context.Context, user string, userType IAM
|
|||||||
return ies.addUser(ctx, user, userType, u, m)
|
return ies.addUser(ctx, user, userType, u, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ies *IAMEtcdStore) loadUsers(ctx context.Context, userType IAMUserType, m map[string]auth.Credentials) error {
|
func (ies *IAMEtcdStore) loadUsers(ctx context.Context, userType IAMUserType, m map[string]UserIdentity) error {
|
||||||
var basePrefix string
|
var basePrefix string
|
||||||
switch userType {
|
switch userType {
|
||||||
case svcUser:
|
case svcUser:
|
||||||
|
@ -287,7 +287,7 @@ func (iamOS *IAMObjectStore) loadPolicyDocs(ctx context.Context, m map[string]Po
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iamOS *IAMObjectStore) loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]auth.Credentials) error {
|
func (iamOS *IAMObjectStore) loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]UserIdentity) error {
|
||||||
var u UserIdentity
|
var u UserIdentity
|
||||||
err := iamOS.loadIAMConfig(ctx, &u, getUserIdentityPath(user, userType))
|
err := iamOS.loadIAMConfig(ctx, &u, getUserIdentityPath(user, userType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -308,11 +308,11 @@ func (iamOS *IAMObjectStore) loadUser(ctx context.Context, user string, userType
|
|||||||
u.Credentials.AccessKey = user
|
u.Credentials.AccessKey = user
|
||||||
}
|
}
|
||||||
|
|
||||||
m[user] = u.Credentials
|
m[user] = u
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iamOS *IAMObjectStore) loadUsers(ctx context.Context, userType IAMUserType, m map[string]auth.Credentials) error {
|
func (iamOS *IAMObjectStore) loadUsers(ctx context.Context, userType IAMUserType, m map[string]UserIdentity) error {
|
||||||
var basePrefix string
|
var basePrefix string
|
||||||
switch userType {
|
switch userType {
|
||||||
case svcUser:
|
case svcUser:
|
||||||
|
282
cmd/iam-store.go
282
cmd/iam-store.go
@ -249,7 +249,7 @@ type iamCache struct {
|
|||||||
// map of policy names to policy definitions
|
// map of policy names to policy definitions
|
||||||
iamPolicyDocsMap map[string]PolicyDoc
|
iamPolicyDocsMap map[string]PolicyDoc
|
||||||
// map of usernames to credentials
|
// map of usernames to credentials
|
||||||
iamUsersMap map[string]auth.Credentials
|
iamUsersMap map[string]UserIdentity
|
||||||
// map of group names to group info
|
// map of group names to group info
|
||||||
iamGroupsMap map[string]GroupInfo
|
iamGroupsMap map[string]GroupInfo
|
||||||
// map of user names to groups they are a member of
|
// map of user names to groups they are a member of
|
||||||
@ -263,7 +263,7 @@ type iamCache struct {
|
|||||||
func newIamCache() *iamCache {
|
func newIamCache() *iamCache {
|
||||||
return &iamCache{
|
return &iamCache{
|
||||||
iamPolicyDocsMap: map[string]PolicyDoc{},
|
iamPolicyDocsMap: map[string]PolicyDoc{},
|
||||||
iamUsersMap: map[string]auth.Credentials{},
|
iamUsersMap: map[string]UserIdentity{},
|
||||||
iamGroupsMap: map[string]GroupInfo{},
|
iamGroupsMap: map[string]GroupInfo{},
|
||||||
iamUserGroupMemberships: map[string]set.StringSet{},
|
iamUserGroupMemberships: map[string]set.StringSet{},
|
||||||
iamUserPolicyMap: map[string]MappedPolicy{},
|
iamUserPolicyMap: map[string]MappedPolicy{},
|
||||||
@ -346,16 +346,16 @@ func (c *iamCache) policyDBGet(mode UsersSysType, name string, isGroup bool) ([]
|
|||||||
var parentName string
|
var parentName string
|
||||||
u, ok := c.iamUsersMap[name]
|
u, ok := c.iamUsersMap[name]
|
||||||
if ok {
|
if ok {
|
||||||
if !u.IsValid() {
|
if !u.Credentials.IsValid() {
|
||||||
return nil, time.Time{}, nil
|
return nil, time.Time{}, nil
|
||||||
}
|
}
|
||||||
parentName = u.ParentUser
|
parentName = u.Credentials.ParentUser
|
||||||
}
|
}
|
||||||
|
|
||||||
mp, ok := c.iamUserPolicyMap[name]
|
mp, ok := c.iamUserPolicyMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Service accounts with root credentials, inherit parent permissions
|
// Service accounts with root credentials, inherit parent permissions
|
||||||
if parentName == globalActiveCred.AccessKey && u.IsServiceAccount() {
|
if parentName == globalActiveCred.AccessKey && u.Credentials.IsServiceAccount() {
|
||||||
// even if this is set, the claims present in the service
|
// even if this is set, the claims present in the service
|
||||||
// accounts apply the final permissions if any.
|
// accounts apply the final permissions if any.
|
||||||
return []string{"consoleAdmin"}, mp.UpdatedAt, nil
|
return []string{"consoleAdmin"}, mp.UpdatedAt, nil
|
||||||
@ -395,8 +395,8 @@ type IAMStorageAPI interface {
|
|||||||
getUsersSysType() UsersSysType
|
getUsersSysType() UsersSysType
|
||||||
loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error
|
loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error
|
||||||
loadPolicyDocs(ctx context.Context, m map[string]PolicyDoc) error
|
loadPolicyDocs(ctx context.Context, m map[string]PolicyDoc) error
|
||||||
loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]auth.Credentials) error
|
loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]UserIdentity) error
|
||||||
loadUsers(ctx context.Context, userType IAMUserType, m map[string]auth.Credentials) error
|
loadUsers(ctx context.Context, userType IAMUserType, m map[string]UserIdentity) error
|
||||||
loadGroup(ctx context.Context, group string, m map[string]GroupInfo) error
|
loadGroup(ctx context.Context, group string, m map[string]GroupInfo) error
|
||||||
loadGroups(ctx context.Context, 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
|
loadMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error
|
||||||
@ -526,12 +526,12 @@ func (store *IAMStoreSys) HasWatcher() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetUser - fetches credential from memory.
|
// GetUser - fetches credential from memory.
|
||||||
func (store *IAMStoreSys) GetUser(user string) (auth.Credentials, bool) {
|
func (store *IAMStoreSys) GetUser(user string) (UserIdentity, bool) {
|
||||||
cache := store.rlock()
|
cache := store.rlock()
|
||||||
defer store.runlock()
|
defer store.runlock()
|
||||||
|
|
||||||
c, ok := cache.iamUsersMap[user]
|
u, ok := cache.iamUsersMap[user]
|
||||||
return c, ok
|
return u, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMappedPolicy - fetches mapped policy from memory.
|
// GetMappedPolicy - fetches mapped policy from memory.
|
||||||
@ -614,9 +614,9 @@ func (store *IAMStoreSys) PolicyDBGet(name string, isGroup bool, groups ...strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddUsersToGroup - adds users to group, creating the group if needed.
|
// AddUsersToGroup - adds users to group, creating the group if needed.
|
||||||
func (store *IAMStoreSys) AddUsersToGroup(ctx context.Context, group string, members []string) error {
|
func (store *IAMStoreSys) AddUsersToGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
|
||||||
if group == "" {
|
if group == "" {
|
||||||
return errInvalidArgument
|
return updatedAt, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
@ -624,12 +624,13 @@ func (store *IAMStoreSys) AddUsersToGroup(ctx context.Context, group string, mem
|
|||||||
|
|
||||||
// Validate that all members exist.
|
// Validate that all members exist.
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
cr, ok := cache.iamUsersMap[member]
|
u, ok := cache.iamUsersMap[member]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchUser
|
return updatedAt, errNoSuchUser
|
||||||
}
|
}
|
||||||
|
cr := u.Credentials
|
||||||
if cr.IsTemp() || cr.IsServiceAccount() {
|
if cr.IsTemp() || cr.IsServiceAccount() {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,10 +641,11 @@ func (store *IAMStoreSys) AddUsersToGroup(ctx context.Context, group string, mem
|
|||||||
gi = newGroupInfo(members)
|
gi = newGroupInfo(members)
|
||||||
} else {
|
} else {
|
||||||
gi.Members = set.CreateStringSet(append(gi.Members, members...)...).ToSlice()
|
gi.Members = set.CreateStringSet(append(gi.Members, members...)...).ToSlice()
|
||||||
|
gi.UpdatedAt = UTCNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := store.saveGroupInfo(ctx, group, gi); err != nil {
|
if err := store.saveGroupInfo(ctx, group, gi); err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamGroupsMap[group] = gi
|
cache.iamGroupsMap[group] = gi
|
||||||
@ -660,16 +662,15 @@ func (store *IAMStoreSys) AddUsersToGroup(ctx context.Context, group string, mem
|
|||||||
}
|
}
|
||||||
|
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
return gi.UpdatedAt, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function - does not take any locks. Updates only cache if
|
// helper function - does not take any locks. Updates only cache if
|
||||||
// updateCacheOnly is set.
|
// updateCacheOnly is set.
|
||||||
func removeMembersFromGroup(ctx context.Context, store *IAMStoreSys, cache *iamCache, group string, members []string, updateCacheOnly bool) error {
|
func removeMembersFromGroup(ctx context.Context, store *IAMStoreSys, cache *iamCache, group string, members []string, updateCacheOnly bool) (updatedAt time.Time, err error) {
|
||||||
gi, ok := cache.iamGroupsMap[group]
|
gi, ok := cache.iamGroupsMap[group]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchGroup
|
return updatedAt, errNoSuchGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
s := set.CreateStringSet(gi.Members...)
|
s := set.CreateStringSet(gi.Members...)
|
||||||
@ -679,9 +680,10 @@ func removeMembersFromGroup(ctx context.Context, store *IAMStoreSys, cache *iamC
|
|||||||
if !updateCacheOnly {
|
if !updateCacheOnly {
|
||||||
err := store.saveGroupInfo(ctx, group, gi)
|
err := store.saveGroupInfo(ctx, group, gi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gi.UpdatedAt = UTCNow()
|
||||||
cache.iamGroupsMap[group] = gi
|
cache.iamGroupsMap[group] = gi
|
||||||
|
|
||||||
// update user-group membership map
|
// update user-group membership map
|
||||||
@ -695,13 +697,13 @@ func removeMembersFromGroup(ctx context.Context, store *IAMStoreSys, cache *iamC
|
|||||||
}
|
}
|
||||||
|
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
return nil
|
return gi.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveUsersFromGroup - removes users from group, deleting it if it is empty.
|
// RemoveUsersFromGroup - removes users from group, deleting it if it is empty.
|
||||||
func (store *IAMStoreSys) RemoveUsersFromGroup(ctx context.Context, group string, members []string) error {
|
func (store *IAMStoreSys) RemoveUsersFromGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
|
||||||
if group == "" {
|
if group == "" {
|
||||||
return errInvalidArgument
|
return updatedAt, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
@ -709,23 +711,24 @@ func (store *IAMStoreSys) RemoveUsersFromGroup(ctx context.Context, group string
|
|||||||
|
|
||||||
// Validate that all members exist.
|
// Validate that all members exist.
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
cr, ok := cache.iamUsersMap[member]
|
u, ok := cache.iamUsersMap[member]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchUser
|
return updatedAt, errNoSuchUser
|
||||||
}
|
}
|
||||||
|
cr := u.Credentials
|
||||||
if cr.IsTemp() || cr.IsServiceAccount() {
|
if cr.IsTemp() || cr.IsServiceAccount() {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gi, ok := cache.iamGroupsMap[group]
|
gi, ok := cache.iamGroupsMap[group]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchGroup
|
return updatedAt, errNoSuchGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if attempting to delete a non-empty group.
|
// Check if attempting to delete a non-empty group.
|
||||||
if len(members) == 0 && len(gi.Members) != 0 {
|
if len(members) == 0 && len(gi.Members) != 0 {
|
||||||
return errGroupNotEmpty
|
return updatedAt, errGroupNotEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(members) == 0 {
|
if len(members) == 0 {
|
||||||
@ -734,26 +737,26 @@ func (store *IAMStoreSys) RemoveUsersFromGroup(ctx context.Context, group string
|
|||||||
// Remove the group from storage. First delete the
|
// Remove the group from storage. First delete the
|
||||||
// mapped policy. No-mapped-policy case is ignored.
|
// mapped policy. No-mapped-policy case is ignored.
|
||||||
if err := store.deleteMappedPolicy(ctx, group, regUser, true); err != nil && err != errNoSuchPolicy {
|
if err := store.deleteMappedPolicy(ctx, group, regUser, true); err != nil && err != errNoSuchPolicy {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
if err := store.deleteGroupInfo(ctx, group); err != nil && err != errNoSuchGroup {
|
if err := store.deleteGroupInfo(ctx, group); err != nil && err != errNoSuchGroup {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete from server memory
|
// Delete from server memory
|
||||||
delete(cache.iamGroupsMap, group)
|
delete(cache.iamGroupsMap, group)
|
||||||
delete(cache.iamGroupPolicyMap, group)
|
delete(cache.iamGroupPolicyMap, group)
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
return nil
|
return cache.updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeMembersFromGroup(ctx, store, cache, group, members, false)
|
return removeMembersFromGroup(ctx, store, cache, group, members, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroupStatus - updates group status
|
// SetGroupStatus - updates group status
|
||||||
func (store *IAMStoreSys) SetGroupStatus(ctx context.Context, group string, enabled bool) error {
|
func (store *IAMStoreSys) SetGroupStatus(ctx context.Context, group string, enabled bool) (updatedAt time.Time, err error) {
|
||||||
if group == "" {
|
if group == "" {
|
||||||
return errInvalidArgument
|
return updatedAt, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
@ -761,7 +764,7 @@ func (store *IAMStoreSys) SetGroupStatus(ctx context.Context, group string, enab
|
|||||||
|
|
||||||
gi, ok := cache.iamGroupsMap[group]
|
gi, ok := cache.iamGroupsMap[group]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchGroup
|
return updatedAt, errNoSuchGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
if enabled {
|
if enabled {
|
||||||
@ -769,15 +772,15 @@ func (store *IAMStoreSys) SetGroupStatus(ctx context.Context, group string, enab
|
|||||||
} else {
|
} else {
|
||||||
gi.Status = statusDisabled
|
gi.Status = statusDisabled
|
||||||
}
|
}
|
||||||
|
gi.UpdatedAt = UTCNow()
|
||||||
if err := store.saveGroupInfo(ctx, group, gi); err != nil {
|
if err := store.saveGroupInfo(ctx, group, gi); err != nil {
|
||||||
return err
|
return gi.UpdatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamGroupsMap[group] = gi
|
cache.iamGroupsMap[group] = gi
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
return nil
|
return gi.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroupDescription - builds up group description
|
// GetGroupDescription - builds up group description
|
||||||
@ -851,9 +854,9 @@ func (store *IAMStoreSys) ListGroups(ctx context.Context) (res []string, err err
|
|||||||
|
|
||||||
// PolicyDBSet - update the policy mapping for the given user or group in
|
// PolicyDBSet - update the policy mapping for the given user or group in
|
||||||
// storage and in cache.
|
// storage and in cache.
|
||||||
func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string, userType IAMUserType, isGroup bool) error {
|
func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string, userType IAMUserType, isGroup bool) (updatedAt time.Time, err error) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return errInvalidArgument
|
return updatedAt, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
@ -863,11 +866,11 @@ func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string,
|
|||||||
if store.getUsersSysType() == MinIOUsersSysType {
|
if store.getUsersSysType() == MinIOUsersSysType {
|
||||||
if !isGroup {
|
if !isGroup {
|
||||||
if _, ok := cache.iamUsersMap[name]; !ok {
|
if _, ok := cache.iamUsersMap[name]; !ok {
|
||||||
return errNoSuchUser
|
return updatedAt, errNoSuchUser
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if _, ok := cache.iamGroupsMap[name]; !ok {
|
if _, ok := cache.iamGroupsMap[name]; !ok {
|
||||||
return errNoSuchGroup
|
return updatedAt, errNoSuchGroup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -882,7 +885,7 @@ func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string,
|
|||||||
}
|
}
|
||||||
err := store.deleteMappedPolicy(ctx, name, userType, isGroup)
|
err := store.deleteMappedPolicy(ctx, name, userType, isGroup)
|
||||||
if err != nil && err != errNoSuchPolicy {
|
if err != nil && err != errNoSuchPolicy {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
if !isGroup {
|
if !isGroup {
|
||||||
delete(cache.iamUserPolicyMap, name)
|
delete(cache.iamUserPolicyMap, name)
|
||||||
@ -890,8 +893,7 @@ func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string,
|
|||||||
delete(cache.iamGroupPolicyMap, name)
|
delete(cache.iamGroupPolicyMap, name)
|
||||||
}
|
}
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
return cache.updatedAt, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle policy mapping set/update
|
// Handle policy mapping set/update
|
||||||
@ -899,12 +901,12 @@ func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string,
|
|||||||
for _, p := range mp.toSlice() {
|
for _, p := range mp.toSlice() {
|
||||||
if _, found := cache.iamPolicyDocsMap[p]; !found {
|
if _, found := cache.iamPolicyDocsMap[p]; !found {
|
||||||
logger.LogIf(GlobalContext, fmt.Errorf("%w: (%s)", errNoSuchPolicy, p))
|
logger.LogIf(GlobalContext, fmt.Errorf("%w: (%s)", errNoSuchPolicy, p))
|
||||||
return errNoSuchPolicy
|
return updatedAt, errNoSuchPolicy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := store.saveMappedPolicy(ctx, name, userType, isGroup, mp); err != nil {
|
if err := store.saveMappedPolicy(ctx, name, userType, isGroup, mp); err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
if !isGroup {
|
if !isGroup {
|
||||||
cache.iamUserPolicyMap[name] = mp
|
cache.iamUserPolicyMap[name] = mp
|
||||||
@ -912,7 +914,7 @@ func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string,
|
|||||||
cache.iamGroupPolicyMap[name] = mp
|
cache.iamGroupPolicyMap[name] = mp
|
||||||
}
|
}
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
return nil
|
return mp.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PolicyNotificationHandler - loads given policy from storage. If not present,
|
// PolicyNotificationHandler - loads given policy from storage. If not present,
|
||||||
@ -1068,9 +1070,9 @@ func (store *IAMStoreSys) GetPolicyDoc(name string) (r PolicyDoc, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetPolicy - creates a policy with name.
|
// SetPolicy - creates a policy with name.
|
||||||
func (store *IAMStoreSys) SetPolicy(ctx context.Context, name string, policy iampolicy.Policy) error {
|
func (store *IAMStoreSys) SetPolicy(ctx context.Context, name string, policy iampolicy.Policy) (time.Time, error) {
|
||||||
if policy.IsEmpty() || name == "" {
|
if policy.IsEmpty() || name == "" {
|
||||||
return errInvalidArgument
|
return time.Time{}, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
@ -1087,13 +1089,13 @@ func (store *IAMStoreSys) SetPolicy(ctx context.Context, name string, policy iam
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := store.savePolicyDoc(ctx, name, d); err != nil {
|
if err := store.savePolicyDoc(ctx, name, d); err != nil {
|
||||||
return err
|
return d.UpdateDate, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamPolicyDocsMap[name] = d
|
cache.iamPolicyDocsMap[name] = d
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
return nil
|
return d.UpdateDate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListPolicies - fetches all policies from storage and updates cache as well.
|
// ListPolicies - fetches all policies from storage and updates cache as well.
|
||||||
@ -1198,7 +1200,8 @@ func (store *IAMStoreSys) GetBucketUsers(bucket string) (map[string]madmin.UserI
|
|||||||
|
|
||||||
result := map[string]madmin.UserInfo{}
|
result := map[string]madmin.UserInfo{}
|
||||||
for k, v := range cache.iamUsersMap {
|
for k, v := range cache.iamUsersMap {
|
||||||
if v.IsTemp() || v.IsServiceAccount() {
|
c := v.Credentials
|
||||||
|
if c.IsTemp() || c.IsServiceAccount() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var policies []string
|
var policies []string
|
||||||
@ -1216,7 +1219,7 @@ func (store *IAMStoreSys) GetBucketUsers(bucket string) (map[string]madmin.UserI
|
|||||||
result[k] = madmin.UserInfo{
|
result[k] = madmin.UserInfo{
|
||||||
PolicyName: matchedPolicies,
|
PolicyName: matchedPolicies,
|
||||||
Status: func() madmin.AccountStatus {
|
Status: func() madmin.AccountStatus {
|
||||||
if v.IsValid() {
|
if c.IsValid() {
|
||||||
return madmin.AccountEnabled
|
return madmin.AccountEnabled
|
||||||
}
|
}
|
||||||
return madmin.AccountDisabled
|
return madmin.AccountDisabled
|
||||||
@ -1235,7 +1238,9 @@ func (store *IAMStoreSys) GetUsers() map[string]madmin.UserInfo {
|
|||||||
defer store.runlock()
|
defer store.runlock()
|
||||||
|
|
||||||
result := map[string]madmin.UserInfo{}
|
result := map[string]madmin.UserInfo{}
|
||||||
for k, v := range cache.iamUsersMap {
|
for k, u := range cache.iamUsersMap {
|
||||||
|
v := u.Credentials
|
||||||
|
|
||||||
if v.IsTemp() || v.IsServiceAccount() {
|
if v.IsTemp() || v.IsServiceAccount() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1281,8 +1286,8 @@ func (store *IAMStoreSys) GetUserInfo(name string) (u madmin.UserInfo, err error
|
|||||||
// return that info. Otherwise we return error.
|
// return that info. Otherwise we return error.
|
||||||
var groups []string
|
var groups []string
|
||||||
for _, v := range cache.iamUsersMap {
|
for _, v := range cache.iamUsersMap {
|
||||||
if v.ParentUser == name {
|
if v.Credentials.ParentUser == name {
|
||||||
groups = v.Groups
|
groups = v.Credentials.Groups
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1297,11 +1302,11 @@ func (store *IAMStoreSys) GetUserInfo(name string) (u madmin.UserInfo, err error
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, found := cache.iamUsersMap[name]
|
ui, found := cache.iamUsersMap[name]
|
||||||
if !found {
|
if !found {
|
||||||
return u, errNoSuchUser
|
return u, errNoSuchUser
|
||||||
}
|
}
|
||||||
|
cred := ui.Credentials
|
||||||
if cred.IsTemp() || cred.IsServiceAccount() {
|
if cred.IsTemp() || cred.IsServiceAccount() {
|
||||||
return u, errIAMActionNotAllowed
|
return u, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
@ -1363,7 +1368,7 @@ func (store *IAMStoreSys) UserNotificationHandler(ctx context.Context, accessKey
|
|||||||
if store.getUsersSysType() == MinIOUsersSysType {
|
if store.getUsersSysType() == MinIOUsersSysType {
|
||||||
memberOf := cache.iamUserGroupMemberships[accessKey].ToSlice()
|
memberOf := cache.iamUserGroupMemberships[accessKey].ToSlice()
|
||||||
for _, group := range memberOf {
|
for _, group := range memberOf {
|
||||||
removeErr := removeMembersFromGroup(ctx, store, cache, group, []string{accessKey}, true)
|
_, removeErr := removeMembersFromGroup(ctx, store, cache, group, []string{accessKey}, true)
|
||||||
if removeErr == errNoSuchGroup {
|
if removeErr == errNoSuchGroup {
|
||||||
removeErr = nil
|
removeErr = nil
|
||||||
}
|
}
|
||||||
@ -1376,11 +1381,11 @@ func (store *IAMStoreSys) UserNotificationHandler(ctx context.Context, accessKey
|
|||||||
// 2. Remove any derived credentials from memory
|
// 2. Remove any derived credentials from memory
|
||||||
if userType == regUser {
|
if userType == regUser {
|
||||||
for _, u := range cache.iamUsersMap {
|
for _, u := range cache.iamUsersMap {
|
||||||
if u.IsServiceAccount() && u.ParentUser == accessKey {
|
if u.Credentials.IsServiceAccount() && u.Credentials.ParentUser == accessKey {
|
||||||
delete(cache.iamUsersMap, u.AccessKey)
|
delete(cache.iamUsersMap, u.Credentials.AccessKey)
|
||||||
}
|
}
|
||||||
if u.IsTemp() && u.ParentUser == accessKey {
|
if u.Credentials.IsTemp() && u.Credentials.ParentUser == accessKey {
|
||||||
delete(cache.iamUsersMap, u.AccessKey)
|
delete(cache.iamUsersMap, u.Credentials.AccessKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1412,8 +1417,9 @@ func (store *IAMStoreSys) UserNotificationHandler(ctx context.Context, accessKey
|
|||||||
// This mapping is necessary to ensure that valid credentials
|
// This mapping is necessary to ensure that valid credentials
|
||||||
// have necessary ParentUser present - this is mainly for only
|
// have necessary ParentUser present - this is mainly for only
|
||||||
// webIdentity based STS tokens.
|
// webIdentity based STS tokens.
|
||||||
cred, ok := cache.iamUsersMap[accessKey]
|
u, ok := cache.iamUsersMap[accessKey]
|
||||||
if ok {
|
if ok {
|
||||||
|
cred := u.Credentials
|
||||||
if cred.IsTemp() && cred.ParentUser != "" && cred.ParentUser != globalActiveCred.AccessKey {
|
if cred.IsTemp() && cred.ParentUser != "" && cred.ParentUser != globalActiveCred.AccessKey {
|
||||||
if _, ok := cache.iamUserPolicyMap[cred.ParentUser]; !ok {
|
if _, ok := cache.iamUserPolicyMap[cred.ParentUser]; !ok {
|
||||||
cache.iamUserPolicyMap[cred.ParentUser] = cache.iamUserPolicyMap[accessKey]
|
cache.iamUserPolicyMap[cred.ParentUser] = cache.iamUserPolicyMap[accessKey]
|
||||||
@ -1439,7 +1445,7 @@ func (store *IAMStoreSys) DeleteUser(ctx context.Context, accessKey string, user
|
|||||||
if store.getUsersSysType() == MinIOUsersSysType && userType == regUser {
|
if store.getUsersSysType() == MinIOUsersSysType && userType == regUser {
|
||||||
memberOf := cache.iamUserGroupMemberships[accessKey].ToSlice()
|
memberOf := cache.iamUserGroupMemberships[accessKey].ToSlice()
|
||||||
for _, group := range memberOf {
|
for _, group := range memberOf {
|
||||||
removeErr := removeMembersFromGroup(ctx, store, cache, group, []string{accessKey}, false)
|
_, removeErr := removeMembersFromGroup(ctx, store, cache, group, []string{accessKey}, false)
|
||||||
if removeErr != nil {
|
if removeErr != nil {
|
||||||
return removeErr
|
return removeErr
|
||||||
}
|
}
|
||||||
@ -1451,7 +1457,8 @@ func (store *IAMStoreSys) DeleteUser(ctx context.Context, accessKey string, user
|
|||||||
// Delete any STS and service account derived from this credential
|
// Delete any STS and service account derived from this credential
|
||||||
// first.
|
// first.
|
||||||
if userType == regUser {
|
if userType == regUser {
|
||||||
for _, u := range cache.iamUsersMap {
|
for _, ui := range cache.iamUsersMap {
|
||||||
|
u := ui.Credentials
|
||||||
if u.IsServiceAccount() && u.ParentUser == accessKey {
|
if u.IsServiceAccount() && u.ParentUser == accessKey {
|
||||||
_ = store.deleteUserIdentity(ctx, u.AccessKey, svcUser)
|
_ = store.deleteUserIdentity(ctx, u.AccessKey, svcUser)
|
||||||
delete(cache.iamUsersMap, u.AccessKey)
|
delete(cache.iamUsersMap, u.AccessKey)
|
||||||
@ -1483,9 +1490,9 @@ func (store *IAMStoreSys) DeleteUser(ctx context.Context, accessKey string, user
|
|||||||
// SetTempUser - saves temporary (STS) credential to storage and cache. If a
|
// SetTempUser - saves temporary (STS) credential to storage and cache. If a
|
||||||
// policy name is given, it is associated with the parent user specified in the
|
// policy name is given, it is associated with the parent user specified in the
|
||||||
// credential.
|
// credential.
|
||||||
func (store *IAMStoreSys) SetTempUser(ctx context.Context, accessKey string, cred auth.Credentials, policyName string) error {
|
func (store *IAMStoreSys) SetTempUser(ctx context.Context, accessKey string, cred auth.Credentials, policyName string) (time.Time, error) {
|
||||||
if accessKey == "" || !cred.IsTemp() || cred.IsExpired() || cred.ParentUser == "" {
|
if accessKey == "" || !cred.IsTemp() || cred.IsExpired() || cred.ParentUser == "" {
|
||||||
return errInvalidArgument
|
return time.Time{}, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
ttl := int64(cred.Expiration.Sub(UTCNow()).Seconds())
|
ttl := int64(cred.Expiration.Sub(UTCNow()).Seconds())
|
||||||
@ -1498,12 +1505,12 @@ func (store *IAMStoreSys) SetTempUser(ctx context.Context, accessKey string, cre
|
|||||||
_, combinedPolicyStmt := filterPolicies(cache, mp.Policies, "")
|
_, combinedPolicyStmt := filterPolicies(cache, mp.Policies, "")
|
||||||
|
|
||||||
if combinedPolicyStmt.IsEmpty() {
|
if combinedPolicyStmt.IsEmpty() {
|
||||||
return fmt.Errorf("specified policy %s, not found %w", policyName, errNoSuchPolicy)
|
return time.Time{}, fmt.Errorf("specified policy %s, not found %w", policyName, errNoSuchPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := store.saveMappedPolicy(ctx, cred.ParentUser, stsUser, false, mp, options{ttl: ttl})
|
err := store.saveMappedPolicy(ctx, cred.ParentUser, stsUser, false, mp, options{ttl: ttl})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return time.Time{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamUserPolicyMap[cred.ParentUser] = mp
|
cache.iamUserPolicyMap[cred.ParentUser] = mp
|
||||||
@ -1512,14 +1519,14 @@ func (store *IAMStoreSys) SetTempUser(ctx context.Context, accessKey string, cre
|
|||||||
u := newUserIdentity(cred)
|
u := newUserIdentity(cred)
|
||||||
err := store.saveUserIdentity(ctx, accessKey, stsUser, u, options{ttl: ttl})
|
err := store.saveUserIdentity(ctx, accessKey, stsUser, u, options{ttl: ttl})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return time.Time{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamUsersMap[accessKey] = cred
|
cache.iamUsersMap[accessKey] = u
|
||||||
|
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
return nil
|
return u.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUsers - given a set of users or access keys, deletes them along with
|
// DeleteUsers - given a set of users or access keys, deletes them along with
|
||||||
@ -1531,8 +1538,10 @@ func (store *IAMStoreSys) DeleteUsers(ctx context.Context, users []string) error
|
|||||||
|
|
||||||
var deleted bool
|
var deleted bool
|
||||||
usersToDelete := set.CreateStringSet(users...)
|
usersToDelete := set.CreateStringSet(users...)
|
||||||
for user, cred := range cache.iamUsersMap {
|
for user, ui := range cache.iamUsersMap {
|
||||||
userType := regUser
|
userType := regUser
|
||||||
|
cred := ui.Credentials
|
||||||
|
|
||||||
if cred.IsServiceAccount() {
|
if cred.IsServiceAccount() {
|
||||||
userType = svcUser
|
userType = svcUser
|
||||||
} else if cred.IsTemp() {
|
} else if cred.IsTemp() {
|
||||||
@ -1575,7 +1584,8 @@ func (store *IAMStoreSys) GetAllParentUsers() map[string]ParentUserInfo {
|
|||||||
defer store.runlock()
|
defer store.runlock()
|
||||||
|
|
||||||
res := map[string]ParentUserInfo{}
|
res := map[string]ParentUserInfo{}
|
||||||
for _, cred := range cache.iamUsersMap {
|
for _, ui := range cache.iamUsersMap {
|
||||||
|
cred := ui.Credentials
|
||||||
// Only consider service account or STS credentials with
|
// Only consider service account or STS credentials with
|
||||||
// non-empty session tokens.
|
// non-empty session tokens.
|
||||||
if !(cred.IsServiceAccount() || cred.IsTemp()) ||
|
if !(cred.IsServiceAccount() || cred.IsTemp()) ||
|
||||||
@ -1633,21 +1643,22 @@ func (store *IAMStoreSys) GetAllParentUsers() map[string]ParentUserInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetUserStatus - sets current user status.
|
// SetUserStatus - sets current user status.
|
||||||
func (store *IAMStoreSys) SetUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) error {
|
func (store *IAMStoreSys) SetUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) (updatedAt time.Time, err error) {
|
||||||
if accessKey != "" && status != madmin.AccountEnabled && status != madmin.AccountDisabled {
|
if accessKey != "" && status != madmin.AccountEnabled && status != madmin.AccountDisabled {
|
||||||
return errInvalidArgument
|
return updatedAt, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
defer store.unlock()
|
defer store.unlock()
|
||||||
|
|
||||||
cred, ok := cache.iamUsersMap[accessKey]
|
ui, ok := cache.iamUsersMap[accessKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchUser
|
return updatedAt, errNoSuchUser
|
||||||
}
|
}
|
||||||
|
cred := ui.Credentials
|
||||||
|
|
||||||
if cred.IsTemp() || cred.IsServiceAccount() {
|
if cred.IsTemp() || cred.IsServiceAccount() {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
uinfo := newUserIdentity(auth.Credentials{
|
uinfo := newUserIdentity(auth.Credentials{
|
||||||
@ -1663,17 +1674,17 @@ func (store *IAMStoreSys) SetUserStatus(ctx context.Context, accessKey string, s
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err := store.saveUserIdentity(ctx, accessKey, regUser, uinfo); err != nil {
|
if err := store.saveUserIdentity(ctx, accessKey, regUser, uinfo); err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamUsersMap[accessKey] = uinfo.Credentials
|
cache.iamUsersMap[accessKey] = uinfo
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
return nil
|
return uinfo.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddServiceAccount - add a new service account
|
// AddServiceAccount - add a new service account
|
||||||
func (store *IAMStoreSys) AddServiceAccount(ctx context.Context, cred auth.Credentials) error {
|
func (store *IAMStoreSys) AddServiceAccount(ctx context.Context, cred auth.Credentials) (updatedAt time.Time, err error) {
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
defer store.unlock()
|
defer store.unlock()
|
||||||
|
|
||||||
@ -1683,44 +1694,45 @@ func (store *IAMStoreSys) AddServiceAccount(ctx context.Context, cred auth.Crede
|
|||||||
// Found newly requested service account, to be an existing account -
|
// Found newly requested service account, to be an existing account -
|
||||||
// reject such operation (updates to the service account are handled in
|
// reject such operation (updates to the service account are handled in
|
||||||
// a different API).
|
// a different API).
|
||||||
if scred, found := cache.iamUsersMap[accessKey]; found {
|
if su, found := cache.iamUsersMap[accessKey]; found {
|
||||||
|
scred := su.Credentials
|
||||||
if scred.ParentUser != parentUser {
|
if scred.ParentUser != parentUser {
|
||||||
return errIAMServiceAccountUsed
|
return updatedAt, errIAMServiceAccountUsed
|
||||||
}
|
}
|
||||||
return errIAMServiceAccount
|
return updatedAt, errIAMServiceAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent user must not be a service account.
|
// Parent user must not be a service account.
|
||||||
if cr, found := cache.iamUsersMap[parentUser]; found && cr.IsServiceAccount() {
|
if u, found := cache.iamUsersMap[parentUser]; found && u.Credentials.IsServiceAccount() {
|
||||||
return errIAMServiceAccount
|
return updatedAt, errIAMServiceAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
u := newUserIdentity(cred)
|
u := newUserIdentity(cred)
|
||||||
err := store.saveUserIdentity(ctx, u.Credentials.AccessKey, svcUser, u)
|
err = store.saveUserIdentity(ctx, u.Credentials.AccessKey, svcUser, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamUsersMap[u.Credentials.AccessKey] = u.Credentials
|
cache.iamUsersMap[u.Credentials.AccessKey] = u
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
return nil
|
return u.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateServiceAccount - updates a service account on storage.
|
// UpdateServiceAccount - updates a service account on storage.
|
||||||
func (store *IAMStoreSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) error {
|
func (store *IAMStoreSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) (updatedAt time.Time, err error) {
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
defer store.unlock()
|
defer store.unlock()
|
||||||
|
|
||||||
cr, ok := cache.iamUsersMap[accessKey]
|
ui, ok := cache.iamUsersMap[accessKey]
|
||||||
if !ok || !cr.IsServiceAccount() {
|
if !ok || !ui.Credentials.IsServiceAccount() {
|
||||||
return errNoSuchServiceAccount
|
return updatedAt, errNoSuchServiceAccount
|
||||||
}
|
}
|
||||||
|
cr := ui.Credentials
|
||||||
currentSecretKey := cr.SecretKey
|
currentSecretKey := cr.SecretKey
|
||||||
if opts.secretKey != "" {
|
if opts.secretKey != "" {
|
||||||
if !auth.IsSecretKeyValid(opts.secretKey) {
|
if !auth.IsSecretKeyValid(opts.secretKey) {
|
||||||
return auth.ErrInvalidSecretKeyLength
|
return updatedAt, auth.ErrInvalidSecretKeyLength
|
||||||
}
|
}
|
||||||
cr.SecretKey = opts.secretKey
|
cr.SecretKey = opts.secretKey
|
||||||
}
|
}
|
||||||
@ -1736,12 +1748,12 @@ func (store *IAMStoreSys) UpdateServiceAccount(ctx context.Context, accessKey st
|
|||||||
case auth.AccountOn, auth.AccountOff:
|
case auth.AccountOn, auth.AccountOff:
|
||||||
cr.Status = opts.status
|
cr.Status = opts.status
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown account status value")
|
return updatedAt, errors.New("unknown account status value")
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := getClaimsFromTokenWithSecret(cr.SessionToken, currentSecretKey)
|
m, err := getClaimsFromTokenWithSecret(cr.SessionToken, currentSecretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to get svc acc claims: %v", err)
|
return updatedAt, fmt.Errorf("unable to get svc acc claims: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extracted session policy name string can be removed as its not useful
|
// Extracted session policy name string can be removed as its not useful
|
||||||
@ -1757,16 +1769,16 @@ func (store *IAMStoreSys) UpdateServiceAccount(ctx context.Context, accessKey st
|
|||||||
|
|
||||||
if opts.sessionPolicy != nil {
|
if opts.sessionPolicy != nil {
|
||||||
if err := opts.sessionPolicy.Validate(); err != nil {
|
if err := opts.sessionPolicy.Validate(); err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
policyBuf, err := json.Marshal(opts.sessionPolicy)
|
policyBuf, err := json.Marshal(opts.sessionPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(policyBuf) > 16*humanize.KiByte {
|
if len(policyBuf) > 16*humanize.KiByte {
|
||||||
return fmt.Errorf("Session policy should not exceed 16 KiB characters")
|
return updatedAt, fmt.Errorf("Session policy should not exceed 16 KiB characters")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overwrite session policy claims.
|
// Overwrite session policy claims.
|
||||||
@ -1776,41 +1788,41 @@ func (store *IAMStoreSys) UpdateServiceAccount(ctx context.Context, accessKey st
|
|||||||
|
|
||||||
cr.SessionToken, err = auth.JWTSignWithAccessKey(accessKey, m, cr.SecretKey)
|
cr.SessionToken, err = auth.JWTSignWithAccessKey(accessKey, m, cr.SecretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
u := newUserIdentity(cr)
|
u := newUserIdentity(cr)
|
||||||
if err := store.saveUserIdentity(ctx, u.Credentials.AccessKey, svcUser, u); err != nil {
|
if err := store.saveUserIdentity(ctx, u.Credentials.AccessKey, svcUser, u); err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamUsersMap[u.Credentials.AccessKey] = u.Credentials
|
cache.iamUsersMap[u.Credentials.AccessKey] = u
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
return nil
|
return u.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListTempAccounts - lists only temporary accounts from the cache.
|
// ListTempAccounts - lists only temporary accounts from the cache.
|
||||||
func (store *IAMStoreSys) ListTempAccounts(ctx context.Context, accessKey string) ([]auth.Credentials, error) {
|
func (store *IAMStoreSys) ListTempAccounts(ctx context.Context, accessKey string) ([]UserIdentity, error) {
|
||||||
cache := store.rlock()
|
cache := store.rlock()
|
||||||
defer store.runlock()
|
defer store.runlock()
|
||||||
|
|
||||||
userExists := false
|
userExists := false
|
||||||
var tempAccounts []auth.Credentials
|
var tempAccounts []UserIdentity
|
||||||
for _, v := range cache.iamUsersMap {
|
for _, v := range cache.iamUsersMap {
|
||||||
isDerived := false
|
isDerived := false
|
||||||
if v.IsServiceAccount() || v.IsTemp() {
|
if v.Credentials.IsServiceAccount() || v.Credentials.IsTemp() {
|
||||||
isDerived = true
|
isDerived = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isDerived && v.AccessKey == accessKey {
|
if !isDerived && v.Credentials.AccessKey == accessKey {
|
||||||
userExists = true
|
userExists = true
|
||||||
} else if isDerived && v.ParentUser == accessKey {
|
} else if isDerived && v.Credentials.ParentUser == accessKey {
|
||||||
userExists = true
|
userExists = true
|
||||||
if v.IsTemp() {
|
if v.Credentials.IsTemp() {
|
||||||
// Hide secret key & session key here
|
// Hide secret key & session key here
|
||||||
v.SecretKey = ""
|
v.Credentials.SecretKey = ""
|
||||||
v.SessionToken = ""
|
v.Credentials.SessionToken = ""
|
||||||
tempAccounts = append(tempAccounts, v)
|
tempAccounts = append(tempAccounts, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1830,8 +1842,9 @@ func (store *IAMStoreSys) ListServiceAccounts(ctx context.Context, accessKey str
|
|||||||
|
|
||||||
userExists := false
|
userExists := false
|
||||||
var serviceAccounts []auth.Credentials
|
var serviceAccounts []auth.Credentials
|
||||||
for _, v := range cache.iamUsersMap {
|
for _, u := range cache.iamUsersMap {
|
||||||
isDerived := false
|
isDerived := false
|
||||||
|
v := u.Credentials
|
||||||
if v.IsServiceAccount() || v.IsTemp() {
|
if v.IsServiceAccount() || v.IsTemp() {
|
||||||
isDerived = true
|
isDerived = true
|
||||||
}
|
}
|
||||||
@ -1857,17 +1870,17 @@ func (store *IAMStoreSys) ListServiceAccounts(ctx context.Context, accessKey str
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddUser - adds/updates long term user account to storage.
|
// AddUser - adds/updates long term user account to storage.
|
||||||
func (store *IAMStoreSys) AddUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) error {
|
func (store *IAMStoreSys) AddUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) (updatedAt time.Time, err error) {
|
||||||
cache := store.lock()
|
cache := store.lock()
|
||||||
defer store.unlock()
|
defer store.unlock()
|
||||||
|
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
cr, ok := cache.iamUsersMap[accessKey]
|
ui, ok := cache.iamUsersMap[accessKey]
|
||||||
|
|
||||||
// It is not possible to update an STS account.
|
// It is not possible to update an STS account.
|
||||||
if ok && cr.IsTemp() {
|
if ok && ui.Credentials.IsTemp() {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
u := newUserIdentity(auth.Credentials{
|
u := newUserIdentity(auth.Credentials{
|
||||||
@ -1883,12 +1896,12 @@ func (store *IAMStoreSys) AddUser(ctx context.Context, accessKey string, ureq ma
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err := store.saveUserIdentity(ctx, accessKey, regUser, u); err != nil {
|
if err := store.saveUserIdentity(ctx, accessKey, regUser, u); err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamUsersMap[accessKey] = u.Credentials
|
cache.iamUsersMap[accessKey] = u
|
||||||
|
|
||||||
return nil
|
return u.UpdatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUserSecretKey - sets user secret key to storage.
|
// UpdateUserSecretKey - sets user secret key to storage.
|
||||||
@ -1898,18 +1911,18 @@ func (store *IAMStoreSys) UpdateUserSecretKey(ctx context.Context, accessKey, se
|
|||||||
|
|
||||||
cache.updatedAt = time.Now()
|
cache.updatedAt = time.Now()
|
||||||
|
|
||||||
cred, ok := cache.iamUsersMap[accessKey]
|
ui, ok := cache.iamUsersMap[accessKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNoSuchUser
|
return errNoSuchUser
|
||||||
}
|
}
|
||||||
|
cred := ui.Credentials
|
||||||
cred.SecretKey = secretKey
|
cred.SecretKey = secretKey
|
||||||
u := newUserIdentity(cred)
|
u := newUserIdentity(cred)
|
||||||
if err := store.saveUserIdentity(ctx, accessKey, regUser, u); err != nil {
|
if err := store.saveUserIdentity(ctx, accessKey, regUser, u); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.iamUsersMap[accessKey] = cred
|
cache.iamUsersMap[accessKey] = u
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1919,7 +1932,8 @@ func (store *IAMStoreSys) GetSTSAndServiceAccounts() []auth.Credentials {
|
|||||||
defer store.runlock()
|
defer store.runlock()
|
||||||
|
|
||||||
var res []auth.Credentials
|
var res []auth.Credentials
|
||||||
for _, cred := range cache.iamUsersMap {
|
for _, u := range cache.iamUsersMap {
|
||||||
|
cred := u.Credentials
|
||||||
if cred.IsTemp() || cred.IsServiceAccount() {
|
if cred.IsTemp() || cred.IsServiceAccount() {
|
||||||
res = append(res, cred)
|
res = append(res, cred)
|
||||||
}
|
}
|
||||||
@ -1940,13 +1954,13 @@ func (store *IAMStoreSys) UpdateUserIdentity(ctx context.Context, cred auth.Cred
|
|||||||
} else if cred.IsTemp() {
|
} else if cred.IsTemp() {
|
||||||
userType = stsUser
|
userType = stsUser
|
||||||
}
|
}
|
||||||
|
ui := newUserIdentity(cred)
|
||||||
// Overwrite the user identity here. As store should be
|
// Overwrite the user identity here. As store should be
|
||||||
// atomic, it shouldn't cause any corruption.
|
// atomic, it shouldn't cause any corruption.
|
||||||
if err := store.saveUserIdentity(ctx, cred.AccessKey, userType, newUserIdentity(cred)); err != nil {
|
if err := store.saveUserIdentity(ctx, cred.AccessKey, userType, ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cache.iamUsersMap[cred.AccessKey] = cred
|
cache.iamUsersMap[cred.AccessKey] = ui
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1969,9 +1983,9 @@ func (store *IAMStoreSys) LoadUser(ctx context.Context, accessKey string) {
|
|||||||
if svc, found := cache.iamUsersMap[accessKey]; found {
|
if svc, found := cache.iamUsersMap[accessKey]; found {
|
||||||
// Load parent user and mapped policies.
|
// Load parent user and mapped policies.
|
||||||
if store.getUsersSysType() == MinIOUsersSysType {
|
if store.getUsersSysType() == MinIOUsersSysType {
|
||||||
store.loadUser(ctx, svc.ParentUser, regUser, cache.iamUsersMap)
|
store.loadUser(ctx, svc.Credentials.ParentUser, regUser, cache.iamUsersMap)
|
||||||
}
|
}
|
||||||
store.loadMappedPolicy(ctx, svc.ParentUser, regUser, false, cache.iamUserPolicyMap)
|
store.loadMappedPolicy(ctx, svc.Credentials.ParentUser, regUser, false, cache.iamUserPolicyMap)
|
||||||
} else {
|
} else {
|
||||||
// check for STS account
|
// check for STS account
|
||||||
store.loadUser(ctx, accessKey, stsUser, cache.iamUsersMap)
|
store.loadUser(ctx, accessKey, stsUser, cache.iamUsersMap)
|
||||||
|
182
cmd/iam.go
182
cmd/iam.go
@ -599,14 +599,14 @@ func (sys *IAMSys) ListPolicyDocs(ctx context.Context, bucketName string) (map[s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetPolicy - sets a new named policy.
|
// SetPolicy - sets a new named policy.
|
||||||
func (sys *IAMSys) SetPolicy(ctx context.Context, policyName string, p iampolicy.Policy) error {
|
func (sys *IAMSys) SetPolicy(ctx context.Context, policyName string, p iampolicy.Policy) (time.Time, error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return time.Time{}, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.SetPolicy(ctx, policyName, p)
|
updatedAt, err := sys.store.SetPolicy(ctx, policyName, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sys.HasWatcher() {
|
if !sys.HasWatcher() {
|
||||||
@ -618,7 +618,7 @@ func (sys *IAMSys) SetPolicy(ctx context.Context, policyName string, p iampolicy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser - delete user (only for long-term users not STS users).
|
// DeleteUser - delete user (only for long-term users not STS users).
|
||||||
@ -707,9 +707,9 @@ func (sys *IAMSys) notifyForUser(ctx context.Context, accessKey string, isTemp b
|
|||||||
// elsewhere), the AssumeRole case (because the parent user is real and their
|
// elsewhere), the AssumeRole case (because the parent user is real and their
|
||||||
// policy is associated via policy-set API) and the AssumeRoleWithLDAP case
|
// policy is associated via policy-set API) and the AssumeRoleWithLDAP case
|
||||||
// (because the policy association is made via policy-set API).
|
// (because the policy association is made via policy-set API).
|
||||||
func (sys *IAMSys) SetTempUser(ctx context.Context, accessKey string, cred auth.Credentials, policyName string) error {
|
func (sys *IAMSys) SetTempUser(ctx context.Context, accessKey string, cred auth.Credentials, policyName string) (time.Time, error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return time.Time{}, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
if newGlobalAuthZPluginFn() != nil {
|
if newGlobalAuthZPluginFn() != nil {
|
||||||
@ -717,14 +717,14 @@ func (sys *IAMSys) SetTempUser(ctx context.Context, accessKey string, cred auth.
|
|||||||
policyName = ""
|
policyName = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.SetTempUser(ctx, accessKey, cred, policyName)
|
updatedAt, err := sys.store.SetTempUser(ctx, accessKey, cred, policyName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return time.Time{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForUser(ctx, cred.AccessKey, true)
|
sys.notifyForUser(ctx, cred.AccessKey, true)
|
||||||
|
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListBucketUsers - list all users who can access this 'bucket'
|
// ListBucketUsers - list all users who can access this 'bucket'
|
||||||
@ -782,11 +782,11 @@ func (sys *IAMSys) IsTempUser(name string) (bool, string, error) {
|
|||||||
return false, "", errServerNotInitialized
|
return false, "", errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, found := sys.store.GetUser(name)
|
u, found := sys.store.GetUser(name)
|
||||||
if !found {
|
if !found {
|
||||||
return false, "", errNoSuchUser
|
return false, "", errNoSuchUser
|
||||||
}
|
}
|
||||||
|
cred := u.Credentials
|
||||||
if cred.IsTemp() {
|
if cred.IsTemp() {
|
||||||
return true, cred.ParentUser, nil
|
return true, cred.ParentUser, nil
|
||||||
}
|
}
|
||||||
@ -800,11 +800,11 @@ func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) {
|
|||||||
return false, "", errServerNotInitialized
|
return false, "", errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, found := sys.store.GetUser(name)
|
u, found := sys.store.GetUser(name)
|
||||||
if !found {
|
if !found {
|
||||||
return false, "", errNoSuchUser
|
return false, "", errNoSuchUser
|
||||||
}
|
}
|
||||||
|
cred := u.Credentials
|
||||||
if cred.IsServiceAccount() {
|
if cred.IsServiceAccount() {
|
||||||
return true, cred.ParentUser, nil
|
return true, cred.ParentUser, nil
|
||||||
}
|
}
|
||||||
@ -828,22 +828,22 @@ func (sys *IAMSys) GetUserInfo(ctx context.Context, name string) (u madmin.UserI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetUserStatus - sets current user status, supports disabled or enabled.
|
// SetUserStatus - sets current user status, supports disabled or enabled.
|
||||||
func (sys *IAMSys) SetUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) error {
|
func (sys *IAMSys) SetUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) (updatedAt time.Time, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return updatedAt, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.usersSysType != MinIOUsersSysType {
|
if sys.usersSysType != MinIOUsersSysType {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.SetUserStatus(ctx, accessKey, status)
|
updatedAt, err = sys.store.SetUserStatus(ctx, accessKey, status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForUser(ctx, accessKey, false)
|
sys.notifyForUser(ctx, accessKey, false)
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *IAMSys) notifyForServiceAccount(ctx context.Context, accessKey string) {
|
func (sys *IAMSys) notifyForServiceAccount(ctx context.Context, accessKey string) {
|
||||||
@ -867,34 +867,34 @@ type newServiceAccountOpts struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewServiceAccount - create a new service account
|
// NewServiceAccount - create a new service account
|
||||||
func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, groups []string, opts newServiceAccountOpts) (auth.Credentials, error) {
|
func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, groups []string, opts newServiceAccountOpts) (auth.Credentials, time.Time, error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return auth.Credentials{}, errServerNotInitialized
|
return auth.Credentials{}, time.Time{}, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
if parentUser == "" {
|
if parentUser == "" {
|
||||||
return auth.Credentials{}, errInvalidArgument
|
return auth.Credentials{}, time.Time{}, errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
var policyBuf []byte
|
var policyBuf []byte
|
||||||
if opts.sessionPolicy != nil {
|
if opts.sessionPolicy != nil {
|
||||||
err := opts.sessionPolicy.Validate()
|
err := opts.sessionPolicy.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, err
|
return auth.Credentials{}, time.Time{}, err
|
||||||
}
|
}
|
||||||
policyBuf, err = json.Marshal(opts.sessionPolicy)
|
policyBuf, err = json.Marshal(opts.sessionPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, err
|
return auth.Credentials{}, time.Time{}, err
|
||||||
}
|
}
|
||||||
if len(policyBuf) > 16*humanize.KiByte {
|
if len(policyBuf) > 16*humanize.KiByte {
|
||||||
return auth.Credentials{}, fmt.Errorf("Session policy should not exceed 16 KiB characters")
|
return auth.Credentials{}, time.Time{}, fmt.Errorf("Session policy should not exceed 16 KiB characters")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// found newly requested service account, to be same as
|
// found newly requested service account, to be same as
|
||||||
// parentUser, reject such operations.
|
// parentUser, reject such operations.
|
||||||
if parentUser == opts.accessKey {
|
if parentUser == opts.accessKey {
|
||||||
return auth.Credentials{}, errIAMActionNotAllowed
|
return auth.Credentials{}, time.Time{}, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
m := make(map[string]interface{})
|
m := make(map[string]interface{})
|
||||||
@ -922,24 +922,24 @@ func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, gro
|
|||||||
} else {
|
} else {
|
||||||
accessKey, secretKey, err = auth.GenerateCredentials()
|
accessKey, secretKey, err = auth.GenerateCredentials()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, err
|
return auth.Credentials{}, time.Time{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cred, err := auth.CreateNewCredentialsWithMetadata(accessKey, secretKey, m, secretKey)
|
cred, err := auth.CreateNewCredentialsWithMetadata(accessKey, secretKey, m, secretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, err
|
return auth.Credentials{}, time.Time{}, err
|
||||||
}
|
}
|
||||||
cred.ParentUser = parentUser
|
cred.ParentUser = parentUser
|
||||||
cred.Groups = groups
|
cred.Groups = groups
|
||||||
cred.Status = string(auth.AccountOn)
|
cred.Status = string(auth.AccountOn)
|
||||||
|
|
||||||
err = sys.store.AddServiceAccount(ctx, cred)
|
updatedAt, err := sys.store.AddServiceAccount(ctx, cred)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, err
|
return auth.Credentials{}, time.Time{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForServiceAccount(ctx, cred.AccessKey)
|
sys.notifyForServiceAccount(ctx, cred.AccessKey)
|
||||||
return cred, nil
|
return cred, updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateServiceAccountOpts struct {
|
type updateServiceAccountOpts struct {
|
||||||
@ -949,18 +949,18 @@ type updateServiceAccountOpts struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateServiceAccount - edit a service account
|
// UpdateServiceAccount - edit a service account
|
||||||
func (sys *IAMSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) error {
|
func (sys *IAMSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) (updatedAt time.Time, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return updatedAt, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.UpdateServiceAccount(ctx, accessKey, opts)
|
updatedAt, err = sys.store.UpdateServiceAccount(ctx, accessKey, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForServiceAccount(ctx, accessKey)
|
sys.notifyForServiceAccount(ctx, accessKey)
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListServiceAccounts - lists all services accounts associated to a specific user
|
// ListServiceAccounts - lists all services accounts associated to a specific user
|
||||||
@ -978,7 +978,7 @@ func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListTempAccounts - lists all services accounts associated to a specific user
|
// ListTempAccounts - lists all services accounts associated to a specific user
|
||||||
func (sys *IAMSys) ListTempAccounts(ctx context.Context, accessKey string) ([]auth.Credentials, error) {
|
func (sys *IAMSys) ListTempAccounts(ctx context.Context, accessKey string) ([]UserIdentity, error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return nil, errServerNotInitialized
|
return nil, errServerNotInitialized
|
||||||
}
|
}
|
||||||
@ -995,32 +995,32 @@ func (sys *IAMSys) ListTempAccounts(ctx context.Context, accessKey string) ([]au
|
|||||||
func (sys *IAMSys) GetServiceAccount(ctx context.Context, accessKey string) (auth.Credentials, *iampolicy.Policy, error) {
|
func (sys *IAMSys) GetServiceAccount(ctx context.Context, accessKey string) (auth.Credentials, *iampolicy.Policy, error) {
|
||||||
sa, embeddedPolicy, err := sys.getServiceAccount(ctx, accessKey)
|
sa, embeddedPolicy, err := sys.getServiceAccount(ctx, accessKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sa, embeddedPolicy, err
|
return auth.Credentials{}, embeddedPolicy, err
|
||||||
}
|
}
|
||||||
// Hide secret & session keys
|
// Hide secret & session keys
|
||||||
sa.SecretKey = ""
|
sa.Credentials.SecretKey = ""
|
||||||
sa.SessionToken = ""
|
sa.Credentials.SessionToken = ""
|
||||||
return sa, embeddedPolicy, nil
|
return sa.Credentials, embeddedPolicy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getServiceAccount - gets information about a service account
|
// getServiceAccount - gets information about a service account
|
||||||
func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (auth.Credentials, *iampolicy.Policy, error) {
|
func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (u UserIdentity, p *iampolicy.Policy, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return auth.Credentials{}, nil, errServerNotInitialized
|
return u, nil, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
sa, ok := sys.store.GetUser(accessKey)
|
sa, ok := sys.store.GetUser(accessKey)
|
||||||
if !ok || !sa.IsServiceAccount() {
|
if !ok || !sa.Credentials.IsServiceAccount() {
|
||||||
return auth.Credentials{}, nil, errNoSuchServiceAccount
|
return u, nil, errNoSuchServiceAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
var embeddedPolicy *iampolicy.Policy
|
var embeddedPolicy *iampolicy.Policy
|
||||||
|
|
||||||
jwtClaims, err := auth.ExtractClaims(sa.SessionToken, sa.SecretKey)
|
jwtClaims, err := auth.ExtractClaims(sa.Credentials.SessionToken, sa.Credentials.SecretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jwtClaims, err = auth.ExtractClaims(sa.SessionToken, globalActiveCred.SecretKey)
|
jwtClaims, err = auth.ExtractClaims(sa.Credentials.SessionToken, globalActiveCred.SecretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, nil, err
|
return u, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pt, ptok := jwtClaims.Lookup(iamPolicyClaimNameSA())
|
pt, ptok := jwtClaims.Lookup(iamPolicyClaimNameSA())
|
||||||
@ -1028,11 +1028,11 @@ func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (aut
|
|||||||
if ptok && spok && pt == embeddedPolicyType {
|
if ptok && spok && pt == embeddedPolicyType {
|
||||||
policyBytes, err := base64.StdEncoding.DecodeString(sp)
|
policyBytes, err := base64.StdEncoding.DecodeString(sp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, nil, err
|
return u, nil, err
|
||||||
}
|
}
|
||||||
embeddedPolicy, err = iampolicy.ParseConfig(bytes.NewReader(policyBytes))
|
embeddedPolicy, err = iampolicy.ParseConfig(bytes.NewReader(policyBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return auth.Credentials{}, nil, err
|
return u, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1050,13 +1050,13 @@ func (sys *IAMSys) GetClaimsForSvcAcc(ctx context.Context, accessKey string) (ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
sa, ok := sys.store.GetUser(accessKey)
|
sa, ok := sys.store.GetUser(accessKey)
|
||||||
if !ok || !sa.IsServiceAccount() {
|
if !ok || !sa.Credentials.IsServiceAccount() {
|
||||||
return nil, errNoSuchServiceAccount
|
return nil, errNoSuchServiceAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
jwtClaims, err := auth.ExtractClaims(sa.SessionToken, sa.SecretKey)
|
jwtClaims, err := auth.ExtractClaims(sa.Credentials.SessionToken, sa.Credentials.SecretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jwtClaims, err = auth.ExtractClaims(sa.SessionToken, globalActiveCred.SecretKey)
|
jwtClaims, err = auth.ExtractClaims(sa.Credentials.SessionToken, globalActiveCred.SecretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1071,7 +1071,7 @@ func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string, n
|
|||||||
}
|
}
|
||||||
|
|
||||||
sa, ok := sys.store.GetUser(accessKey)
|
sa, ok := sys.store.GetUser(accessKey)
|
||||||
if !ok || !sa.IsServiceAccount() {
|
if !ok || !sa.Credentials.IsServiceAccount() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1093,30 +1093,30 @@ func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string, n
|
|||||||
|
|
||||||
// CreateUser - create new user credentials and policy, if user already exists
|
// CreateUser - create new user credentials and policy, if user already exists
|
||||||
// they shall be rewritten with new inputs.
|
// they shall be rewritten with new inputs.
|
||||||
func (sys *IAMSys) CreateUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) error {
|
func (sys *IAMSys) CreateUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) (updatedAt time.Time, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return updatedAt, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.usersSysType != MinIOUsersSysType {
|
if sys.usersSysType != MinIOUsersSysType {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
if !auth.IsAccessKeyValid(accessKey) {
|
if !auth.IsAccessKeyValid(accessKey) {
|
||||||
return auth.ErrInvalidAccessKeyLength
|
return updatedAt, auth.ErrInvalidAccessKeyLength
|
||||||
}
|
}
|
||||||
|
|
||||||
if !auth.IsSecretKeyValid(ureq.SecretKey) {
|
if !auth.IsSecretKeyValid(ureq.SecretKey) {
|
||||||
return auth.ErrInvalidSecretKeyLength
|
return updatedAt, auth.ErrInvalidSecretKeyLength
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.AddUser(ctx, accessKey, ureq)
|
updatedAt, err = sys.store.AddUser(ctx, accessKey, ureq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForUser(ctx, accessKey, false)
|
sys.notifyForUser(ctx, accessKey, false)
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUserSecretKey - sets user secret key
|
// SetUserSecretKey - sets user secret key
|
||||||
@ -1291,9 +1291,9 @@ func (sys *IAMSys) updateGroupMembershipsForLDAP(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetUser - get user credentials
|
// GetUser - get user credentials
|
||||||
func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (cred auth.Credentials, ok bool) {
|
func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (u UserIdentity, ok bool) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return cred, false
|
return u, false
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback := false
|
fallback := false
|
||||||
@ -1304,7 +1304,7 @@ func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (cred auth.Cre
|
|||||||
fallback = true
|
fallback = true
|
||||||
}
|
}
|
||||||
|
|
||||||
cred, ok = sys.store.GetUser(accessKey)
|
u, ok = sys.store.GetUser(accessKey)
|
||||||
if !ok && !fallback {
|
if !ok && !fallback {
|
||||||
// accessKey not found, also
|
// accessKey not found, also
|
||||||
// IAM store is not in fallback mode
|
// IAM store is not in fallback mode
|
||||||
@ -1313,10 +1313,10 @@ func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (cred auth.Cre
|
|||||||
// exists now. If it doesn't proceed to
|
// exists now. If it doesn't proceed to
|
||||||
// fail.
|
// fail.
|
||||||
sys.store.LoadUser(ctx, accessKey)
|
sys.store.LoadUser(ctx, accessKey)
|
||||||
cred, ok = sys.store.GetUser(accessKey)
|
u, ok = sys.store.GetUser(accessKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cred, ok && cred.IsValid()
|
return u, ok && u.Credentials.IsValid()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify all other MinIO peers to load group.
|
// Notify all other MinIO peers to load group.
|
||||||
@ -1333,61 +1333,61 @@ func (sys *IAMSys) notifyForGroup(ctx context.Context, group string) {
|
|||||||
|
|
||||||
// AddUsersToGroup - adds users to a group, creating the group if
|
// AddUsersToGroup - adds users to a group, creating the group if
|
||||||
// needed. No error if user(s) already are in the group.
|
// needed. No error if user(s) already are in the group.
|
||||||
func (sys *IAMSys) AddUsersToGroup(ctx context.Context, group string, members []string) error {
|
func (sys *IAMSys) AddUsersToGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return updatedAt, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.usersSysType != MinIOUsersSysType {
|
if sys.usersSysType != MinIOUsersSysType {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.AddUsersToGroup(ctx, group, members)
|
updatedAt, err = sys.store.AddUsersToGroup(ctx, group, members)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForGroup(ctx, group)
|
sys.notifyForGroup(ctx, group)
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveUsersFromGroup - remove users from group. If no users are
|
// RemoveUsersFromGroup - remove users from group. If no users are
|
||||||
// given, and the group is empty, deletes the group as well.
|
// given, and the group is empty, deletes the group as well.
|
||||||
func (sys *IAMSys) RemoveUsersFromGroup(ctx context.Context, group string, members []string) error {
|
func (sys *IAMSys) RemoveUsersFromGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return updatedAt, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.usersSysType != MinIOUsersSysType {
|
if sys.usersSysType != MinIOUsersSysType {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.RemoveUsersFromGroup(ctx, group, members)
|
updatedAt, err = sys.store.RemoveUsersFromGroup(ctx, group, members)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForGroup(ctx, group)
|
sys.notifyForGroup(ctx, group)
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroupStatus - enable/disabled a group
|
// SetGroupStatus - enable/disabled a group
|
||||||
func (sys *IAMSys) SetGroupStatus(ctx context.Context, group string, enabled bool) error {
|
func (sys *IAMSys) SetGroupStatus(ctx context.Context, group string, enabled bool) (updatedAt time.Time, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return updatedAt, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.usersSysType != MinIOUsersSysType {
|
if sys.usersSysType != MinIOUsersSysType {
|
||||||
return errIAMActionNotAllowed
|
return updatedAt, errIAMActionNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.SetGroupStatus(ctx, group, enabled)
|
updatedAt, err = sys.store.SetGroupStatus(ctx, group, enabled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return updatedAt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.notifyForGroup(ctx, group)
|
sys.notifyForGroup(ctx, group)
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroupDescription - builds up group description
|
// GetGroupDescription - builds up group description
|
||||||
@ -1414,9 +1414,9 @@ func (sys *IAMSys) ListGroups(ctx context.Context) (r []string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PolicyDBSet - sets a policy for a user or group in the PolicyDB.
|
// PolicyDBSet - sets a policy for a user or group in the PolicyDB.
|
||||||
func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup bool) error {
|
func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup bool) (updatedAt time.Time, err error) {
|
||||||
if !sys.Initialized() {
|
if !sys.Initialized() {
|
||||||
return errServerNotInitialized
|
return updatedAt, errServerNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine user-type based on IDP mode.
|
// Determine user-type based on IDP mode.
|
||||||
@ -1425,9 +1425,9 @@ func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup
|
|||||||
userType = stsUser
|
userType = stsUser
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sys.store.PolicyDBSet(ctx, name, policy, userType, isGroup)
|
updatedAt, err = sys.store.PolicyDBSet(ctx, name, policy, userType, isGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify all other MinIO peers to reload policy
|
// Notify all other MinIO peers to reload policy
|
||||||
@ -1440,7 +1440,7 @@ func (sys *IAMSys) PolicyDBSet(ctx context.Context, name, policy string, isGroup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return updatedAt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PolicyDBGet - gets policy set on a user or group. If a list of groups is
|
// PolicyDBGet - gets policy set on a user or group. If a list of groups is
|
||||||
|
11
cmd/jwt.go
11
cmd/jwt.go
@ -63,11 +63,11 @@ func authenticateJWTUsers(accessKey, secretKey string, expiry time.Duration) (st
|
|||||||
func authenticateJWTUsersWithCredentials(credentials auth.Credentials, expiresAt time.Time) (string, error) {
|
func authenticateJWTUsersWithCredentials(credentials auth.Credentials, expiresAt time.Time) (string, error) {
|
||||||
serverCred := globalActiveCred
|
serverCred := globalActiveCred
|
||||||
if serverCred.AccessKey != credentials.AccessKey {
|
if serverCred.AccessKey != credentials.AccessKey {
|
||||||
var ok bool
|
u, ok := globalIAMSys.GetUser(context.TODO(), credentials.AccessKey)
|
||||||
serverCred, ok = globalIAMSys.GetUser(context.TODO(), credentials.AccessKey)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", errInvalidAccessKeyID
|
return "", errInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
|
serverCred = u.Credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
if !serverCred.Equal(credentials) {
|
if !serverCred.Equal(credentials) {
|
||||||
@ -145,10 +145,11 @@ func metricsRequestAuthenticate(req *http.Request) (*xjwt.MapClaims, []string, b
|
|||||||
if claims.AccessKey == globalActiveCred.AccessKey {
|
if claims.AccessKey == globalActiveCred.AccessKey {
|
||||||
return []byte(globalActiveCred.SecretKey), nil
|
return []byte(globalActiveCred.SecretKey), nil
|
||||||
}
|
}
|
||||||
cred, ok := globalIAMSys.GetUser(req.Context(), claims.AccessKey)
|
u, ok := globalIAMSys.GetUser(req.Context(), claims.AccessKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errInvalidAccessKeyID
|
return nil, errInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
|
cred := u.Credentials
|
||||||
return []byte(cred.SecretKey), nil
|
return []byte(cred.SecretKey), nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return claims, nil, false, errAuthentication
|
return claims, nil, false, errAuthentication
|
||||||
@ -157,11 +158,11 @@ func metricsRequestAuthenticate(req *http.Request) (*xjwt.MapClaims, []string, b
|
|||||||
var groups []string
|
var groups []string
|
||||||
if globalActiveCred.AccessKey != claims.AccessKey {
|
if globalActiveCred.AccessKey != claims.AccessKey {
|
||||||
// Check if the access key is part of users credentials.
|
// Check if the access key is part of users credentials.
|
||||||
ucred, ok := globalIAMSys.GetUser(req.Context(), claims.AccessKey)
|
u, ok := globalIAMSys.GetUser(req.Context(), claims.AccessKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, false, errInvalidAccessKeyID
|
return nil, nil, false, errInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
|
ucred := u.Credentials
|
||||||
// get embedded claims
|
// get embedded claims
|
||||||
eclaims, s3Err := checkClaimsFromToken(req, ucred)
|
eclaims, s3Err := checkClaimsFromToken(req, ucred)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
|
@ -152,16 +152,16 @@ func checkKeyValid(r *http.Request, accessKey string) (auth.Credentials, bool, A
|
|||||||
cred := globalActiveCred
|
cred := globalActiveCred
|
||||||
if cred.AccessKey != accessKey {
|
if cred.AccessKey != accessKey {
|
||||||
// Check if the access key is part of users credentials.
|
// Check if the access key is part of users credentials.
|
||||||
ucred, ok := globalIAMSys.GetUser(r.Context(), accessKey)
|
u, ok := globalIAMSys.GetUser(r.Context(), accessKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
// Credentials will be invalid but and disabled
|
// Credentials will be invalid but and disabled
|
||||||
// return a different error in such a scenario.
|
// return a different error in such a scenario.
|
||||||
if ucred.Status == auth.AccountOff {
|
if u.Credentials.Status == auth.AccountOff {
|
||||||
return cred, false, ErrAccessKeyDisabled
|
return cred, false, ErrAccessKeyDisabled
|
||||||
}
|
}
|
||||||
return cred, false, ErrInvalidAccessKeyID
|
return cred, false, ErrInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
cred = ucred
|
cred = u.Credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := checkClaimsFromToken(r, cred)
|
claims, s3Err := checkClaimsFromToken(r, cred)
|
||||||
|
@ -403,14 +403,15 @@ func (c *SiteReplicationSys) AddPeerClusters(ctx context.Context, psites []madmi
|
|||||||
|
|
||||||
// Generate a secret key for the service account if not created already.
|
// Generate a secret key for the service account if not created already.
|
||||||
var secretKey string
|
var secretKey string
|
||||||
svcCred, _, err := globalIAMSys.getServiceAccount(ctx, siteReplicatorSvcAcc)
|
var svcCred auth.Credentials
|
||||||
|
sa, _, err := globalIAMSys.getServiceAccount(ctx, siteReplicatorSvcAcc)
|
||||||
switch {
|
switch {
|
||||||
case err == errNoSuchServiceAccount:
|
case err == errNoSuchServiceAccount:
|
||||||
_, secretKey, err = auth.GenerateCredentials()
|
_, secretKey, err = auth.GenerateCredentials()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return madmin.ReplicateAddStatus{}, errSRServiceAccount(fmt.Errorf("unable to create local service account: %w", err))
|
return madmin.ReplicateAddStatus{}, errSRServiceAccount(fmt.Errorf("unable to create local service account: %w", err))
|
||||||
}
|
}
|
||||||
svcCred, err = globalIAMSys.NewServiceAccount(ctx, sites[selfIdx].AccessKey, nil, newServiceAccountOpts{
|
svcCred, _, err = globalIAMSys.NewServiceAccount(ctx, sites[selfIdx].AccessKey, nil, newServiceAccountOpts{
|
||||||
accessKey: siteReplicatorSvcAcc,
|
accessKey: siteReplicatorSvcAcc,
|
||||||
secretKey: secretKey,
|
secretKey: secretKey,
|
||||||
})
|
})
|
||||||
@ -418,6 +419,7 @@ func (c *SiteReplicationSys) AddPeerClusters(ctx context.Context, psites []madmi
|
|||||||
return madmin.ReplicateAddStatus{}, errSRServiceAccount(fmt.Errorf("unable to create local service account: %w", err))
|
return madmin.ReplicateAddStatus{}, errSRServiceAccount(fmt.Errorf("unable to create local service account: %w", err))
|
||||||
}
|
}
|
||||||
case err == nil:
|
case err == nil:
|
||||||
|
svcCred = sa.Credentials
|
||||||
secretKey = svcCred.SecretKey
|
secretKey = svcCred.SecretKey
|
||||||
default:
|
default:
|
||||||
return madmin.ReplicateAddStatus{}, errSRBackendIssue(err)
|
return madmin.ReplicateAddStatus{}, errSRBackendIssue(err)
|
||||||
@ -525,7 +527,7 @@ func (c *SiteReplicationSys) PeerJoinReq(ctx context.Context, arg madmin.SRPeerJ
|
|||||||
|
|
||||||
_, _, err := globalIAMSys.GetServiceAccount(ctx, arg.SvcAcctAccessKey)
|
_, _, err := globalIAMSys.GetServiceAccount(ctx, arg.SvcAcctAccessKey)
|
||||||
if err == errNoSuchServiceAccount {
|
if err == errNoSuchServiceAccount {
|
||||||
_, err = globalIAMSys.NewServiceAccount(ctx, arg.SvcAcctParent, nil, newServiceAccountOpts{
|
_, _, err = globalIAMSys.NewServiceAccount(ctx, arg.SvcAcctParent, nil, newServiceAccountOpts{
|
||||||
accessKey: arg.SvcAcctAccessKey,
|
accessKey: arg.SvcAcctAccessKey,
|
||||||
secretKey: arg.SvcAcctSecretKey,
|
secretKey: arg.SvcAcctSecretKey,
|
||||||
})
|
})
|
||||||
@ -1022,12 +1024,18 @@ func (c *SiteReplicationSys) IAMChangeHook(ctx context.Context, item madmin.SRIA
|
|||||||
|
|
||||||
// PeerAddPolicyHandler - copies IAM policy to local. A nil policy argument,
|
// PeerAddPolicyHandler - copies IAM policy to local. A nil policy argument,
|
||||||
// causes the named policy to be deleted.
|
// causes the named policy to be deleted.
|
||||||
func (c *SiteReplicationSys) PeerAddPolicyHandler(ctx context.Context, policyName string, p *iampolicy.Policy) error {
|
func (c *SiteReplicationSys) PeerAddPolicyHandler(ctx context.Context, policyName string, p *iampolicy.Policy, updatedAt time.Time) error {
|
||||||
var err error
|
var err error
|
||||||
|
// skip overwrite of local update if peer sent stale info
|
||||||
|
if !updatedAt.IsZero() {
|
||||||
|
if p, err := globalIAMSys.store.GetPolicyDoc(policyName); err == nil && p.UpdateDate.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
if p == nil {
|
if p == nil {
|
||||||
err = globalIAMSys.DeletePolicy(ctx, policyName, true)
|
err = globalIAMSys.DeletePolicy(ctx, policyName, true)
|
||||||
} else {
|
} else {
|
||||||
err = globalIAMSys.SetPolicy(ctx, policyName, *p)
|
_, err = globalIAMSys.SetPolicy(ctx, policyName, *p)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
@ -1036,10 +1044,17 @@ func (c *SiteReplicationSys) PeerAddPolicyHandler(ctx context.Context, policyNam
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerIAMUserChangeHandler - copies IAM user to local.
|
// PeerIAMUserChangeHandler - copies IAM user to local.
|
||||||
func (c *SiteReplicationSys) PeerIAMUserChangeHandler(ctx context.Context, change *madmin.SRIAMUser) error {
|
func (c *SiteReplicationSys) PeerIAMUserChangeHandler(ctx context.Context, change *madmin.SRIAMUser, updatedAt time.Time) error {
|
||||||
if change == nil {
|
if change == nil {
|
||||||
return errSRInvalidRequest(errInvalidArgument)
|
return errSRInvalidRequest(errInvalidArgument)
|
||||||
}
|
}
|
||||||
|
// skip overwrite of local update if peer sent stale info
|
||||||
|
if !updatedAt.IsZero() {
|
||||||
|
if ui, err := globalIAMSys.GetUserInfo(ctx, change.AccessKey); err == nil && ui.UpdatedAt.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if change.IsDeleteReq {
|
if change.IsDeleteReq {
|
||||||
err = globalIAMSys.DeleteUser(ctx, change.AccessKey, true)
|
err = globalIAMSys.DeleteUser(ctx, change.AccessKey, true)
|
||||||
@ -1051,9 +1066,9 @@ func (c *SiteReplicationSys) PeerIAMUserChangeHandler(ctx context.Context, chang
|
|||||||
if userReq.Status != "" && userReq.SecretKey == "" {
|
if userReq.Status != "" && userReq.SecretKey == "" {
|
||||||
// Status is set without secretKey updates means we are
|
// Status is set without secretKey updates means we are
|
||||||
// only changing the account status.
|
// only changing the account status.
|
||||||
err = globalIAMSys.SetUserStatus(ctx, change.AccessKey, userReq.Status)
|
_, err = globalIAMSys.SetUserStatus(ctx, change.AccessKey, userReq.Status)
|
||||||
} else {
|
} else {
|
||||||
err = globalIAMSys.CreateUser(ctx, change.AccessKey, userReq)
|
_, err = globalIAMSys.CreateUser(ctx, change.AccessKey, userReq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1063,19 +1078,27 @@ func (c *SiteReplicationSys) PeerIAMUserChangeHandler(ctx context.Context, chang
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerGroupInfoChangeHandler - copies group changes to local.
|
// PeerGroupInfoChangeHandler - copies group changes to local.
|
||||||
func (c *SiteReplicationSys) PeerGroupInfoChangeHandler(ctx context.Context, change *madmin.SRGroupInfo) error {
|
func (c *SiteReplicationSys) PeerGroupInfoChangeHandler(ctx context.Context, change *madmin.SRGroupInfo, updatedAt time.Time) error {
|
||||||
if change == nil {
|
if change == nil {
|
||||||
return errSRInvalidRequest(errInvalidArgument)
|
return errSRInvalidRequest(errInvalidArgument)
|
||||||
}
|
}
|
||||||
updReq := change.UpdateReq
|
updReq := change.UpdateReq
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
// skip overwrite of local update if peer sent stale info
|
||||||
|
if !updatedAt.IsZero() {
|
||||||
|
if gd, err := globalIAMSys.GetGroupDescription(updReq.Group); err == nil && gd.UpdatedAt.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if updReq.IsRemove {
|
if updReq.IsRemove {
|
||||||
err = globalIAMSys.RemoveUsersFromGroup(ctx, updReq.Group, updReq.Members)
|
_, err = globalIAMSys.RemoveUsersFromGroup(ctx, updReq.Group, updReq.Members)
|
||||||
} else {
|
} else {
|
||||||
if updReq.Status != "" && len(updReq.Members) == 0 {
|
if updReq.Status != "" && len(updReq.Members) == 0 {
|
||||||
err = globalIAMSys.SetGroupStatus(ctx, updReq.Group, updReq.Status == madmin.GroupEnabled)
|
_, err = globalIAMSys.SetGroupStatus(ctx, updReq.Group, updReq.Status == madmin.GroupEnabled)
|
||||||
} else {
|
} else {
|
||||||
err = globalIAMSys.AddUsersToGroup(ctx, updReq.Group, updReq.Members)
|
_, err = globalIAMSys.AddUsersToGroup(ctx, updReq.Group, updReq.Members)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1085,7 +1108,7 @@ func (c *SiteReplicationSys) PeerGroupInfoChangeHandler(ctx context.Context, cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerSvcAccChangeHandler - copies service-account change to local.
|
// PeerSvcAccChangeHandler - copies service-account change to local.
|
||||||
func (c *SiteReplicationSys) PeerSvcAccChangeHandler(ctx context.Context, change *madmin.SRSvcAccChange) error {
|
func (c *SiteReplicationSys) PeerSvcAccChangeHandler(ctx context.Context, change *madmin.SRSvcAccChange, updatedAt time.Time) error {
|
||||||
if change == nil {
|
if change == nil {
|
||||||
return errSRInvalidRequest(errInvalidArgument)
|
return errSRInvalidRequest(errInvalidArgument)
|
||||||
}
|
}
|
||||||
@ -1099,14 +1122,19 @@ func (c *SiteReplicationSys) PeerSvcAccChangeHandler(ctx context.Context, change
|
|||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// skip overwrite of local update if peer sent stale info
|
||||||
|
if !updatedAt.IsZero() && change.Create.AccessKey != "" {
|
||||||
|
if sa, _, err := globalIAMSys.getServiceAccount(ctx, change.Create.AccessKey); err == nil && sa.UpdatedAt.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
opts := newServiceAccountOpts{
|
opts := newServiceAccountOpts{
|
||||||
accessKey: change.Create.AccessKey,
|
accessKey: change.Create.AccessKey,
|
||||||
secretKey: change.Create.SecretKey,
|
secretKey: change.Create.SecretKey,
|
||||||
sessionPolicy: sp,
|
sessionPolicy: sp,
|
||||||
claims: change.Create.Claims,
|
claims: change.Create.Claims,
|
||||||
}
|
}
|
||||||
_, err = globalIAMSys.NewServiceAccount(ctx, change.Create.Parent, change.Create.Groups, opts)
|
_, _, err = globalIAMSys.NewServiceAccount(ctx, change.Create.Parent, change.Create.Groups, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
}
|
}
|
||||||
@ -1120,20 +1148,31 @@ func (c *SiteReplicationSys) PeerSvcAccChangeHandler(ctx context.Context, change
|
|||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// skip overwrite of local update if peer sent stale info
|
||||||
|
if !updatedAt.IsZero() {
|
||||||
|
if sa, _, err := globalIAMSys.getServiceAccount(ctx, change.Update.AccessKey); err == nil && sa.UpdatedAt.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
opts := updateServiceAccountOpts{
|
opts := updateServiceAccountOpts{
|
||||||
secretKey: change.Update.SecretKey,
|
secretKey: change.Update.SecretKey,
|
||||||
status: change.Update.Status,
|
status: change.Update.Status,
|
||||||
sessionPolicy: sp,
|
sessionPolicy: sp,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = globalIAMSys.UpdateServiceAccount(ctx, change.Update.AccessKey, opts)
|
_, err = globalIAMSys.UpdateServiceAccount(ctx, change.Update.AccessKey, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
case change.Delete != nil:
|
case change.Delete != nil:
|
||||||
err := globalIAMSys.DeleteServiceAccount(ctx, change.Delete.AccessKey, true)
|
// skip overwrite of local update if peer sent stale info
|
||||||
if err != nil {
|
if !updatedAt.IsZero() {
|
||||||
|
if sa, _, err := globalIAMSys.getServiceAccount(ctx, change.Delete.AccessKey); err == nil && sa.UpdatedAt.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := globalIAMSys.DeleteServiceAccount(ctx, change.Delete.AccessKey, true); err != nil {
|
||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1143,11 +1182,19 @@ func (c *SiteReplicationSys) PeerSvcAccChangeHandler(ctx context.Context, change
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerPolicyMappingHandler - copies policy mapping to local.
|
// PeerPolicyMappingHandler - copies policy mapping to local.
|
||||||
func (c *SiteReplicationSys) PeerPolicyMappingHandler(ctx context.Context, mapping *madmin.SRPolicyMapping) error {
|
func (c *SiteReplicationSys) PeerPolicyMappingHandler(ctx context.Context, mapping *madmin.SRPolicyMapping, updatedAt time.Time) error {
|
||||||
if mapping == nil {
|
if mapping == nil {
|
||||||
return errSRInvalidRequest(errInvalidArgument)
|
return errSRInvalidRequest(errInvalidArgument)
|
||||||
}
|
}
|
||||||
err := globalIAMSys.PolicyDBSet(ctx, mapping.UserOrGroup, mapping.Policy, mapping.IsGroup)
|
// skip overwrite of local update if peer sent stale info
|
||||||
|
if !updatedAt.IsZero() {
|
||||||
|
mp, ok := globalIAMSys.store.GetMappedPolicy(mapping.Policy, mapping.IsGroup)
|
||||||
|
if ok && mp.UpdatedAt.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := globalIAMSys.PolicyDBSet(ctx, mapping.UserOrGroup, mapping.Policy, mapping.IsGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
}
|
}
|
||||||
@ -1155,10 +1202,19 @@ func (c *SiteReplicationSys) PeerPolicyMappingHandler(ctx context.Context, mappi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerSTSAccHandler - replicates STS credential locally.
|
// PeerSTSAccHandler - replicates STS credential locally.
|
||||||
func (c *SiteReplicationSys) PeerSTSAccHandler(ctx context.Context, stsCred *madmin.SRSTSCredential) error {
|
func (c *SiteReplicationSys) PeerSTSAccHandler(ctx context.Context, stsCred *madmin.SRSTSCredential, updatedAt time.Time) error {
|
||||||
if stsCred == nil {
|
if stsCred == nil {
|
||||||
return errSRInvalidRequest(errInvalidArgument)
|
return errSRInvalidRequest(errInvalidArgument)
|
||||||
}
|
}
|
||||||
|
// skip overwrite of local update if peer sent stale info
|
||||||
|
if !updatedAt.IsZero() {
|
||||||
|
if u, err := globalIAMSys.GetUserInfo(ctx, stsCred.AccessKey); err == nil {
|
||||||
|
ok, _, _ := globalIAMSys.IsTempUser(stsCred.AccessKey)
|
||||||
|
if ok && u.UpdatedAt.After(updatedAt) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify the session token of the stsCred
|
// Verify the session token of the stsCred
|
||||||
claims, err := auth.ExtractClaims(stsCred.SessionToken, globalActiveCred.SecretKey)
|
claims, err := auth.ExtractClaims(stsCred.SessionToken, globalActiveCred.SecretKey)
|
||||||
@ -1195,7 +1251,7 @@ func (c *SiteReplicationSys) PeerSTSAccHandler(ctx context.Context, stsCred *mad
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set these credentials to IAM.
|
// Set these credentials to IAM.
|
||||||
if err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, stsCred.ParentPolicyMapping); err != nil {
|
if _, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, stsCred.ParentPolicyMapping); err != nil {
|
||||||
return fmt.Errorf("unable to save STS credential and/or parent policy mapping: %w", err)
|
return fmt.Errorf("unable to save STS credential and/or parent policy mapping: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1426,11 +1482,11 @@ func (c *SiteReplicationSys) getAdminClientWithEndpoint(ctx context.Context, dep
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *SiteReplicationSys) getPeerCreds() (*auth.Credentials, error) {
|
func (c *SiteReplicationSys) getPeerCreds() (*auth.Credentials, error) {
|
||||||
creds, ok := globalIAMSys.store.GetUser(c.state.ServiceAccountAccessKey)
|
u, ok := globalIAMSys.store.GetUser(c.state.ServiceAccountAccessKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("site replication service account not found")
|
return nil, errors.New("site replication service account not found")
|
||||||
}
|
}
|
||||||
return &creds, nil
|
return &u.Credentials, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// listBuckets returns a consistent common view of latest unique buckets across
|
// listBuckets returns a consistent common view of latest unique buckets across
|
||||||
@ -1606,13 +1662,13 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
// Policies should be synced first.
|
// Policies should be synced first.
|
||||||
{
|
{
|
||||||
// Replicate IAM policies on local to all peers.
|
// Replicate IAM policies on local to all peers.
|
||||||
allPolicies, err := globalIAMSys.ListPolicies(ctx, "")
|
allPolicyDocs, err := globalIAMSys.ListPolicyDocs(ctx, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRBackendIssue(err)
|
return errSRBackendIssue(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for pname, policy := range allPolicies {
|
for pname, pdoc := range allPolicyDocs {
|
||||||
policyJSON, err := json.Marshal(policy)
|
policyJSON, err := json.Marshal(pdoc.Policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapSRErr(err)
|
return wrapSRErr(err)
|
||||||
}
|
}
|
||||||
@ -1620,6 +1676,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
Type: madmin.SRIAMItemPolicy,
|
Type: madmin.SRIAMItemPolicy,
|
||||||
Name: pname,
|
Name: pname,
|
||||||
Policy: policyJSON,
|
Policy: policyJSON,
|
||||||
|
UpdatedAt: pdoc.UpdateDate,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
@ -1630,7 +1687,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
// Next should be userAccounts those are local users, OIDC and LDAP will not
|
// Next should be userAccounts those are local users, OIDC and LDAP will not
|
||||||
// may not have any local users.
|
// may not have any local users.
|
||||||
{
|
{
|
||||||
userAccounts := make(map[string]auth.Credentials)
|
userAccounts := make(map[string]UserIdentity)
|
||||||
globalIAMSys.store.rlock()
|
globalIAMSys.store.rlock()
|
||||||
err := globalIAMSys.store.loadUsers(ctx, regUser, userAccounts)
|
err := globalIAMSys.store.loadUsers(ctx, regUser, userAccounts)
|
||||||
globalIAMSys.store.runlock()
|
globalIAMSys.store.runlock()
|
||||||
@ -1642,13 +1699,14 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
if err := c.IAMChangeHook(ctx, madmin.SRIAMItem{
|
if err := c.IAMChangeHook(ctx, madmin.SRIAMItem{
|
||||||
Type: madmin.SRIAMItemIAMUser,
|
Type: madmin.SRIAMItemIAMUser,
|
||||||
IAMUser: &madmin.SRIAMUser{
|
IAMUser: &madmin.SRIAMUser{
|
||||||
AccessKey: acc.AccessKey,
|
AccessKey: acc.Credentials.AccessKey,
|
||||||
IsDeleteReq: false,
|
IsDeleteReq: false,
|
||||||
UserReq: &madmin.AddOrUpdateUserReq{
|
UserReq: &madmin.AddOrUpdateUserReq{
|
||||||
SecretKey: acc.SecretKey,
|
SecretKey: acc.Credentials.SecretKey,
|
||||||
Status: madmin.AccountStatus(acc.Status),
|
Status: madmin.AccountStatus(acc.Credentials.Status),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: acc.UpdatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
}
|
}
|
||||||
@ -1678,6 +1736,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
IsRemove: false,
|
IsRemove: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: group.UpdatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
}
|
}
|
||||||
@ -1687,7 +1746,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
// Service accounts are the static accounts that should be synced with
|
// Service accounts are the static accounts that should be synced with
|
||||||
// valid claims.
|
// valid claims.
|
||||||
{
|
{
|
||||||
serviceAccounts := make(map[string]auth.Credentials)
|
serviceAccounts := make(map[string]UserIdentity)
|
||||||
globalIAMSys.store.rlock()
|
globalIAMSys.store.rlock()
|
||||||
err := globalIAMSys.store.loadUsers(ctx, svcUser, serviceAccounts)
|
err := globalIAMSys.store.loadUsers(ctx, svcUser, serviceAccounts)
|
||||||
globalIAMSys.store.runlock()
|
globalIAMSys.store.runlock()
|
||||||
@ -1702,12 +1761,12 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, err := globalIAMSys.GetClaimsForSvcAcc(ctx, acc.AccessKey)
|
claims, err := globalIAMSys.GetClaimsForSvcAcc(ctx, acc.Credentials.AccessKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRBackendIssue(err)
|
return errSRBackendIssue(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, policy, err := globalIAMSys.GetServiceAccount(ctx, acc.AccessKey)
|
_, policy, err := globalIAMSys.GetServiceAccount(ctx, acc.Credentials.AccessKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRBackendIssue(err)
|
return errSRBackendIssue(err)
|
||||||
}
|
}
|
||||||
@ -1724,15 +1783,16 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
Type: madmin.SRIAMItemSvcAcc,
|
Type: madmin.SRIAMItemSvcAcc,
|
||||||
SvcAccChange: &madmin.SRSvcAccChange{
|
SvcAccChange: &madmin.SRSvcAccChange{
|
||||||
Create: &madmin.SRSvcAccCreate{
|
Create: &madmin.SRSvcAccCreate{
|
||||||
Parent: acc.ParentUser,
|
Parent: acc.Credentials.ParentUser,
|
||||||
AccessKey: user,
|
AccessKey: user,
|
||||||
SecretKey: acc.SecretKey,
|
SecretKey: acc.Credentials.SecretKey,
|
||||||
Groups: acc.Groups,
|
Groups: acc.Credentials.Groups,
|
||||||
Claims: claims,
|
Claims: claims,
|
||||||
SessionPolicy: json.RawMessage(policyJSON),
|
SessionPolicy: json.RawMessage(policyJSON),
|
||||||
Status: acc.Status,
|
Status: acc.Credentials.Status,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: acc.UpdatedAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
@ -1761,6 +1821,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
IsGroup: false,
|
IsGroup: false,
|
||||||
Policy: mp.Policies,
|
Policy: mp.Policies,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: mp.UpdatedAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
@ -1779,6 +1840,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
IsGroup: true,
|
IsGroup: true,
|
||||||
Policy: mp.Policies,
|
Policy: mp.Policies,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: mp.UpdatedAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
@ -1807,6 +1869,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
IsGroup: false,
|
IsGroup: false,
|
||||||
Policy: mp.Policies,
|
Policy: mp.Policies,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: mp.UpdatedAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
@ -1825,6 +1888,7 @@ func (c *SiteReplicationSys) syncToAllPeers(ctx context.Context) error {
|
|||||||
IsGroup: true,
|
IsGroup: true,
|
||||||
Policy: mp.Policies,
|
Policy: mp.Policies,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: mp.UpdatedAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSRIAMError(err)
|
return errSRIAMError(err)
|
||||||
@ -3244,8 +3308,8 @@ func (c *SiteReplicationSys) SiteReplicationMetaInfo(ctx context.Context, objAPI
|
|||||||
return info, errSRBackendIssue(err)
|
return info, errSRBackendIssue(err)
|
||||||
}
|
}
|
||||||
for _, tempAcct := range tempAccts {
|
for _, tempAcct := range tempAccts {
|
||||||
info.UserInfoMap[tempAcct.AccessKey] = madmin.UserInfo{
|
info.UserInfoMap[tempAcct.Credentials.AccessKey] = madmin.UserInfo{
|
||||||
Status: madmin.AccountStatus(tempAcct.Status),
|
Status: madmin.AccountStatus(tempAcct.Credentials.Status),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4166,6 +4230,7 @@ func (c *SiteReplicationSys) healPolicies(ctx context.Context, objAPI ObjectLaye
|
|||||||
Type: madmin.SRIAMItemPolicy,
|
Type: madmin.SRIAMItemPolicy,
|
||||||
Name: policy,
|
Name: policy,
|
||||||
Policy: latestPolicyStat.policy.Policy,
|
Policy: latestPolicyStat.policy.Policy,
|
||||||
|
UpdatedAt: lastUpdate,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(ctx, fmt.Errorf("Error healing IAM policy %s from peer site %s -> site %s : %w", policy, latestPeerName, peerName, err))
|
logger.LogIf(ctx, fmt.Errorf("Error healing IAM policy %s from peer site %s -> site %s : %w", policy, latestPeerName, peerName, err))
|
||||||
@ -4225,6 +4290,7 @@ func (c *SiteReplicationSys) healUserPolicies(ctx context.Context, objAPI Object
|
|||||||
IsGroup: false,
|
IsGroup: false,
|
||||||
Policy: latestUserStat.userPolicy.Policy,
|
Policy: latestUserStat.userPolicy.Policy,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: lastUpdate,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(ctx, fmt.Errorf("Error healing IAM user policy mapping for %s from peer site %s -> site %s : %w", user, latestPeerName, peerName, err))
|
logger.LogIf(ctx, fmt.Errorf("Error healing IAM user policy mapping for %s from peer site %s -> site %s : %w", user, latestPeerName, peerName, err))
|
||||||
@ -4286,6 +4352,7 @@ func (c *SiteReplicationSys) healGroupPolicies(ctx context.Context, objAPI Objec
|
|||||||
IsGroup: true,
|
IsGroup: true,
|
||||||
Policy: latestGroupStat.groupPolicy.Policy,
|
Policy: latestGroupStat.groupPolicy.Policy,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: lastUpdate,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(ctx, fmt.Errorf("Error healing IAM group policy mapping for %s from peer site %s -> site %s : %w", group, latestPeerName, peerName, err))
|
logger.LogIf(ctx, fmt.Errorf("Error healing IAM group policy mapping for %s from peer site %s -> site %s : %w", group, latestPeerName, peerName, err))
|
||||||
@ -4340,11 +4407,11 @@ func (c *SiteReplicationSys) healUsers(ctx context.Context, objAPI ObjectLayer,
|
|||||||
|
|
||||||
peerName := info.Sites[dID].Name
|
peerName := info.Sites[dID].Name
|
||||||
|
|
||||||
creds, ok := globalIAMSys.GetUser(ctx, user)
|
u, ok := globalIAMSys.GetUser(ctx, user)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
creds := u.Credentials
|
||||||
// heal only the user accounts that are local users
|
// heal only the user accounts that are local users
|
||||||
if creds.IsServiceAccount() {
|
if creds.IsServiceAccount() {
|
||||||
claims, err := globalIAMSys.GetClaimsForSvcAcc(ctx, creds.AccessKey)
|
claims, err := globalIAMSys.GetClaimsForSvcAcc(ctx, creds.AccessKey)
|
||||||
@ -4381,6 +4448,7 @@ func (c *SiteReplicationSys) healUsers(ctx context.Context, objAPI ObjectLayer,
|
|||||||
Status: creds.Status,
|
Status: creds.Status,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: lastUpdate,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, fmt.Errorf("Error healing service account %s from peer site %s -> %s : %w", user, latestPeerName, peerName, err))
|
logger.LogIf(ctx, fmt.Errorf("Error healing service account %s from peer site %s -> %s : %w", user, latestPeerName, peerName, err))
|
||||||
}
|
}
|
||||||
@ -4402,6 +4470,7 @@ func (c *SiteReplicationSys) healUsers(ctx context.Context, objAPI ObjectLayer,
|
|||||||
ParentUser: creds.ParentUser,
|
ParentUser: creds.ParentUser,
|
||||||
ParentPolicyMapping: u.PolicyName,
|
ParentPolicyMapping: u.PolicyName,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: lastUpdate,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, fmt.Errorf("Error healing temporary credentials %s from peer site %s -> %s : %w", user, latestPeerName, peerName, err))
|
logger.LogIf(ctx, fmt.Errorf("Error healing temporary credentials %s from peer site %s -> %s : %w", user, latestPeerName, peerName, err))
|
||||||
}
|
}
|
||||||
@ -4417,6 +4486,7 @@ func (c *SiteReplicationSys) healUsers(ctx context.Context, objAPI ObjectLayer,
|
|||||||
Status: latestUserStat.userInfo.Status,
|
Status: latestUserStat.userInfo.Status,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: lastUpdate,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, fmt.Errorf("Error healing user %s from peer site %s -> %s : %w", user, latestPeerName, peerName, err))
|
logger.LogIf(ctx, fmt.Errorf("Error healing user %s from peer site %s -> %s : %w", user, latestPeerName, peerName, err))
|
||||||
}
|
}
|
||||||
@ -4481,6 +4551,7 @@ func (c *SiteReplicationSys) healGroups(ctx context.Context, objAPI ObjectLayer,
|
|||||||
IsRemove: false,
|
IsRemove: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdatedAt: lastUpdate,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, fmt.Errorf("Error healing group %s from peer site %s -> site %s : %w", group, latestPeerName, peerName, err))
|
logger.LogIf(ctx, fmt.Errorf("Error healing group %s from peer site %s -> site %s : %w", group, latestPeerName, peerName, err))
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,8 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
|
|||||||
cred.ParentUser = user.AccessKey
|
cred.ParentUser = user.AccessKey
|
||||||
|
|
||||||
// Set the newly generated credentials.
|
// Set the newly generated credentials.
|
||||||
if err = globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, ""); err != nil {
|
updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, "")
|
||||||
|
if err != nil {
|
||||||
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -290,6 +291,7 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) {
|
|||||||
SessionToken: cred.SessionToken,
|
SessionToken: cred.SessionToken,
|
||||||
ParentUser: cred.ParentUser,
|
ParentUser: cred.ParentUser,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
}
|
}
|
||||||
@ -469,7 +471,8 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the newly generated credentials.
|
// Set the newly generated credentials.
|
||||||
if err = globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, policyName); err != nil {
|
updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, policyName)
|
||||||
|
if err != nil {
|
||||||
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -484,6 +487,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
|
|||||||
ParentUser: cred.ParentUser,
|
ParentUser: cred.ParentUser,
|
||||||
ParentPolicyMapping: policyName,
|
ParentPolicyMapping: policyName,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
}
|
}
|
||||||
@ -639,7 +643,8 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
|
|||||||
// Set the newly generated credentials, policyName is empty on purpose
|
// Set the newly generated credentials, policyName is empty on purpose
|
||||||
// LDAP policies are applied automatically using their ldapUser, ldapGroups
|
// LDAP policies are applied automatically using their ldapUser, ldapGroups
|
||||||
// mapping.
|
// mapping.
|
||||||
if err = globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, ""); err != nil {
|
updatedAt, err := globalIAMSys.SetTempUser(ctx, cred.AccessKey, cred, "")
|
||||||
|
if err != nil {
|
||||||
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -653,6 +658,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
|
|||||||
SessionToken: cred.SessionToken,
|
SessionToken: cred.SessionToken,
|
||||||
ParentUser: cred.ParentUser,
|
ParentUser: cred.ParentUser,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
}
|
}
|
||||||
@ -797,7 +803,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
|
|||||||
|
|
||||||
tmpCredentials.ParentUser = parentUser
|
tmpCredentials.ParentUser = parentUser
|
||||||
policyName := certificate.Subject.CommonName
|
policyName := certificate.Subject.CommonName
|
||||||
err = globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, policyName)
|
updatedAt, err := globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, policyName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
||||||
return
|
return
|
||||||
@ -813,6 +819,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
|
|||||||
ParentUser: tmpCredentials.ParentUser,
|
ParentUser: tmpCredentials.ParentUser,
|
||||||
ParentPolicyMapping: policyName,
|
ParentPolicyMapping: policyName,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
}
|
}
|
||||||
@ -918,7 +925,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCustomToken(w http.ResponseWriter, r *h
|
|||||||
}
|
}
|
||||||
|
|
||||||
tmpCredentials.ParentUser = parentUser
|
tmpCredentials.ParentUser = parentUser
|
||||||
err = globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, "")
|
updatedAt, err := globalIAMSys.SetTempUser(ctx, tmpCredentials.AccessKey, tmpCredentials, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInternalError, err)
|
||||||
return
|
return
|
||||||
@ -933,6 +940,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCustomToken(w http.ResponseWriter, r *h
|
|||||||
SessionToken: tmpCredentials.SessionToken,
|
SessionToken: tmpCredentials.SessionToken,
|
||||||
ParentUser: tmpCredentials.ParentUser,
|
ParentUser: tmpCredentials.ParentUser,
|
||||||
},
|
},
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
|
@ -285,13 +285,43 @@ if [ "${val}" != "val1" ]; then
|
|||||||
echo "expected bucket tag to have replicated, exiting..."
|
echo "expected bucket tag to have replicated, exiting..."
|
||||||
exit_1;
|
exit_1;
|
||||||
fi
|
fi
|
||||||
|
# Create user with policy consoleAdmin on minio1
|
||||||
|
./mc admin user add minio1 foobarx foobar123
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "adding user failed, exiting.."
|
||||||
|
exit_1;
|
||||||
|
fi
|
||||||
|
./mc admin policy set minio1 consoleAdmin user=foobarx
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "adding policy mapping failed, exiting.."
|
||||||
|
exit_1;
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# unset policy for foobarx in minio2
|
||||||
|
./mc admin policy unset minio2 consoleAdmin user=foobarx
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "unset policy mapping failed, exiting.."
|
||||||
|
exit_1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Test whether policy unset replicated to minio1
|
||||||
|
policy=$(./mc admin user info minio1 foobarx --json | jq -r .policyName)
|
||||||
|
if [ "${policy}" != "null" ]; then
|
||||||
|
echo "expected policy unset to have replicated, exiting..."
|
||||||
|
exit_1;
|
||||||
|
fi
|
||||||
|
|
||||||
kill -9 ${site1_pid}
|
kill -9 ${site1_pid}
|
||||||
# Update tag on minio2/newbucket when minio1 is down
|
# Update tag on minio2/newbucket when minio1 is down
|
||||||
./mc tag set minio2/newbucket "key=val2"
|
./mc tag set minio2/newbucket "key=val2"
|
||||||
|
|
||||||
# Restart minio1 instance
|
# Restart minio1 instance
|
||||||
minio server --config-dir /tmp/minio-internal --address ":9001" /tmp/minio-internal-idp1/{1...4} >/tmp/minio1_1.log 2>&1 &
|
minio server --config-dir /tmp/minio-internal --address ":9001" /tmp/minio-internal-idp1/{1...4} >/tmp/minio1_1.log 2>&1 &
|
||||||
sleep 10
|
sleep 15
|
||||||
|
|
||||||
# Test whether most recent tag update on minio2 is replicated to minio1
|
# Test whether most recent tag update on minio2 is replicated to minio1
|
||||||
val=$(./mc tag list minio1/newbucket --json | jq -r .tagset | jq -r .key )
|
val=$(./mc tag list minio1/newbucket --json | jq -r .tagset | jq -r .key )
|
||||||
if [ "${val}" != "val2" ]; then
|
if [ "${val}" != "val2" ]; then
|
||||||
|
Loading…
Reference in New Issue
Block a user