@ -442,6 +442,122 @@ func (sys *IAMSys) Initialized() bool {
return sys . store != nil
return sys . store != nil
}
}
// Load - loads all credentials
func ( sys * IAMSys ) Load ( ctx context . Context , store IAMStorageAPI ) error {
iamUsersMap := make ( map [ string ] auth . Credentials )
iamGroupsMap := make ( map [ string ] GroupInfo )
iamUserPolicyMap := make ( map [ string ] MappedPolicy )
iamGroupPolicyMap := make ( map [ string ] MappedPolicy )
iamPolicyDocsMap := make ( map [ string ] iampolicy . Policy )
store . rlock ( )
isMinIOUsersSys := sys . usersSysType == MinIOUsersSysType
store . runlock ( )
if err := store . loadPolicyDocs ( ctx , iamPolicyDocsMap ) ; err != nil {
return err
}
// Sets default canned policies, if none are set.
setDefaultCannedPolicies ( iamPolicyDocsMap )
if isMinIOUsersSys {
if err := store . loadUsers ( ctx , regularUser , iamUsersMap ) ; err != nil {
return err
}
if err := store . loadGroups ( ctx , iamGroupsMap ) ; err != nil {
return err
}
}
// load polices mapped to users
if err := store . loadMappedPolicies ( ctx , regularUser , false , iamUserPolicyMap ) ; err != nil {
return err
}
// load policies mapped to groups
if err := store . loadMappedPolicies ( ctx , regularUser , true , iamGroupPolicyMap ) ; err != nil {
return err
}
if err := store . loadUsers ( ctx , srvAccUser , iamUsersMap ) ; err != nil {
return err
}
// load STS temp users
if err := store . loadUsers ( ctx , stsUser , iamUsersMap ) ; err != nil {
return err
}
// load STS policy mappings
if err := store . loadMappedPolicies ( ctx , stsUser , false , iamUserPolicyMap ) ; err != nil {
return err
}
store . lock ( )
defer store . unlock ( )
for k , v := range iamPolicyDocsMap {
sys . iamPolicyDocsMap [ k ] = v
}
// Merge the new reloaded entries into global map.
// See issue https://github.com/minio/minio/issues/9651
// where the present list of entries on disk are not yet
// latest, there is a small window where this can make
// valid users invalid.
for k , v := range iamUsersMap {
sys . iamUsersMap [ k ] = v
}
for k , v := range iamUserPolicyMap {
sys . iamUserPolicyMap [ k ] = v
}
// purge any expired entries which became expired now.
var expiredEntries [ ] string
for k , v := range sys . iamUsersMap {
if v . IsExpired ( ) {
delete ( sys . iamUsersMap , k )
delete ( sys . iamUserPolicyMap , k )
expiredEntries = append ( expiredEntries , k )
// Deleting on the disk is taken care of in the next cycle
}
}
for _ , v := range sys . iamUsersMap {
if v . IsServiceAccount ( ) {
for _ , accessKey := range expiredEntries {
if v . ParentUser == accessKey {
_ = store . deleteUserIdentity ( ctx , v . AccessKey , srvAccUser )
delete ( sys . iamUsersMap , v . AccessKey )
}
}
}
}
// purge any expired entries which became expired now.
for k , v := range sys . iamUsersMap {
if v . IsExpired ( ) {
delete ( sys . iamUsersMap , k )
delete ( sys . iamUserPolicyMap , k )
// Deleting on the etcd is taken care of in the next cycle
}
}
for k , v := range iamGroupPolicyMap {
sys . iamGroupPolicyMap [ k ] = v
}
for k , v := range iamGroupsMap {
sys . iamGroupsMap [ k ] = v
}
sys . buildUserGroupMemberships ( )
sys . storeFallback = false
return nil
}
// Init - initializes config system by reading entries from config/iam
// Init - initializes config system by reading entries from config/iam
func ( sys * IAMSys ) Init ( ctx context . Context , objAPI ObjectLayer ) {
func ( sys * IAMSys ) Init ( ctx context . Context , objAPI ObjectLayer ) {
// Initialize IAM store
// Initialize IAM store
@ -664,6 +780,10 @@ func (sys *IAMSys) DeleteUser(accessKey string) error {
return errServerNotInitialized
return errServerNotInitialized
}
}
if sys . usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
}
// First we remove the user from their groups.
// First we remove the user from their groups.
userInfo , getErr := sys . GetUserInfo ( accessKey )
userInfo , getErr := sys . GetUserInfo ( accessKey )
if getErr != nil {
if getErr != nil {
@ -681,18 +801,21 @@ func (sys *IAMSys) DeleteUser(accessKey string) error {
sys . store . lock ( )
sys . store . lock ( )
defer sys . store . unlock ( )
defer sys . store . unlock ( )
if sys . usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
}
// Delete any service accounts if any first.
for _ , u := range sys . iamUsersMap {
for _ , u := range sys . iamUsersMap {
// Delete any service accounts if any first.
if u . IsServiceAccount ( ) {
if u . IsServiceAccount ( ) {
if u . ParentUser == accessKey {
if u . ParentUser == accessKey {
_ = sys . store . deleteUserIdentity ( context . Background ( ) , u . AccessKey , srvAccUser )
_ = sys . store . deleteUserIdentity ( context . Background ( ) , u . AccessKey , srvAccUser )
delete ( sys . iamUsersMap , u . AccessKey )
delete ( sys . iamUsersMap , u . AccessKey )
}
}
}
}
// Delete any associated STS users.
if u . IsTemp ( ) {
if u . ParentUser == accessKey {
_ = sys . store . deleteUserIdentity ( context . Background ( ) , u . AccessKey , stsUser )
delete ( sys . iamUsersMap , u . AccessKey )
}
}
}
}
// It is ok to ignore deletion error on the mapped policy
// It is ok to ignore deletion error on the mapped policy
@ -869,13 +992,19 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
}
}
sys . store . rlock ( )
sys . store . rlock ( )
defer sys . store . runlock ( )
fallback := sys . storeFallback
sys . store . runlock ( )
if fallback {
sys . loadUserFromStore ( name )
}
if sys . usersSysType != MinIOUsersSysType {
if sys . usersSysType != MinIOUsersSysType {
sys . store . rlock ( )
// If the user has a mapped policy or is a member of a group, we
// If the user has a mapped policy or is a member of a group, we
// return that info. Otherwise we return error.
// return that info. Otherwise we return error.
mappedPolicy , ok1 := sys . iamUserPolicyMap [ name ]
mappedPolicy , ok1 := sys . iamUserPolicyMap [ name ]
memberships , ok2 := sys . iamUserGroupMemberships [ name ]
memberships , ok2 := sys . iamUserGroupMemberships [ name ]
sys . store . runlock ( )
if ! ok1 && ! ok2 {
if ! ok1 && ! ok2 {
return u , errNoSuchUser
return u , errNoSuchUser
}
}
@ -885,6 +1014,9 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
} , nil
} , nil
}
}
sys . store . rlock ( )
defer sys . store . runlock ( )
cred , found := sys . iamUsersMap [ name ]
cred , found := sys . iamUsersMap [ name ]
if ! found {
if ! found {
return u , errNoSuchUser
return u , errNoSuchUser
@ -894,7 +1026,7 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
return u , errIAMActionNotAllowed
return u , errIAMActionNotAllowed
}
}
u = madmin . UserInfo {
return madmin . UserInfo {
PolicyName : sys . iamUserPolicyMap [ name ] . Policies ,
PolicyName : sys . iamUserPolicyMap [ name ] . Policies ,
Status : func ( ) madmin . AccountStatus {
Status : func ( ) madmin . AccountStatus {
if cred . IsValid ( ) {
if cred . IsValid ( ) {
@ -903,8 +1035,8 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
return madmin . AccountDisabled
return madmin . AccountDisabled
} ( ) ,
} ( ) ,
MemberOf : sys . iamUserGroupMemberships [ name ] . ToSlice ( ) ,
MemberOf : sys . iamUserGroupMemberships [ name ] . ToSlice ( ) ,
}
} , nil
return u , nil
}
}
// SetUserStatus - sets current user status, supports disabled or enabled.
// SetUserStatus - sets current user status, supports disabled or enabled.
@ -913,6 +1045,10 @@ func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus)
return errServerNotInitialized
return errServerNotInitialized
}
}
if sys . usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
}
if status != madmin . AccountEnabled && status != madmin . AccountDisabled {
if status != madmin . AccountEnabled && status != madmin . AccountDisabled {
return errInvalidArgument
return errInvalidArgument
}
}
@ -920,10 +1056,6 @@ func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus)
sys . store . lock ( )
sys . store . lock ( )
defer sys . store . unlock ( )
defer sys . store . unlock ( )
if sys . usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
}
cred , ok := sys . iamUsersMap [ accessKey ]
cred , ok := sys . iamUsersMap [ accessKey ]
if ! ok {
if ! ok {
return errNoSuchUser
return errNoSuchUser
@ -1091,30 +1223,31 @@ func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string) e
return nil
return nil
}
}
// SetUser - set user credentials and policy.
// CreateUser - create new user credentials and policy, if user already exists
func ( sys * IAMSys ) SetUser ( accessKey string , uinfo madmin . UserInfo ) error {
// they shall be rewritten with new inputs.
func ( sys * IAMSys ) CreateUser ( accessKey string , uinfo madmin . UserInfo ) error {
if ! sys . Initialized ( ) {
if ! sys . Initialized ( ) {
return errServerNotInitialized
return errServerNotInitialized
}
}
u := newUserIdentity ( auth . Credentials {
AccessKey : accessKey ,
SecretKey : uinfo . SecretKey ,
Status : string ( uinfo . Status ) ,
} )
sys . store . lock ( )
defer sys . store . unlock ( )
if sys . usersSysType != MinIOUsersSysType {
if sys . usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
return errIAMActionNotAllowed
}
}
sys . store . lock ( )
defer sys . store . unlock ( )
cr , ok := sys . iamUsersMap [ accessKey ]
cr , ok := sys . iamUsersMap [ accessKey ]
if cr . IsTemp ( ) && ok {
if cr . IsTemp ( ) && ok {
return errIAMActionNotAllowed
return errIAMActionNotAllowed
}
}
u := newUserIdentity ( auth . Credentials {
AccessKey : accessKey ,
SecretKey : uinfo . SecretKey ,
Status : string ( uinfo . Status ) ,
} )
if err := sys . store . saveUserIdentity ( context . Background ( ) , accessKey , regularUser , u ) ; err != nil {
if err := sys . store . saveUserIdentity ( context . Background ( ) , accessKey , regularUser , u ) ; err != nil {
return err
return err
}
}
@ -1156,55 +1289,55 @@ func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error {
return nil
return nil
}
}
// GetUser - get user credentials
func ( sys * IAMSys ) loadUserFromStore ( accessKey string ) {
func ( sys * IAMSys ) GetUser ( accessKey string ) ( cred auth . Credentials , ok bool ) {
sys . store . lock ( )
if ! sys . Initialized ( ) {
// If user is already found proceed.
return cred , false
if _ , found := sys . iamUsersMap [ accessKey ] ; ! found {
}
sys . store . loadUser ( context . Background ( ) , accessKey , regularUser , sys . iamUsersMap )
if _ , found = sys . iamUsersMap [ accessKey ] ; found {
reloadUser := func ( ) {
// found user, load its mapped policies
sys . store . lock ( )
sys . store . loadMappedPolicy ( context . Background ( ) , accessKey , regularUser , false , sys . iamUserPolicyMap )
// If user is already found proceed.
} else {
if _ , found := sys . iamUsersMap [ accessKey ] ; ! found {
sys . store . loadUser ( context . Background ( ) , accessKey , srvAccUser , sys . iamUsersMap )
sys . store . loadUser ( context . Background ( ) , accessKey , regularUser , sys . iamUsersMap )
if svc , found := sys . iamUsersMap [ accessKey ] ; found {
if _ , found = sys . iamUsersMap [ accessKey ] ; found {
// Found service account, load its parent user and its mapped policies.
// found user, load its mapped policies
if sys . usersSysType == MinIOUsersSysType {
sys . store . loadMappedPolicy ( context . Background ( ) , accessKey , regularUser , false , sys . iamUserPolicyMap )
sys . store . loadUser ( context . Background ( ) , svc . ParentUser , regularUser , sys . iamUsersMap )
}
sys . store . loadMappedPolicy ( context . Background ( ) , svc . ParentUser , regularUser , false , sys . iamUserPolicyMap )
} else {
} else {
sys . store . loadUser ( context . Background ( ) , accessKey , srvAccUser , sys . iamUsersMap )
// None found fall back to STS users.
if svc , found := sys . iamUsersMap [ accessKey ] ; found {
sys . store . loadUser ( context . Background ( ) , accessKey , stsUser , sys . iamUsersMap )
// Found service account, load its parent user and its mapped policies.
if _ , found = sys . iamUsersMap [ accessKey ] ; found {
if sys . usersSysType == MinIOUsersSysType {
// STS user found, load its mapped policy.
sys . store . loadUser ( context . Background ( ) , svc . ParentUser , regularUser , sys . iamUsersMap )
sys . store . loadMappedPolicy ( context . Background ( ) , accessKey , stsUser , false , sys . iamUserPolicyMap )
}
sys . store . loadMappedPolicy ( context . Background ( ) , svc . ParentUser , regularUser , false , sys . iamUserPolicyMap )
} else {
// None found fall back to STS users.
sys . store . loadUser ( context . Background ( ) , accessKey , stsUser , sys . iamUsersMap )
if _ , found = sys . iamUsersMap [ accessKey ] ; found {
// STS user found, load its mapped policy.
sys . store . loadMappedPolicy ( context . Background ( ) , accessKey , stsUser , false , sys . iamUserPolicyMap )
}
}
}
}
}
}
}
}
// Load associated policies if any.
// Load associated policies if any.
for _ , policy := range sys . iamUserPolicyMap [ accessKey ] . toSlice ( ) {
for _ , policy := range sys . iamUserPolicyMap [ accessKey ] . toSlice ( ) {
if _ , found := sys . iamPolicyDocsMap [ policy ] ; ! found {
if _ , found := sys . iamPolicyDocsMap [ policy ] ; ! found {
sys . store . loadPolicyDoc ( context . Background ( ) , policy , sys . iamPolicyDocsMap )
sys . store . loadPolicyDoc ( context . Background ( ) , policy , sys . iamPolicyDocsMap )
}
}
}
}
sys . buildUserGroupMemberships ( )
sys . store . unlock ( )
}
sys . buildUserGroupMemberships ( )
// GetUser - get user credentials
sys . store . unlock ( )
func ( sys * IAMSys ) GetUser ( accessKey string ) ( cred auth . Credentials , ok bool ) {
if ! sys . Initialized ( ) {
return cred , false
}
}
sys . store . rlock ( )
sys . store . rlock ( )
fallback := sys . storeFallback
fallback := sys . storeFallback
sys . store . runlock ( )
sys . store . runlock ( )
if fallback {
if fallback {
re loadUser( )
sys . loadUserFromStore ( accessKey )
}
}
sys . store . rlock ( )
sys . store . rlock ( )
@ -1217,7 +1350,7 @@ func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) {
// the IAM store and see if credential
// the IAM store and see if credential
// exists now. If it doesn't proceed to
// exists now. If it doesn't proceed to
// fail.
// fail.
re loadUser( )
sys . loadUserFromStore ( accessKey )
sys . store . rlock ( )
sys . store . rlock ( )
cred , ok = sys . iamUsersMap [ accessKey ]
cred , ok = sys . iamUsersMap [ accessKey ]
@ -1305,14 +1438,14 @@ func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error {
return errServerNotInitialized
return errServerNotInitialized
}
}
if group == "" {
return errInvalidArgument
}
if sys . usersSysType != MinIOUsersSysType {
if sys . usersSysType != MinIOUsersSysType {
return errIAMActionNotAllowed
return errIAMActionNotAllowed
}
}
if group == "" {
return errInvalidArgument
}
sys . store . lock ( )
sys . store . lock ( )
defer sys . store . unlock ( )
defer sys . store . unlock ( )