github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/iam-store.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"context"
    22  	"encoding/base64"
    23  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"sort"
    27  	"strings"
    28  	"time"
    29  
    30  	jsoniter "github.com/json-iterator/go"
    31  	"github.com/minio/madmin-go/v3"
    32  	"github.com/minio/minio-go/v7/pkg/set"
    33  	"github.com/minio/minio/internal/auth"
    34  	"github.com/minio/minio/internal/config/identity/openid"
    35  	"github.com/minio/minio/internal/jwt"
    36  	"github.com/minio/minio/internal/logger"
    37  	"github.com/minio/pkg/v2/policy"
    38  	"github.com/puzpuzpuz/xsync/v3"
    39  )
    40  
    41  const (
    42  	// IAM configuration directory.
    43  	iamConfigPrefix = minioConfigPrefix + "/iam"
    44  
    45  	// IAM users directory.
    46  	iamConfigUsersPrefix = iamConfigPrefix + "/users/"
    47  
    48  	// IAM service accounts directory.
    49  	iamConfigServiceAccountsPrefix = iamConfigPrefix + "/service-accounts/"
    50  
    51  	// IAM groups directory.
    52  	iamConfigGroupsPrefix = iamConfigPrefix + "/groups/"
    53  
    54  	// IAM policies directory.
    55  	iamConfigPoliciesPrefix = iamConfigPrefix + "/policies/"
    56  
    57  	// IAM sts directory.
    58  	iamConfigSTSPrefix = iamConfigPrefix + "/sts/"
    59  
    60  	// IAM Policy DB prefixes.
    61  	iamConfigPolicyDBPrefix                = iamConfigPrefix + "/policydb/"
    62  	iamConfigPolicyDBUsersPrefix           = iamConfigPolicyDBPrefix + "users/"
    63  	iamConfigPolicyDBSTSUsersPrefix        = iamConfigPolicyDBPrefix + "sts-users/"
    64  	iamConfigPolicyDBServiceAccountsPrefix = iamConfigPolicyDBPrefix + "service-accounts/"
    65  	iamConfigPolicyDBGroupsPrefix          = iamConfigPolicyDBPrefix + "groups/"
    66  
    67  	// IAM identity file which captures identity credentials.
    68  	iamIdentityFile = "identity.json"
    69  
    70  	// IAM policy file which provides policies for each users.
    71  	iamPolicyFile = "policy.json"
    72  
    73  	// IAM group members file
    74  	iamGroupMembersFile = "members.json"
    75  
    76  	// IAM format file
    77  	iamFormatFile = "format.json"
    78  
    79  	iamFormatVersion1 = 1
    80  
    81  	minServiceAccountExpiry time.Duration = 15 * time.Minute
    82  	maxServiceAccountExpiry time.Duration = 365 * 24 * time.Hour
    83  )
    84  
    85  var errInvalidSvcAcctExpiration = errors.New("invalid service account expiration")
    86  
    87  type iamFormat struct {
    88  	Version int `json:"version"`
    89  }
    90  
    91  func newIAMFormatVersion1() iamFormat {
    92  	return iamFormat{Version: iamFormatVersion1}
    93  }
    94  
    95  func getIAMFormatFilePath() string {
    96  	return iamConfigPrefix + SlashSeparator + iamFormatFile
    97  }
    98  
    99  func getUserIdentityPath(user string, userType IAMUserType) string {
   100  	var basePath string
   101  	switch userType {
   102  	case svcUser:
   103  		basePath = iamConfigServiceAccountsPrefix
   104  	case stsUser:
   105  		basePath = iamConfigSTSPrefix
   106  	default:
   107  		basePath = iamConfigUsersPrefix
   108  	}
   109  	return pathJoin(basePath, user, iamIdentityFile)
   110  }
   111  
   112  func saveIAMFormat(ctx context.Context, store IAMStorageAPI) error {
   113  	bootstrapTraceMsg("Load IAM format file")
   114  	var iamFmt iamFormat
   115  	path := getIAMFormatFilePath()
   116  	if err := store.loadIAMConfig(ctx, &iamFmt, path); err != nil && !errors.Is(err, errConfigNotFound) {
   117  		// if IAM format
   118  		return err
   119  	}
   120  
   121  	if iamFmt.Version >= iamFormatVersion1 {
   122  		// Nothing to do.
   123  		return nil
   124  	}
   125  
   126  	bootstrapTraceMsg("Write IAM format file")
   127  	// Save iam format to version 1.
   128  	return store.saveIAMConfig(ctx, newIAMFormatVersion1(), path)
   129  }
   130  
   131  func getGroupInfoPath(group string) string {
   132  	return pathJoin(iamConfigGroupsPrefix, group, iamGroupMembersFile)
   133  }
   134  
   135  func getPolicyDocPath(name string) string {
   136  	return pathJoin(iamConfigPoliciesPrefix, name, iamPolicyFile)
   137  }
   138  
   139  func getMappedPolicyPath(name string, userType IAMUserType, isGroup bool) string {
   140  	if isGroup {
   141  		return pathJoin(iamConfigPolicyDBGroupsPrefix, name+".json")
   142  	}
   143  	switch userType {
   144  	case svcUser:
   145  		return pathJoin(iamConfigPolicyDBServiceAccountsPrefix, name+".json")
   146  	case stsUser:
   147  		return pathJoin(iamConfigPolicyDBSTSUsersPrefix, name+".json")
   148  	default:
   149  		return pathJoin(iamConfigPolicyDBUsersPrefix, name+".json")
   150  	}
   151  }
   152  
   153  // UserIdentity represents a user's secret key and their status
   154  type UserIdentity struct {
   155  	Version     int              `json:"version"`
   156  	Credentials auth.Credentials `json:"credentials"`
   157  	UpdatedAt   time.Time        `json:"updatedAt,omitempty"`
   158  }
   159  
   160  func newUserIdentity(cred auth.Credentials) UserIdentity {
   161  	return UserIdentity{Version: 1, Credentials: cred, UpdatedAt: UTCNow()}
   162  }
   163  
   164  // GroupInfo contains info about a group
   165  type GroupInfo struct {
   166  	Version   int       `json:"version"`
   167  	Status    string    `json:"status"`
   168  	Members   []string  `json:"members"`
   169  	UpdatedAt time.Time `json:"updatedAt,omitempty"`
   170  }
   171  
   172  func newGroupInfo(members []string) GroupInfo {
   173  	return GroupInfo{Version: 1, Status: statusEnabled, Members: members, UpdatedAt: UTCNow()}
   174  }
   175  
   176  // MappedPolicy represents a policy name mapped to a user or group
   177  type MappedPolicy struct {
   178  	Version   int       `json:"version"`
   179  	Policies  string    `json:"policy"`
   180  	UpdatedAt time.Time `json:"updatedAt,omitempty"`
   181  }
   182  
   183  // mappedPoliciesToMap copies the map of mapped policies to a regular map.
   184  func mappedPoliciesToMap(m *xsync.MapOf[string, MappedPolicy]) map[string]MappedPolicy {
   185  	policies := make(map[string]MappedPolicy, m.Size())
   186  	m.Range(func(k string, v MappedPolicy) bool {
   187  		policies[k] = v
   188  		return true
   189  	})
   190  	return policies
   191  }
   192  
   193  // converts a mapped policy into a slice of distinct policies
   194  func (mp MappedPolicy) toSlice() []string {
   195  	var policies []string
   196  	for _, policy := range strings.Split(mp.Policies, ",") {
   197  		if strings.TrimSpace(policy) == "" {
   198  			continue
   199  		}
   200  		policies = append(policies, policy)
   201  	}
   202  	return policies
   203  }
   204  
   205  func (mp MappedPolicy) policySet() set.StringSet {
   206  	return set.CreateStringSet(mp.toSlice()...)
   207  }
   208  
   209  func newMappedPolicy(policy string) MappedPolicy {
   210  	return MappedPolicy{Version: 1, Policies: policy, UpdatedAt: UTCNow()}
   211  }
   212  
   213  // PolicyDoc represents an IAM policy with some metadata.
   214  type PolicyDoc struct {
   215  	Version    int `json:",omitempty"`
   216  	Policy     policy.Policy
   217  	CreateDate time.Time `json:",omitempty"`
   218  	UpdateDate time.Time `json:",omitempty"`
   219  }
   220  
   221  func newPolicyDoc(p policy.Policy) PolicyDoc {
   222  	now := UTCNow().Round(time.Millisecond)
   223  	return PolicyDoc{
   224  		Version:    1,
   225  		Policy:     p,
   226  		CreateDate: now,
   227  		UpdateDate: now,
   228  	}
   229  }
   230  
   231  // defaultPolicyDoc - used to wrap a default policy as PolicyDoc.
   232  func defaultPolicyDoc(p policy.Policy) PolicyDoc {
   233  	return PolicyDoc{
   234  		Version: 1,
   235  		Policy:  p,
   236  	}
   237  }
   238  
   239  func (d *PolicyDoc) update(p policy.Policy) {
   240  	now := UTCNow().Round(time.Millisecond)
   241  	d.UpdateDate = now
   242  	if d.CreateDate.IsZero() {
   243  		d.CreateDate = now
   244  	}
   245  	d.Policy = p
   246  }
   247  
   248  // parseJSON parses both the old and the new format for storing policy
   249  // definitions.
   250  //
   251  // The on-disk format of policy definitions has changed (around early 12/2021)
   252  // from policy.Policy to PolicyDoc. To avoid a migration, loading supports
   253  // both the old and the new formats.
   254  func (d *PolicyDoc) parseJSON(data []byte) error {
   255  	json := jsoniter.ConfigCompatibleWithStandardLibrary
   256  	var doc PolicyDoc
   257  	err := json.Unmarshal(data, &doc)
   258  	if err != nil {
   259  		err2 := json.Unmarshal(data, &doc.Policy)
   260  		if err2 != nil {
   261  			// Just return the first error.
   262  			return err
   263  		}
   264  		d.Policy = doc.Policy
   265  		return nil
   266  	}
   267  	*d = doc
   268  	return nil
   269  }
   270  
   271  // key options
   272  type options struct {
   273  	ttl int64 // expiry in seconds
   274  }
   275  
   276  type iamWatchEvent struct {
   277  	isCreated bool // !isCreated implies a delete event.
   278  	keyPath   string
   279  }
   280  
   281  // iamCache contains in-memory cache of IAM data.
   282  type iamCache struct {
   283  	updatedAt time.Time
   284  
   285  	// map of policy names to policy definitions
   286  	iamPolicyDocsMap map[string]PolicyDoc
   287  
   288  	// map of regular username to credentials
   289  	iamUsersMap map[string]UserIdentity
   290  	// map of regular username to policy names
   291  	iamUserPolicyMap *xsync.MapOf[string, MappedPolicy]
   292  
   293  	// STS accounts are loaded on demand and not via the periodic IAM reload.
   294  	// map of STS access key to credentials
   295  	iamSTSAccountsMap map[string]UserIdentity
   296  	// map of STS access key to policy names
   297  	iamSTSPolicyMap *xsync.MapOf[string, MappedPolicy]
   298  
   299  	// map of group names to group info
   300  	iamGroupsMap map[string]GroupInfo
   301  	// map of user names to groups they are a member of
   302  	iamUserGroupMemberships map[string]set.StringSet
   303  	// map of group names to policy names
   304  	iamGroupPolicyMap *xsync.MapOf[string, MappedPolicy]
   305  }
   306  
   307  func newIamCache() *iamCache {
   308  	return &iamCache{
   309  		iamPolicyDocsMap:        map[string]PolicyDoc{},
   310  		iamUsersMap:             map[string]UserIdentity{},
   311  		iamUserPolicyMap:        xsync.NewMapOf[string, MappedPolicy](),
   312  		iamSTSAccountsMap:       map[string]UserIdentity{},
   313  		iamSTSPolicyMap:         xsync.NewMapOf[string, MappedPolicy](),
   314  		iamGroupsMap:            map[string]GroupInfo{},
   315  		iamUserGroupMemberships: map[string]set.StringSet{},
   316  		iamGroupPolicyMap:       xsync.NewMapOf[string, MappedPolicy](),
   317  	}
   318  }
   319  
   320  // buildUserGroupMemberships - builds the memberships map. IMPORTANT:
   321  // Assumes that c.Lock is held by caller.
   322  func (c *iamCache) buildUserGroupMemberships() {
   323  	for group, gi := range c.iamGroupsMap {
   324  		c.updateGroupMembershipsMap(group, &gi)
   325  	}
   326  }
   327  
   328  // updateGroupMembershipsMap - updates the memberships map for a
   329  // group. IMPORTANT: Assumes c.Lock() is held by caller.
   330  func (c *iamCache) updateGroupMembershipsMap(group string, gi *GroupInfo) {
   331  	if gi == nil {
   332  		return
   333  	}
   334  	for _, member := range gi.Members {
   335  		v := c.iamUserGroupMemberships[member]
   336  		if v == nil {
   337  			v = set.CreateStringSet(group)
   338  		} else {
   339  			v.Add(group)
   340  		}
   341  		c.iamUserGroupMemberships[member] = v
   342  	}
   343  }
   344  
   345  // removeGroupFromMembershipsMap - removes the group from every member
   346  // in the cache. IMPORTANT: Assumes c.Lock() is held by caller.
   347  func (c *iamCache) removeGroupFromMembershipsMap(group string) {
   348  	for member, groups := range c.iamUserGroupMemberships {
   349  		if !groups.Contains(group) {
   350  			continue
   351  		}
   352  		groups.Remove(group)
   353  		c.iamUserGroupMemberships[member] = groups
   354  	}
   355  }
   356  
   357  // policyDBGet - lower-level helper; does not take locks.
   358  //
   359  // If a group is passed, it returns policies associated with the group.
   360  //
   361  // If a user is passed, it returns policies of the user along with any groups
   362  // that the server knows the user is a member of.
   363  //
   364  // In LDAP users mode, the server does not store any group membership
   365  // information in IAM (i.e sys.iam*Map) - this info is stored only in the STS
   366  // generated credentials. Thus we skip looking up group memberships, user map,
   367  // and group map and check the appropriate policy maps directly.
   368  func (c *iamCache) policyDBGet(store *IAMStoreSys, name string, isGroup bool) ([]string, time.Time, error) {
   369  	if isGroup {
   370  		if store.getUsersSysType() == MinIOUsersSysType {
   371  			g, ok := c.iamGroupsMap[name]
   372  			if !ok {
   373  				if err := store.loadGroup(context.Background(), name, c.iamGroupsMap); err != nil {
   374  					return nil, time.Time{}, err
   375  				}
   376  				g, ok = c.iamGroupsMap[name]
   377  				if !ok {
   378  					return nil, time.Time{}, errNoSuchGroup
   379  				}
   380  			}
   381  
   382  			// Group is disabled, so we return no policy - this
   383  			// ensures the request is denied.
   384  			if g.Status == statusDisabled {
   385  				return nil, time.Time{}, nil
   386  			}
   387  		}
   388  
   389  		policy, ok := c.iamGroupPolicyMap.Load(name)
   390  		if ok {
   391  			return policy.toSlice(), policy.UpdatedAt, nil
   392  		}
   393  		if err := store.loadMappedPolicyWithRetry(context.TODO(), name, regUser, true, c.iamGroupPolicyMap, 3); err != nil && !errors.Is(err, errNoSuchPolicy) {
   394  			return nil, time.Time{}, err
   395  		}
   396  		policy, _ = c.iamGroupPolicyMap.Load(name)
   397  		return policy.toSlice(), policy.UpdatedAt, nil
   398  	}
   399  
   400  	// When looking for a user's policies, we also check if the user
   401  	// and the groups they are member of are enabled.
   402  	u, ok := c.iamUsersMap[name]
   403  	if ok {
   404  		if !u.Credentials.IsValid() {
   405  			return nil, time.Time{}, nil
   406  		}
   407  	}
   408  
   409  	// For internal IDP regular/service account user accounts, the policy
   410  	// mapping is iamUserPolicyMap. For STS accounts, the parent user would be
   411  	// passed here and we lookup the mapping in iamSTSPolicyMap.
   412  	mp, ok := c.iamUserPolicyMap.Load(name)
   413  	if !ok {
   414  		if err := store.loadMappedPolicyWithRetry(context.TODO(), name, regUser, false, c.iamUserPolicyMap, 3); err != nil && !errors.Is(err, errNoSuchPolicy) {
   415  			return nil, time.Time{}, err
   416  		}
   417  
   418  		mp, ok = c.iamUserPolicyMap.Load(name)
   419  		if !ok {
   420  			// Since user "name" could be a parent user of an STS account, we look up
   421  			// mappings for those too.
   422  			mp, ok = c.iamSTSPolicyMap.Load(name)
   423  			if !ok {
   424  				// Attempt to load parent user mapping for STS accounts
   425  				if err := store.loadMappedPolicyWithRetry(context.TODO(), name, stsUser, false, c.iamSTSPolicyMap, 3); err != nil && !errors.Is(err, errNoSuchPolicy) {
   426  					return nil, time.Time{}, err
   427  				}
   428  				mp, _ = c.iamSTSPolicyMap.Load(name)
   429  			}
   430  		}
   431  	}
   432  
   433  	// returned policy could be empty
   434  	policies := mp.toSlice()
   435  
   436  	for _, group := range c.iamUserGroupMemberships[name].ToSlice() {
   437  		if store.getUsersSysType() == MinIOUsersSysType {
   438  			g, ok := c.iamGroupsMap[group]
   439  			if !ok {
   440  				if err := store.loadGroup(context.Background(), group, c.iamGroupsMap); err != nil {
   441  					return nil, time.Time{}, err
   442  				}
   443  				g, ok = c.iamGroupsMap[group]
   444  				if !ok {
   445  					return nil, time.Time{}, errNoSuchGroup
   446  				}
   447  			}
   448  
   449  			// Group is disabled, so we return no policy - this
   450  			// ensures the request is denied.
   451  			if g.Status == statusDisabled {
   452  				return nil, time.Time{}, nil
   453  			}
   454  		}
   455  
   456  		policy, ok := c.iamGroupPolicyMap.Load(group)
   457  		if !ok {
   458  			if err := store.loadMappedPolicyWithRetry(context.TODO(), group, regUser, true, c.iamGroupPolicyMap, 3); err != nil && !errors.Is(err, errNoSuchPolicy) {
   459  				return nil, time.Time{}, err
   460  			}
   461  			policy, _ = c.iamGroupPolicyMap.Load(group)
   462  		}
   463  
   464  		policies = append(policies, policy.toSlice()...)
   465  	}
   466  
   467  	return policies, mp.UpdatedAt, nil
   468  }
   469  
   470  func (c *iamCache) updateUserWithClaims(key string, u UserIdentity) error {
   471  	if u.Credentials.SessionToken != "" {
   472  		jwtClaims, err := extractJWTClaims(u)
   473  		if err != nil {
   474  			return err
   475  		}
   476  		u.Credentials.Claims = jwtClaims.Map()
   477  	}
   478  	if u.Credentials.IsTemp() && !u.Credentials.IsServiceAccount() {
   479  		c.iamSTSAccountsMap[key] = u
   480  	} else {
   481  		c.iamUsersMap[key] = u
   482  	}
   483  	c.updatedAt = time.Now()
   484  	return nil
   485  }
   486  
   487  // IAMStorageAPI defines an interface for the IAM persistence layer
   488  type IAMStorageAPI interface {
   489  	// The role of the read-write lock is to prevent go routines from
   490  	// concurrently reading and writing the IAM storage. The (r)lock()
   491  	// functions return the iamCache. The cache can be safely written to
   492  	// only when returned by `lock()`.
   493  	lock() *iamCache
   494  	unlock()
   495  	rlock() *iamCache
   496  	runlock()
   497  	getUsersSysType() UsersSysType
   498  	loadPolicyDoc(ctx context.Context, policy string, m map[string]PolicyDoc) error
   499  	loadPolicyDocWithRetry(ctx context.Context, policy string, m map[string]PolicyDoc, retries int) error
   500  	loadPolicyDocs(ctx context.Context, m map[string]PolicyDoc) error
   501  	loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]UserIdentity) error
   502  	loadUsers(ctx context.Context, userType IAMUserType, m map[string]UserIdentity) error
   503  	loadGroup(ctx context.Context, group string, m map[string]GroupInfo) error
   504  	loadGroups(ctx context.Context, m map[string]GroupInfo) error
   505  	loadMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, m *xsync.MapOf[string, MappedPolicy]) error
   506  	loadMappedPolicyWithRetry(ctx context.Context, name string, userType IAMUserType, isGroup bool, m *xsync.MapOf[string, MappedPolicy], retries int) error
   507  	loadMappedPolicies(ctx context.Context, userType IAMUserType, isGroup bool, m *xsync.MapOf[string, MappedPolicy]) error
   508  	saveIAMConfig(ctx context.Context, item interface{}, path string, opts ...options) error
   509  	loadIAMConfig(ctx context.Context, item interface{}, path string) error
   510  	deleteIAMConfig(ctx context.Context, path string) error
   511  	savePolicyDoc(ctx context.Context, policyName string, p PolicyDoc) error
   512  	saveMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, mp MappedPolicy, opts ...options) error
   513  	saveUserIdentity(ctx context.Context, name string, userType IAMUserType, u UserIdentity, opts ...options) error
   514  	saveGroupInfo(ctx context.Context, group string, gi GroupInfo) error
   515  	deletePolicyDoc(ctx context.Context, policyName string) error
   516  	deleteMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool) error
   517  	deleteUserIdentity(ctx context.Context, name string, userType IAMUserType) error
   518  	deleteGroupInfo(ctx context.Context, name string) error
   519  }
   520  
   521  // iamStorageWatcher is implemented by `IAMStorageAPI` implementers that
   522  // additionally support watching storage for changes.
   523  type iamStorageWatcher interface {
   524  	watch(ctx context.Context, keyPath string) <-chan iamWatchEvent
   525  }
   526  
   527  // Set default canned policies only if not already overridden by users.
   528  func setDefaultCannedPolicies(policies map[string]PolicyDoc) {
   529  	for _, v := range policy.DefaultPolicies {
   530  		if _, ok := policies[v.Name]; !ok {
   531  			policies[v.Name] = defaultPolicyDoc(v.Definition)
   532  		}
   533  	}
   534  }
   535  
   536  // PurgeExpiredSTS - purges expired STS credentials.
   537  func (store *IAMStoreSys) PurgeExpiredSTS(ctx context.Context) error {
   538  	iamOS, ok := store.IAMStorageAPI.(*IAMObjectStore)
   539  	if !ok {
   540  		// No purging is done for non-object storage.
   541  		return nil
   542  	}
   543  	return iamOS.PurgeExpiredSTS(ctx)
   544  }
   545  
   546  // LoadIAMCache reads all IAM items and populates a new iamCache object and
   547  // replaces the in-memory cache object.
   548  func (store *IAMStoreSys) LoadIAMCache(ctx context.Context, firstTime bool) error {
   549  	bootstrapTraceMsg := func(s string) {
   550  		if firstTime {
   551  			bootstrapTraceMsg(s)
   552  		}
   553  	}
   554  	bootstrapTraceMsg("loading IAM data")
   555  
   556  	newCache := newIamCache()
   557  
   558  	loadedAt := time.Now()
   559  
   560  	if iamOS, ok := store.IAMStorageAPI.(*IAMObjectStore); ok {
   561  		err := iamOS.loadAllFromObjStore(ctx, newCache)
   562  		if err != nil {
   563  			return err
   564  		}
   565  	} else {
   566  
   567  		bootstrapTraceMsg("loading policy documents")
   568  		if err := store.loadPolicyDocs(ctx, newCache.iamPolicyDocsMap); err != nil {
   569  			return err
   570  		}
   571  
   572  		// Sets default canned policies, if none are set.
   573  		setDefaultCannedPolicies(newCache.iamPolicyDocsMap)
   574  
   575  		if store.getUsersSysType() == MinIOUsersSysType {
   576  			bootstrapTraceMsg("loading regular users")
   577  			if err := store.loadUsers(ctx, regUser, newCache.iamUsersMap); err != nil {
   578  				return err
   579  			}
   580  			bootstrapTraceMsg("loading regular groups")
   581  			if err := store.loadGroups(ctx, newCache.iamGroupsMap); err != nil {
   582  				return err
   583  			}
   584  		}
   585  
   586  		bootstrapTraceMsg("loading user policy mapping")
   587  		// load polices mapped to users
   588  		if err := store.loadMappedPolicies(ctx, regUser, false, newCache.iamUserPolicyMap); err != nil {
   589  			return err
   590  		}
   591  
   592  		bootstrapTraceMsg("loading group policy mapping")
   593  		// load policies mapped to groups
   594  		if err := store.loadMappedPolicies(ctx, regUser, true, newCache.iamGroupPolicyMap); err != nil {
   595  			return err
   596  		}
   597  
   598  		bootstrapTraceMsg("loading service accounts")
   599  		// load service accounts
   600  		if err := store.loadUsers(ctx, svcUser, newCache.iamUsersMap); err != nil {
   601  			return err
   602  		}
   603  
   604  		newCache.buildUserGroupMemberships()
   605  	}
   606  
   607  	cache := store.lock()
   608  	defer store.unlock()
   609  
   610  	// We should only update the in-memory cache if there were no changes
   611  	// to the in-memory cache since the disk loading began. If there
   612  	// were changes to the in-memory cache we should wait for the next
   613  	// cycle until we can safely update the in-memory cache.
   614  	//
   615  	// An in-memory cache must be replaced only if we know for sure that the
   616  	// values loaded from disk are not stale. They might be stale if the
   617  	// cached.updatedAt is more recent than the refresh cycle began.
   618  	if cache.updatedAt.Before(loadedAt) {
   619  		// No one has updated anything since the config was loaded,
   620  		// so we just replace whatever is on the disk into memory.
   621  		cache.iamGroupPolicyMap = newCache.iamGroupPolicyMap
   622  		cache.iamGroupsMap = newCache.iamGroupsMap
   623  		cache.iamPolicyDocsMap = newCache.iamPolicyDocsMap
   624  		cache.iamUserGroupMemberships = newCache.iamUserGroupMemberships
   625  		cache.iamUserPolicyMap = newCache.iamUserPolicyMap
   626  		cache.iamUsersMap = newCache.iamUsersMap
   627  		// For STS policy map, we need to merge the new cache with the existing
   628  		// cache because the periodic IAM reload is partial. The periodic load
   629  		// here is to account for STS policy mapping changes that should apply
   630  		// for service accounts derived from such STS accounts (i.e. LDAP STS
   631  		// accounts).
   632  		newCache.iamSTSPolicyMap.Range(func(k string, v MappedPolicy) bool {
   633  			cache.iamSTSPolicyMap.Store(k, v)
   634  			return true
   635  		})
   636  
   637  		cache.updatedAt = time.Now()
   638  	}
   639  
   640  	return nil
   641  }
   642  
   643  // IAMStoreSys contains IAMStorageAPI to add higher-level methods on the storage
   644  // layer.
   645  type IAMStoreSys struct {
   646  	IAMStorageAPI
   647  }
   648  
   649  // HasWatcher - returns if the storage system has a watcher.
   650  func (store *IAMStoreSys) HasWatcher() bool {
   651  	_, ok := store.IAMStorageAPI.(iamStorageWatcher)
   652  	return ok
   653  }
   654  
   655  // GetUser - fetches credential from memory.
   656  func (store *IAMStoreSys) GetUser(user string) (UserIdentity, bool) {
   657  	cache := store.rlock()
   658  	defer store.runlock()
   659  
   660  	u, ok := cache.iamUsersMap[user]
   661  	if !ok {
   662  		// Check the sts map
   663  		u, ok = cache.iamSTSAccountsMap[user]
   664  	}
   665  	return u, ok
   666  }
   667  
   668  // GetMappedPolicy - fetches mapped policy from memory.
   669  func (store *IAMStoreSys) GetMappedPolicy(name string, isGroup bool) (MappedPolicy, bool) {
   670  	cache := store.rlock()
   671  	defer store.runlock()
   672  
   673  	if isGroup {
   674  		v, ok := cache.iamGroupPolicyMap.Load(name)
   675  		return v, ok
   676  	}
   677  	return cache.iamUserPolicyMap.Load(name)
   678  }
   679  
   680  // GroupNotificationHandler - updates in-memory cache on notification of
   681  // change (e.g. peer notification for object storage and etcd watch
   682  // notification).
   683  func (store *IAMStoreSys) GroupNotificationHandler(ctx context.Context, group string) error {
   684  	cache := store.lock()
   685  	defer store.unlock()
   686  
   687  	err := store.loadGroup(ctx, group, cache.iamGroupsMap)
   688  	if err != nil && err != errNoSuchGroup {
   689  		return err
   690  	}
   691  
   692  	if err == errNoSuchGroup {
   693  		// group does not exist - so remove from memory.
   694  		cache.removeGroupFromMembershipsMap(group)
   695  		delete(cache.iamGroupsMap, group)
   696  		cache.iamGroupPolicyMap.Delete(group)
   697  
   698  		cache.updatedAt = time.Now()
   699  		return nil
   700  	}
   701  
   702  	gi := cache.iamGroupsMap[group]
   703  
   704  	// Updating the group memberships cache happens in two steps:
   705  	//
   706  	// 1. Remove the group from each user's list of memberships.
   707  	// 2. Add the group to each member's list of memberships.
   708  	//
   709  	// This ensures that regardless of members being added or
   710  	// removed, the cache stays current.
   711  	cache.removeGroupFromMembershipsMap(group)
   712  	cache.updateGroupMembershipsMap(group, &gi)
   713  	cache.updatedAt = time.Now()
   714  	return nil
   715  }
   716  
   717  // PolicyDBGet - fetches policies associated with the given user or group, and
   718  // additional groups if provided.
   719  func (store *IAMStoreSys) PolicyDBGet(name string, groups ...string) ([]string, error) {
   720  	if name == "" {
   721  		return nil, errInvalidArgument
   722  	}
   723  
   724  	cache := store.rlock()
   725  	defer store.runlock()
   726  
   727  	policies, _, err := cache.policyDBGet(store, name, false)
   728  	if err != nil {
   729  		return nil, err
   730  	}
   731  
   732  	for _, group := range groups {
   733  		ps, _, err := cache.policyDBGet(store, group, true)
   734  		if err != nil {
   735  			return nil, err
   736  		}
   737  		policies = append(policies, ps...)
   738  	}
   739  
   740  	return policies, nil
   741  }
   742  
   743  // AddUsersToGroup - adds users to group, creating the group if needed.
   744  func (store *IAMStoreSys) AddUsersToGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
   745  	if group == "" {
   746  		return updatedAt, errInvalidArgument
   747  	}
   748  
   749  	cache := store.lock()
   750  	defer store.unlock()
   751  
   752  	// Validate that all members exist.
   753  	for _, member := range members {
   754  		u, ok := cache.iamUsersMap[member]
   755  		if !ok {
   756  			return updatedAt, errNoSuchUser
   757  		}
   758  		cr := u.Credentials
   759  		if cr.IsTemp() || cr.IsServiceAccount() {
   760  			return updatedAt, errIAMActionNotAllowed
   761  		}
   762  	}
   763  
   764  	gi, ok := cache.iamGroupsMap[group]
   765  	if !ok {
   766  		// Set group as enabled by default when it doesn't
   767  		// exist.
   768  		gi = newGroupInfo(members)
   769  	} else {
   770  		gi.Members = set.CreateStringSet(append(gi.Members, members...)...).ToSlice()
   771  		gi.UpdatedAt = UTCNow()
   772  	}
   773  
   774  	if err := store.saveGroupInfo(ctx, group, gi); err != nil {
   775  		return updatedAt, err
   776  	}
   777  
   778  	cache.iamGroupsMap[group] = gi
   779  
   780  	// update user-group membership map
   781  	for _, member := range members {
   782  		gset := cache.iamUserGroupMemberships[member]
   783  		if gset == nil {
   784  			gset = set.CreateStringSet(group)
   785  		} else {
   786  			gset.Add(group)
   787  		}
   788  		cache.iamUserGroupMemberships[member] = gset
   789  	}
   790  
   791  	cache.updatedAt = time.Now()
   792  	return gi.UpdatedAt, nil
   793  }
   794  
   795  // helper function - does not take any locks. Updates only cache if
   796  // updateCacheOnly is set.
   797  func removeMembersFromGroup(ctx context.Context, store *IAMStoreSys, cache *iamCache, group string, members []string, updateCacheOnly bool) (updatedAt time.Time, err error) {
   798  	gi, ok := cache.iamGroupsMap[group]
   799  	if !ok {
   800  		return updatedAt, errNoSuchGroup
   801  	}
   802  
   803  	s := set.CreateStringSet(gi.Members...)
   804  	d := set.CreateStringSet(members...)
   805  	gi.Members = s.Difference(d).ToSlice()
   806  
   807  	if !updateCacheOnly {
   808  		err := store.saveGroupInfo(ctx, group, gi)
   809  		if err != nil {
   810  			return updatedAt, err
   811  		}
   812  	}
   813  	gi.UpdatedAt = UTCNow()
   814  	cache.iamGroupsMap[group] = gi
   815  
   816  	// update user-group membership map
   817  	for _, member := range members {
   818  		gset := cache.iamUserGroupMemberships[member]
   819  		if gset == nil {
   820  			continue
   821  		}
   822  		gset.Remove(group)
   823  		cache.iamUserGroupMemberships[member] = gset
   824  	}
   825  
   826  	cache.updatedAt = time.Now()
   827  	return gi.UpdatedAt, nil
   828  }
   829  
   830  // RemoveUsersFromGroup - removes users from group, deleting it if it is empty.
   831  func (store *IAMStoreSys) RemoveUsersFromGroup(ctx context.Context, group string, members []string) (updatedAt time.Time, err error) {
   832  	if group == "" {
   833  		return updatedAt, errInvalidArgument
   834  	}
   835  
   836  	cache := store.lock()
   837  	defer store.unlock()
   838  
   839  	// Validate that all members exist.
   840  	for _, member := range members {
   841  		u, ok := cache.iamUsersMap[member]
   842  		if !ok {
   843  			return updatedAt, errNoSuchUser
   844  		}
   845  		cr := u.Credentials
   846  		if cr.IsTemp() || cr.IsServiceAccount() {
   847  			return updatedAt, errIAMActionNotAllowed
   848  		}
   849  	}
   850  
   851  	gi, ok := cache.iamGroupsMap[group]
   852  	if !ok {
   853  		return updatedAt, errNoSuchGroup
   854  	}
   855  
   856  	// Check if attempting to delete a non-empty group.
   857  	if len(members) == 0 && len(gi.Members) != 0 {
   858  		return updatedAt, errGroupNotEmpty
   859  	}
   860  
   861  	if len(members) == 0 {
   862  		// len(gi.Members) == 0 here.
   863  
   864  		// Remove the group from storage. First delete the
   865  		// mapped policy. No-mapped-policy case is ignored.
   866  		if err := store.deleteMappedPolicy(ctx, group, regUser, true); err != nil && !errors.Is(err, errNoSuchPolicy) {
   867  			return updatedAt, err
   868  		}
   869  		if err := store.deleteGroupInfo(ctx, group); err != nil && err != errNoSuchGroup {
   870  			return updatedAt, err
   871  		}
   872  
   873  		// Delete from server memory
   874  		delete(cache.iamGroupsMap, group)
   875  		cache.iamGroupPolicyMap.Delete(group)
   876  		cache.updatedAt = time.Now()
   877  		return cache.updatedAt, nil
   878  	}
   879  
   880  	return removeMembersFromGroup(ctx, store, cache, group, members, false)
   881  }
   882  
   883  // SetGroupStatus - updates group status
   884  func (store *IAMStoreSys) SetGroupStatus(ctx context.Context, group string, enabled bool) (updatedAt time.Time, err error) {
   885  	if group == "" {
   886  		return updatedAt, errInvalidArgument
   887  	}
   888  
   889  	cache := store.lock()
   890  	defer store.unlock()
   891  
   892  	gi, ok := cache.iamGroupsMap[group]
   893  	if !ok {
   894  		return updatedAt, errNoSuchGroup
   895  	}
   896  
   897  	if enabled {
   898  		gi.Status = statusEnabled
   899  	} else {
   900  		gi.Status = statusDisabled
   901  	}
   902  	gi.UpdatedAt = UTCNow()
   903  	if err := store.saveGroupInfo(ctx, group, gi); err != nil {
   904  		return gi.UpdatedAt, err
   905  	}
   906  
   907  	cache.iamGroupsMap[group] = gi
   908  	cache.updatedAt = time.Now()
   909  
   910  	return gi.UpdatedAt, nil
   911  }
   912  
   913  // GetGroupDescription - builds up group description
   914  func (store *IAMStoreSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err error) {
   915  	cache := store.rlock()
   916  	defer store.runlock()
   917  
   918  	ps, updatedAt, err := cache.policyDBGet(store, group, true)
   919  	if err != nil {
   920  		return gd, err
   921  	}
   922  
   923  	policy := strings.Join(ps, ",")
   924  
   925  	if store.getUsersSysType() != MinIOUsersSysType {
   926  		return madmin.GroupDesc{
   927  			Name:      group,
   928  			Policy:    policy,
   929  			UpdatedAt: updatedAt,
   930  		}, nil
   931  	}
   932  
   933  	gi, ok := cache.iamGroupsMap[group]
   934  	if !ok {
   935  		return gd, errNoSuchGroup
   936  	}
   937  
   938  	return madmin.GroupDesc{
   939  		Name:      group,
   940  		Status:    gi.Status,
   941  		Members:   gi.Members,
   942  		Policy:    policy,
   943  		UpdatedAt: gi.UpdatedAt,
   944  	}, nil
   945  }
   946  
   947  // ListGroups - lists groups. Since this is not going to be a frequent
   948  // operation, we fetch this info from storage, and refresh the cache as well.
   949  func (store *IAMStoreSys) ListGroups(ctx context.Context) (res []string, err error) {
   950  	cache := store.lock()
   951  	defer store.unlock()
   952  
   953  	if store.getUsersSysType() == MinIOUsersSysType {
   954  		m := map[string]GroupInfo{}
   955  		err = store.loadGroups(ctx, m)
   956  		if err != nil {
   957  			return
   958  		}
   959  		cache.iamGroupsMap = m
   960  		cache.updatedAt = time.Now()
   961  		for k := range cache.iamGroupsMap {
   962  			res = append(res, k)
   963  		}
   964  	}
   965  
   966  	if store.getUsersSysType() == LDAPUsersSysType {
   967  		m := xsync.NewMapOf[string, MappedPolicy]()
   968  		err = store.loadMappedPolicies(ctx, stsUser, true, m)
   969  		if err != nil {
   970  			return
   971  		}
   972  		cache.iamGroupPolicyMap = m
   973  		cache.updatedAt = time.Now()
   974  		cache.iamGroupPolicyMap.Range(func(k string, v MappedPolicy) bool {
   975  			res = append(res, k)
   976  			return true
   977  		})
   978  	}
   979  
   980  	return
   981  }
   982  
   983  // listGroups - lists groups - fetch groups from cache
   984  func (store *IAMStoreSys) listGroups(ctx context.Context) (res []string, err error) {
   985  	cache := store.rlock()
   986  	defer store.runlock()
   987  
   988  	if store.getUsersSysType() == MinIOUsersSysType {
   989  		for k := range cache.iamGroupsMap {
   990  			res = append(res, k)
   991  		}
   992  	}
   993  
   994  	if store.getUsersSysType() == LDAPUsersSysType {
   995  		cache.iamGroupPolicyMap.Range(func(k string, _ MappedPolicy) bool {
   996  			res = append(res, k)
   997  			return true
   998  		})
   999  	}
  1000  	return
  1001  }
  1002  
  1003  // PolicyDBUpdate - adds or removes given policies to/from the user or group's
  1004  // policy associations.
  1005  func (store *IAMStoreSys) PolicyDBUpdate(ctx context.Context, name string, isGroup bool,
  1006  	userType IAMUserType, policies []string, isAttach bool) (updatedAt time.Time,
  1007  	addedOrRemoved, effectivePolicies []string, err error,
  1008  ) {
  1009  	if name == "" {
  1010  		err = errInvalidArgument
  1011  		return
  1012  	}
  1013  
  1014  	cache := store.lock()
  1015  	defer store.unlock()
  1016  
  1017  	// Load existing policy mapping
  1018  	var mp MappedPolicy
  1019  	if !isGroup {
  1020  		if userType == stsUser {
  1021  			stsMap := xsync.NewMapOf[string, MappedPolicy]()
  1022  
  1023  			// Attempt to load parent user mapping for STS accounts
  1024  			store.loadMappedPolicy(context.TODO(), name, stsUser, false, stsMap)
  1025  
  1026  			mp, _ = stsMap.Load(name)
  1027  		} else {
  1028  			mp, _ = cache.iamUserPolicyMap.Load(name)
  1029  		}
  1030  	} else {
  1031  		if store.getUsersSysType() == MinIOUsersSysType {
  1032  			g, ok := cache.iamGroupsMap[name]
  1033  			if !ok {
  1034  				err = errNoSuchGroup
  1035  				return
  1036  			}
  1037  
  1038  			if g.Status == statusDisabled {
  1039  				err = errGroupDisabled
  1040  				return
  1041  			}
  1042  		}
  1043  		mp, _ = cache.iamGroupPolicyMap.Load(name)
  1044  	}
  1045  
  1046  	// Compute net policy change effect and updated policy mapping
  1047  	existingPolicySet := mp.policySet()
  1048  	policiesToUpdate := set.CreateStringSet(policies...)
  1049  	var newPolicySet set.StringSet
  1050  	newPolicyMapping := mp
  1051  	if isAttach {
  1052  		// new policies to attach => inputPolicies - existing (set difference)
  1053  		policiesToUpdate = policiesToUpdate.Difference(existingPolicySet)
  1054  		// validate that new policies to add are defined.
  1055  		for _, p := range policiesToUpdate.ToSlice() {
  1056  			if _, found := cache.iamPolicyDocsMap[p]; !found {
  1057  				err = errNoSuchPolicy
  1058  				return
  1059  			}
  1060  		}
  1061  		newPolicySet = existingPolicySet.Union(policiesToUpdate)
  1062  	} else {
  1063  		// policies to detach => inputPolicies ∩ existing (intersection)
  1064  		policiesToUpdate = policiesToUpdate.Intersection(existingPolicySet)
  1065  		newPolicySet = existingPolicySet.Difference(policiesToUpdate)
  1066  	}
  1067  	// We return an error if the requested policy update will have no effect.
  1068  	if policiesToUpdate.IsEmpty() {
  1069  		err = errNoPolicyToAttachOrDetach
  1070  		return
  1071  	}
  1072  
  1073  	newPolicies := newPolicySet.ToSlice()
  1074  	newPolicyMapping.Policies = strings.Join(newPolicies, ",")
  1075  	newPolicyMapping.UpdatedAt = UTCNow()
  1076  	addedOrRemoved = policiesToUpdate.ToSlice()
  1077  
  1078  	// In case of detach operation, it is possible that no policies are mapped -
  1079  	// in this case, we delete the mapping from the store.
  1080  	if len(newPolicies) == 0 {
  1081  		if err = store.deleteMappedPolicy(ctx, name, userType, isGroup); err != nil && !errors.Is(err, errNoSuchPolicy) {
  1082  			return
  1083  		}
  1084  		if !isGroup {
  1085  			if userType == stsUser {
  1086  				cache.iamSTSPolicyMap.Delete(name)
  1087  			} else {
  1088  				cache.iamUserPolicyMap.Delete(name)
  1089  			}
  1090  		} else {
  1091  			cache.iamGroupPolicyMap.Delete(name)
  1092  		}
  1093  	} else {
  1094  
  1095  		if err = store.saveMappedPolicy(ctx, name, userType, isGroup, newPolicyMapping); err != nil {
  1096  			return
  1097  		}
  1098  		if !isGroup {
  1099  			if userType == stsUser {
  1100  				cache.iamSTSPolicyMap.Store(name, newPolicyMapping)
  1101  			} else {
  1102  				cache.iamUserPolicyMap.Store(name, newPolicyMapping)
  1103  			}
  1104  		} else {
  1105  			cache.iamGroupPolicyMap.Store(name, newPolicyMapping)
  1106  		}
  1107  	}
  1108  
  1109  	cache.updatedAt = UTCNow()
  1110  	return cache.updatedAt, addedOrRemoved, newPolicies, nil
  1111  }
  1112  
  1113  // PolicyDBSet - update the policy mapping for the given user or group in
  1114  // storage and in cache. We do not check for the existence of the user here
  1115  // since users can be virtual, such as for:
  1116  //   - LDAP users
  1117  //   - CommonName for STS accounts generated by AssumeRoleWithCertificate
  1118  func (store *IAMStoreSys) PolicyDBSet(ctx context.Context, name, policy string, userType IAMUserType, isGroup bool) (updatedAt time.Time, err error) {
  1119  	if name == "" {
  1120  		return updatedAt, errInvalidArgument
  1121  	}
  1122  
  1123  	cache := store.lock()
  1124  	defer store.unlock()
  1125  
  1126  	// Handle policy mapping removal.
  1127  	if policy == "" {
  1128  		if store.getUsersSysType() == LDAPUsersSysType {
  1129  			// Add a fallback removal towards previous content that may come back
  1130  			// as a ghost user due to lack of delete, this change occurred
  1131  			// introduced in PR #11840
  1132  			store.deleteMappedPolicy(ctx, name, regUser, false)
  1133  		}
  1134  		err := store.deleteMappedPolicy(ctx, name, userType, isGroup)
  1135  		if err != nil && !errors.Is(err, errNoSuchPolicy) {
  1136  			return updatedAt, err
  1137  		}
  1138  		if !isGroup {
  1139  			if userType == stsUser {
  1140  				cache.iamSTSPolicyMap.Delete(name)
  1141  			} else {
  1142  				cache.iamUserPolicyMap.Delete(name)
  1143  			}
  1144  		} else {
  1145  			cache.iamGroupPolicyMap.Delete(name)
  1146  		}
  1147  		cache.updatedAt = time.Now()
  1148  		return cache.updatedAt, nil
  1149  	}
  1150  
  1151  	// Handle policy mapping set/update
  1152  	mp := newMappedPolicy(policy)
  1153  	for _, p := range mp.toSlice() {
  1154  		if _, found := cache.iamPolicyDocsMap[p]; !found {
  1155  			return updatedAt, errNoSuchPolicy
  1156  		}
  1157  	}
  1158  
  1159  	if err := store.saveMappedPolicy(ctx, name, userType, isGroup, mp); err != nil {
  1160  		return updatedAt, err
  1161  	}
  1162  	if !isGroup {
  1163  		if userType == stsUser {
  1164  			cache.iamSTSPolicyMap.Store(name, mp)
  1165  		} else {
  1166  			cache.iamUserPolicyMap.Store(name, mp)
  1167  		}
  1168  	} else {
  1169  		cache.iamGroupPolicyMap.Store(name, mp)
  1170  	}
  1171  	cache.updatedAt = time.Now()
  1172  	return mp.UpdatedAt, nil
  1173  }
  1174  
  1175  // PolicyNotificationHandler - loads given policy from storage. If not present,
  1176  // deletes from cache. This notification only reads from storage, and updates
  1177  // cache. When the notification is for a policy deletion, it updates the
  1178  // user-policy and group-policy maps as well.
  1179  func (store *IAMStoreSys) PolicyNotificationHandler(ctx context.Context, policy string) error {
  1180  	if policy == "" {
  1181  		return errInvalidArgument
  1182  	}
  1183  
  1184  	cache := store.lock()
  1185  	defer store.unlock()
  1186  
  1187  	err := store.loadPolicyDoc(ctx, policy, cache.iamPolicyDocsMap)
  1188  	if errors.Is(err, errNoSuchPolicy) {
  1189  		// policy was deleted, update cache.
  1190  		delete(cache.iamPolicyDocsMap, policy)
  1191  
  1192  		// update user policy map
  1193  		cache.iamUserPolicyMap.Range(func(u string, mp MappedPolicy) bool {
  1194  			pset := mp.policySet()
  1195  			if !pset.Contains(policy) {
  1196  				return true
  1197  			}
  1198  			if store.getUsersSysType() == MinIOUsersSysType {
  1199  				_, ok := cache.iamUsersMap[u]
  1200  				if !ok {
  1201  					// happens when account is deleted or
  1202  					// expired.
  1203  					cache.iamUserPolicyMap.Delete(u)
  1204  					return true
  1205  				}
  1206  			}
  1207  			pset.Remove(policy)
  1208  			cache.iamUserPolicyMap.Store(u, newMappedPolicy(strings.Join(pset.ToSlice(), ",")))
  1209  			return true
  1210  		})
  1211  
  1212  		// update group policy map
  1213  		cache.iamGroupPolicyMap.Range(func(g string, mp MappedPolicy) bool {
  1214  			pset := mp.policySet()
  1215  			if !pset.Contains(policy) {
  1216  				return true
  1217  			}
  1218  			pset.Remove(policy)
  1219  			cache.iamGroupPolicyMap.Store(g, newMappedPolicy(strings.Join(pset.ToSlice(), ",")))
  1220  			return true
  1221  		})
  1222  
  1223  		cache.updatedAt = time.Now()
  1224  		return nil
  1225  	}
  1226  	return err
  1227  }
  1228  
  1229  // DeletePolicy - deletes policy from storage and cache. When this called in
  1230  // response to a notification (i.e. isFromNotification = true), it skips the
  1231  // validation of policy usage and the attempt to delete in the backend as well
  1232  // (as this is already done by the notifying node).
  1233  func (store *IAMStoreSys) DeletePolicy(ctx context.Context, policy string, isFromNotification bool) error {
  1234  	if policy == "" {
  1235  		return errInvalidArgument
  1236  	}
  1237  
  1238  	cache := store.lock()
  1239  	defer store.unlock()
  1240  
  1241  	if !isFromNotification {
  1242  		// Check if policy is mapped to any existing user or group. If so, we do not
  1243  		// allow deletion of the policy. If the policy is mapped to an STS account,
  1244  		// we do allow deletion.
  1245  		users := []string{}
  1246  		groups := []string{}
  1247  		cache.iamUserPolicyMap.Range(func(u string, mp MappedPolicy) bool {
  1248  			pset := mp.policySet()
  1249  			if store.getUsersSysType() == MinIOUsersSysType {
  1250  				if _, ok := cache.iamUsersMap[u]; !ok {
  1251  					// This case can happen when a temporary account is
  1252  					// deleted or expired - remove it from userPolicyMap.
  1253  					cache.iamUserPolicyMap.Delete(u)
  1254  					return true
  1255  				}
  1256  			}
  1257  			if pset.Contains(policy) {
  1258  				users = append(users, u)
  1259  			}
  1260  			return true
  1261  		})
  1262  		cache.iamGroupPolicyMap.Range(func(g string, mp MappedPolicy) bool {
  1263  			pset := mp.policySet()
  1264  			if pset.Contains(policy) {
  1265  				groups = append(groups, g)
  1266  			}
  1267  			return true
  1268  		})
  1269  		if len(users) != 0 || len(groups) != 0 {
  1270  			return errPolicyInUse
  1271  		}
  1272  
  1273  		err := store.deletePolicyDoc(ctx, policy)
  1274  		if errors.Is(err, errNoSuchPolicy) {
  1275  			// Ignore error if policy is already deleted.
  1276  			err = nil
  1277  		}
  1278  		if err != nil {
  1279  			return err
  1280  		}
  1281  	}
  1282  
  1283  	delete(cache.iamPolicyDocsMap, policy)
  1284  	cache.updatedAt = time.Now()
  1285  
  1286  	return nil
  1287  }
  1288  
  1289  // GetPolicy - gets the policy definition. Allows specifying multiple comma
  1290  // separated policies - returns a combined policy.
  1291  func (store *IAMStoreSys) GetPolicy(name string) (policy.Policy, error) {
  1292  	if name == "" {
  1293  		return policy.Policy{}, errInvalidArgument
  1294  	}
  1295  
  1296  	cache := store.rlock()
  1297  	defer store.runlock()
  1298  
  1299  	policies := newMappedPolicy(name).toSlice()
  1300  	var toMerge []policy.Policy
  1301  	for _, policy := range policies {
  1302  		if policy == "" {
  1303  			continue
  1304  		}
  1305  		v, ok := cache.iamPolicyDocsMap[policy]
  1306  		if !ok {
  1307  			return v.Policy, errNoSuchPolicy
  1308  		}
  1309  		toMerge = append(toMerge, v.Policy)
  1310  	}
  1311  	if len(toMerge) == 0 {
  1312  		return policy.Policy{}, errNoSuchPolicy
  1313  	}
  1314  	return policy.MergePolicies(toMerge...), nil
  1315  }
  1316  
  1317  // GetPolicyDoc - gets the policy doc which has the policy and some metadata.
  1318  // Exactly one policy must be specified here.
  1319  func (store *IAMStoreSys) GetPolicyDoc(name string) (r PolicyDoc, err error) {
  1320  	name = strings.TrimSpace(name)
  1321  	if name == "" {
  1322  		return r, errInvalidArgument
  1323  	}
  1324  
  1325  	cache := store.rlock()
  1326  	defer store.runlock()
  1327  
  1328  	v, ok := cache.iamPolicyDocsMap[name]
  1329  	if !ok {
  1330  		return r, errNoSuchPolicy
  1331  	}
  1332  	return v, nil
  1333  }
  1334  
  1335  // SetPolicy - creates a policy with name.
  1336  func (store *IAMStoreSys) SetPolicy(ctx context.Context, name string, policy policy.Policy) (time.Time, error) {
  1337  	if policy.IsEmpty() || name == "" {
  1338  		return time.Time{}, errInvalidArgument
  1339  	}
  1340  
  1341  	cache := store.lock()
  1342  	defer store.unlock()
  1343  
  1344  	var (
  1345  		d  PolicyDoc
  1346  		ok bool
  1347  	)
  1348  	if d, ok = cache.iamPolicyDocsMap[name]; ok {
  1349  		d.update(policy)
  1350  	} else {
  1351  		d = newPolicyDoc(policy)
  1352  	}
  1353  
  1354  	if err := store.savePolicyDoc(ctx, name, d); err != nil {
  1355  		return d.UpdateDate, err
  1356  	}
  1357  
  1358  	cache.iamPolicyDocsMap[name] = d
  1359  	cache.updatedAt = time.Now()
  1360  
  1361  	return d.UpdateDate, nil
  1362  }
  1363  
  1364  // ListPolicies - fetches all policies from storage and updates cache as well.
  1365  // If bucketName is non-empty, returns policies matching the bucket.
  1366  func (store *IAMStoreSys) ListPolicies(ctx context.Context, bucketName string) (map[string]policy.Policy, error) {
  1367  	cache := store.lock()
  1368  	defer store.unlock()
  1369  
  1370  	m := map[string]PolicyDoc{}
  1371  	err := store.loadPolicyDocs(ctx, m)
  1372  	if err != nil {
  1373  		return nil, err
  1374  	}
  1375  
  1376  	// Sets default canned policies
  1377  	setDefaultCannedPolicies(m)
  1378  
  1379  	cache.iamPolicyDocsMap = m
  1380  	cache.updatedAt = time.Now()
  1381  
  1382  	ret := map[string]policy.Policy{}
  1383  	for k, v := range m {
  1384  		if bucketName == "" || v.Policy.MatchResource(bucketName) {
  1385  			ret[k] = v.Policy
  1386  		}
  1387  	}
  1388  
  1389  	return ret, nil
  1390  }
  1391  
  1392  // ListPolicyDocs - fetches all policy docs from storage and updates cache as well.
  1393  // If bucketName is non-empty, returns policy docs matching the bucket.
  1394  func (store *IAMStoreSys) ListPolicyDocs(ctx context.Context, bucketName string) (map[string]PolicyDoc, error) {
  1395  	cache := store.lock()
  1396  	defer store.unlock()
  1397  
  1398  	m := map[string]PolicyDoc{}
  1399  	err := store.loadPolicyDocs(ctx, m)
  1400  	if err != nil {
  1401  		return nil, err
  1402  	}
  1403  
  1404  	// Sets default canned policies
  1405  	setDefaultCannedPolicies(m)
  1406  
  1407  	cache.iamPolicyDocsMap = m
  1408  	cache.updatedAt = time.Now()
  1409  
  1410  	ret := map[string]PolicyDoc{}
  1411  	for k, v := range m {
  1412  		if bucketName == "" || v.Policy.MatchResource(bucketName) {
  1413  			ret[k] = v
  1414  		}
  1415  	}
  1416  
  1417  	return ret, nil
  1418  }
  1419  
  1420  // fetches all policy docs from cache.
  1421  // If bucketName is non-empty, returns policy docs matching the bucket.
  1422  func (store *IAMStoreSys) listPolicyDocs(ctx context.Context, bucketName string) (map[string]PolicyDoc, error) {
  1423  	cache := store.rlock()
  1424  	defer store.runlock()
  1425  	ret := map[string]PolicyDoc{}
  1426  	for k, v := range cache.iamPolicyDocsMap {
  1427  		if bucketName == "" || v.Policy.MatchResource(bucketName) {
  1428  			ret[k] = v
  1429  		}
  1430  	}
  1431  	return ret, nil
  1432  }
  1433  
  1434  // helper function - does not take locks.
  1435  func filterPolicies(cache *iamCache, policyName string, bucketName string) (string, policy.Policy) {
  1436  	var policies []string
  1437  	mp := newMappedPolicy(policyName)
  1438  	var toMerge []policy.Policy
  1439  	for _, policy := range mp.toSlice() {
  1440  		if policy == "" {
  1441  			continue
  1442  		}
  1443  		p, found := cache.iamPolicyDocsMap[policy]
  1444  		if !found {
  1445  			continue
  1446  		}
  1447  		if bucketName == "" || p.Policy.MatchResource(bucketName) {
  1448  			policies = append(policies, policy)
  1449  			toMerge = append(toMerge, p.Policy)
  1450  		}
  1451  	}
  1452  	return strings.Join(policies, ","), policy.MergePolicies(toMerge...)
  1453  }
  1454  
  1455  // FilterPolicies - accepts a comma separated list of policy names as a string
  1456  // and bucket and returns only policies that currently exist in MinIO. If
  1457  // bucketName is non-empty, additionally filters policies matching the bucket.
  1458  // The first returned value is the list of currently existing policies, and the
  1459  // second is their combined policy definition.
  1460  func (store *IAMStoreSys) FilterPolicies(policyName string, bucketName string) (string, policy.Policy) {
  1461  	cache := store.rlock()
  1462  	defer store.runlock()
  1463  
  1464  	return filterPolicies(cache, policyName, bucketName)
  1465  }
  1466  
  1467  // GetBucketUsers - returns users (not STS or service accounts) that have access
  1468  // to the bucket. User is included even if a group policy that grants access to
  1469  // the bucket is disabled.
  1470  func (store *IAMStoreSys) GetBucketUsers(bucket string) (map[string]madmin.UserInfo, error) {
  1471  	if bucket == "" {
  1472  		return nil, errInvalidArgument
  1473  	}
  1474  
  1475  	cache := store.rlock()
  1476  	defer store.runlock()
  1477  
  1478  	result := map[string]madmin.UserInfo{}
  1479  	for k, v := range cache.iamUsersMap {
  1480  		c := v.Credentials
  1481  		if c.IsTemp() || c.IsServiceAccount() {
  1482  			continue
  1483  		}
  1484  		var policies []string
  1485  		mp, ok := cache.iamUserPolicyMap.Load(k)
  1486  		if ok {
  1487  			policies = append(policies, mp.Policies)
  1488  			for _, group := range cache.iamUserGroupMemberships[k].ToSlice() {
  1489  				if nmp, ok := cache.iamGroupPolicyMap.Load(group); ok {
  1490  					policies = append(policies, nmp.Policies)
  1491  				}
  1492  			}
  1493  		}
  1494  		matchedPolicies, _ := filterPolicies(cache, strings.Join(policies, ","), bucket)
  1495  		if len(matchedPolicies) > 0 {
  1496  			result[k] = madmin.UserInfo{
  1497  				PolicyName: matchedPolicies,
  1498  				Status: func() madmin.AccountStatus {
  1499  					if c.IsValid() {
  1500  						return madmin.AccountEnabled
  1501  					}
  1502  					return madmin.AccountDisabled
  1503  				}(),
  1504  				MemberOf: cache.iamUserGroupMemberships[k].ToSlice(),
  1505  			}
  1506  		}
  1507  	}
  1508  
  1509  	return result, nil
  1510  }
  1511  
  1512  // GetUsers - returns all users (not STS or service accounts).
  1513  func (store *IAMStoreSys) GetUsers() map[string]madmin.UserInfo {
  1514  	cache := store.rlock()
  1515  	defer store.runlock()
  1516  
  1517  	result := map[string]madmin.UserInfo{}
  1518  	for k, u := range cache.iamUsersMap {
  1519  		v := u.Credentials
  1520  
  1521  		if v.IsTemp() || v.IsServiceAccount() {
  1522  			continue
  1523  		}
  1524  		pl, _ := cache.iamUserPolicyMap.Load(k)
  1525  		result[k] = madmin.UserInfo{
  1526  			PolicyName: pl.Policies,
  1527  			Status: func() madmin.AccountStatus {
  1528  				if v.IsValid() {
  1529  					return madmin.AccountEnabled
  1530  				}
  1531  				return madmin.AccountDisabled
  1532  			}(),
  1533  			MemberOf:  cache.iamUserGroupMemberships[k].ToSlice(),
  1534  			UpdatedAt: pl.UpdatedAt,
  1535  		}
  1536  	}
  1537  
  1538  	return result
  1539  }
  1540  
  1541  // GetUsersWithMappedPolicies - safely returns the name of access keys with associated policies
  1542  func (store *IAMStoreSys) GetUsersWithMappedPolicies() map[string]string {
  1543  	cache := store.rlock()
  1544  	defer store.runlock()
  1545  
  1546  	result := make(map[string]string)
  1547  	cache.iamUserPolicyMap.Range(func(k string, v MappedPolicy) bool {
  1548  		result[k] = v.Policies
  1549  		return true
  1550  	})
  1551  	cache.iamSTSPolicyMap.Range(func(k string, v MappedPolicy) bool {
  1552  		result[k] = v.Policies
  1553  		return true
  1554  	})
  1555  	return result
  1556  }
  1557  
  1558  // GetUserInfo - get info on a user.
  1559  func (store *IAMStoreSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
  1560  	if name == "" {
  1561  		return u, errInvalidArgument
  1562  	}
  1563  
  1564  	cache := store.rlock()
  1565  	defer store.runlock()
  1566  
  1567  	if store.getUsersSysType() != MinIOUsersSysType {
  1568  		// If the user has a mapped policy or is a member of a group, we
  1569  		// return that info. Otherwise we return error.
  1570  		var groups []string
  1571  		for _, v := range cache.iamUsersMap {
  1572  			if v.Credentials.ParentUser == name {
  1573  				groups = v.Credentials.Groups
  1574  				break
  1575  			}
  1576  		}
  1577  		for _, v := range cache.iamSTSAccountsMap {
  1578  			if v.Credentials.ParentUser == name {
  1579  				groups = v.Credentials.Groups
  1580  				break
  1581  			}
  1582  		}
  1583  		mappedPolicy, ok := cache.iamUserPolicyMap.Load(name)
  1584  		if !ok {
  1585  			mappedPolicy, ok = cache.iamSTSPolicyMap.Load(name)
  1586  		}
  1587  		if !ok {
  1588  			// Attempt to load parent user mapping for STS accounts
  1589  			store.loadMappedPolicy(context.TODO(), name, stsUser, false, cache.iamSTSPolicyMap)
  1590  			mappedPolicy, ok = cache.iamSTSPolicyMap.Load(name)
  1591  			if !ok {
  1592  				return u, errNoSuchUser
  1593  			}
  1594  		}
  1595  
  1596  		return madmin.UserInfo{
  1597  			PolicyName: mappedPolicy.Policies,
  1598  			MemberOf:   groups,
  1599  			UpdatedAt:  mappedPolicy.UpdatedAt,
  1600  		}, nil
  1601  	}
  1602  
  1603  	ui, found := cache.iamUsersMap[name]
  1604  	if !found {
  1605  		return u, errNoSuchUser
  1606  	}
  1607  	cred := ui.Credentials
  1608  	if cred.IsTemp() || cred.IsServiceAccount() {
  1609  		return u, errIAMActionNotAllowed
  1610  	}
  1611  	pl, _ := cache.iamUserPolicyMap.Load(name)
  1612  	return madmin.UserInfo{
  1613  		PolicyName: pl.Policies,
  1614  		Status: func() madmin.AccountStatus {
  1615  			if cred.IsValid() {
  1616  				return madmin.AccountEnabled
  1617  			}
  1618  			return madmin.AccountDisabled
  1619  		}(),
  1620  		MemberOf:  cache.iamUserGroupMemberships[name].ToSlice(),
  1621  		UpdatedAt: pl.UpdatedAt,
  1622  	}, nil
  1623  }
  1624  
  1625  // PolicyMappingNotificationHandler - handles updating a policy mapping from storage.
  1626  func (store *IAMStoreSys) PolicyMappingNotificationHandler(ctx context.Context, userOrGroup string, isGroup bool, userType IAMUserType) error {
  1627  	if userOrGroup == "" {
  1628  		return errInvalidArgument
  1629  	}
  1630  
  1631  	cache := store.lock()
  1632  	defer store.unlock()
  1633  
  1634  	var m *xsync.MapOf[string, MappedPolicy]
  1635  	switch {
  1636  	case isGroup:
  1637  		m = cache.iamGroupPolicyMap
  1638  	default:
  1639  		m = cache.iamUserPolicyMap
  1640  	}
  1641  	err := store.loadMappedPolicy(ctx, userOrGroup, userType, isGroup, m)
  1642  	if errors.Is(err, errNoSuchPolicy) {
  1643  		// This means that the policy mapping was deleted, so we update
  1644  		// the cache.
  1645  		m.Delete(userOrGroup)
  1646  		cache.updatedAt = time.Now()
  1647  
  1648  		err = nil
  1649  	}
  1650  	return err
  1651  }
  1652  
  1653  // UserNotificationHandler - handles updating a user/STS account/service account
  1654  // from storage.
  1655  func (store *IAMStoreSys) UserNotificationHandler(ctx context.Context, accessKey string, userType IAMUserType) error {
  1656  	if accessKey == "" {
  1657  		return errInvalidArgument
  1658  	}
  1659  
  1660  	cache := store.lock()
  1661  	defer store.unlock()
  1662  
  1663  	var m map[string]UserIdentity
  1664  	switch userType {
  1665  	case stsUser:
  1666  		m = cache.iamSTSAccountsMap
  1667  	default:
  1668  		m = cache.iamUsersMap
  1669  	}
  1670  	err := store.loadUser(ctx, accessKey, userType, m)
  1671  
  1672  	if err == errNoSuchUser {
  1673  		// User was deleted - we update the cache.
  1674  		delete(m, accessKey)
  1675  
  1676  		// Since cache was updated, we update the timestamp.
  1677  		defer func() {
  1678  			cache.updatedAt = time.Now()
  1679  		}()
  1680  
  1681  		// 1. Start with updating user-group memberships
  1682  		if store.getUsersSysType() == MinIOUsersSysType {
  1683  			memberOf := cache.iamUserGroupMemberships[accessKey].ToSlice()
  1684  			for _, group := range memberOf {
  1685  				_, removeErr := removeMembersFromGroup(ctx, store, cache, group, []string{accessKey}, true)
  1686  				if removeErr == errNoSuchGroup {
  1687  					removeErr = nil
  1688  				}
  1689  				if removeErr != nil {
  1690  					return removeErr
  1691  				}
  1692  			}
  1693  		}
  1694  
  1695  		// 2. Remove any derived credentials from memory
  1696  		if userType == regUser {
  1697  			for k, u := range cache.iamUsersMap {
  1698  				if u.Credentials.IsServiceAccount() && u.Credentials.ParentUser == accessKey {
  1699  					delete(cache.iamUsersMap, k)
  1700  				}
  1701  			}
  1702  			for k, u := range cache.iamSTSAccountsMap {
  1703  				if u.Credentials.ParentUser == accessKey {
  1704  					delete(cache.iamSTSAccountsMap, k)
  1705  				}
  1706  			}
  1707  		}
  1708  
  1709  		// 3. Delete any mapped policy
  1710  		cache.iamUserPolicyMap.Delete(accessKey)
  1711  
  1712  		return nil
  1713  	}
  1714  
  1715  	if err != nil {
  1716  		return err
  1717  	}
  1718  
  1719  	// Since cache was updated, we update the timestamp.
  1720  	defer func() {
  1721  		cache.updatedAt = time.Now()
  1722  	}()
  1723  
  1724  	cred := m[accessKey].Credentials
  1725  	switch userType {
  1726  	case stsUser:
  1727  		// For STS accounts a policy is mapped to the parent user (if a mapping exists).
  1728  		err = store.loadMappedPolicy(ctx, cred.ParentUser, userType, false, cache.iamSTSPolicyMap)
  1729  	case svcUser:
  1730  		// For service accounts, the parent may be a regular (internal) IDP
  1731  		// user or a "virtual" user (parent of an STS account).
  1732  		//
  1733  		// If parent is a regular user => policy mapping is done on that parent itself.
  1734  		//
  1735  		// If parent is "virtual" => policy mapping is done on the virtual
  1736  		// parent and that virtual parent is an stsUser.
  1737  		//
  1738  		// To load the appropriate mapping, we check the parent user type.
  1739  		_, parentIsRegularUser := cache.iamUsersMap[cred.ParentUser]
  1740  		if parentIsRegularUser {
  1741  			err = store.loadMappedPolicy(ctx, cred.ParentUser, regUser, false, cache.iamUserPolicyMap)
  1742  		} else {
  1743  			err = store.loadMappedPolicy(ctx, cred.ParentUser, stsUser, false, cache.iamSTSPolicyMap)
  1744  		}
  1745  	case regUser:
  1746  		// For regular users, we load the mapped policy.
  1747  		err = store.loadMappedPolicy(ctx, accessKey, userType, false, cache.iamUserPolicyMap)
  1748  	default:
  1749  		// This is just to ensure that we have covered all cases for new
  1750  		// code in future.
  1751  		panic("unknown user type")
  1752  	}
  1753  	// Ignore policy not mapped error
  1754  	if err != nil && !errors.Is(err, errNoSuchPolicy) {
  1755  		return err
  1756  	}
  1757  
  1758  	return nil
  1759  }
  1760  
  1761  // DeleteUser - deletes a user from storage and cache. This only used with
  1762  // long-term users and service accounts, not STS.
  1763  func (store *IAMStoreSys) DeleteUser(ctx context.Context, accessKey string, userType IAMUserType) error {
  1764  	if accessKey == "" {
  1765  		return errInvalidArgument
  1766  	}
  1767  
  1768  	cache := store.lock()
  1769  	defer store.unlock()
  1770  
  1771  	// first we remove the user from their groups.
  1772  	if store.getUsersSysType() == MinIOUsersSysType && userType == regUser {
  1773  		memberOf := cache.iamUserGroupMemberships[accessKey].ToSlice()
  1774  		for _, group := range memberOf {
  1775  			_, removeErr := removeMembersFromGroup(ctx, store, cache, group, []string{accessKey}, false)
  1776  			if removeErr != nil {
  1777  				return removeErr
  1778  			}
  1779  		}
  1780  	}
  1781  
  1782  	// Now we can remove the user from memory and IAM store
  1783  
  1784  	// Delete any STS and service account derived from this credential
  1785  	// first.
  1786  	if userType == regUser {
  1787  		for _, ui := range cache.iamUsersMap {
  1788  			u := ui.Credentials
  1789  			if u.ParentUser == accessKey {
  1790  				switch {
  1791  				case u.IsServiceAccount():
  1792  					_ = store.deleteUserIdentity(ctx, u.AccessKey, svcUser)
  1793  					delete(cache.iamUsersMap, u.AccessKey)
  1794  				case u.IsTemp():
  1795  					_ = store.deleteUserIdentity(ctx, u.AccessKey, stsUser)
  1796  					delete(cache.iamUsersMap, u.AccessKey)
  1797  				}
  1798  			}
  1799  		}
  1800  	}
  1801  
  1802  	// It is ok to ignore deletion error on the mapped policy
  1803  	store.deleteMappedPolicy(ctx, accessKey, userType, false)
  1804  	cache.iamUserPolicyMap.Delete(accessKey)
  1805  
  1806  	err := store.deleteUserIdentity(ctx, accessKey, userType)
  1807  	if err == errNoSuchUser {
  1808  		// ignore if user is already deleted.
  1809  		err = nil
  1810  	}
  1811  	delete(cache.iamUsersMap, accessKey)
  1812  
  1813  	cache.updatedAt = time.Now()
  1814  
  1815  	return err
  1816  }
  1817  
  1818  // SetTempUser - saves temporary (STS) credential to storage and cache. If a
  1819  // policy name is given, it is associated with the parent user specified in the
  1820  // credential.
  1821  func (store *IAMStoreSys) SetTempUser(ctx context.Context, accessKey string, cred auth.Credentials, policyName string) (time.Time, error) {
  1822  	if accessKey == "" || !cred.IsTemp() || cred.IsExpired() || cred.ParentUser == "" {
  1823  		return time.Time{}, errInvalidArgument
  1824  	}
  1825  
  1826  	ttl := int64(cred.Expiration.Sub(UTCNow()).Seconds())
  1827  
  1828  	cache := store.lock()
  1829  	defer store.unlock()
  1830  
  1831  	if policyName != "" {
  1832  		mp := newMappedPolicy(policyName)
  1833  		_, combinedPolicyStmt := filterPolicies(cache, mp.Policies, "")
  1834  
  1835  		if combinedPolicyStmt.IsEmpty() {
  1836  			return time.Time{}, fmt.Errorf("specified policy %s, not found %w", policyName, errNoSuchPolicy)
  1837  		}
  1838  
  1839  		err := store.saveMappedPolicy(ctx, cred.ParentUser, stsUser, false, mp, options{ttl: ttl})
  1840  		if err != nil {
  1841  			return time.Time{}, err
  1842  		}
  1843  
  1844  		cache.iamSTSPolicyMap.Store(cred.ParentUser, mp)
  1845  	}
  1846  
  1847  	u := newUserIdentity(cred)
  1848  	err := store.saveUserIdentity(ctx, accessKey, stsUser, u, options{ttl: ttl})
  1849  	if err != nil {
  1850  		return time.Time{}, err
  1851  	}
  1852  
  1853  	cache.iamSTSAccountsMap[accessKey] = u
  1854  	cache.updatedAt = time.Now()
  1855  
  1856  	return u.UpdatedAt, nil
  1857  }
  1858  
  1859  // DeleteUsers - given a set of users or access keys, deletes them along with
  1860  // any derived credentials (STS or service accounts) and any associated policy
  1861  // mappings.
  1862  func (store *IAMStoreSys) DeleteUsers(ctx context.Context, users []string) error {
  1863  	cache := store.lock()
  1864  	defer store.unlock()
  1865  
  1866  	var deleted bool
  1867  	usersToDelete := set.CreateStringSet(users...)
  1868  	for user, ui := range cache.iamUsersMap {
  1869  		userType := regUser
  1870  		cred := ui.Credentials
  1871  
  1872  		if cred.IsServiceAccount() {
  1873  			userType = svcUser
  1874  		} else if cred.IsTemp() {
  1875  			userType = stsUser
  1876  		}
  1877  
  1878  		if usersToDelete.Contains(user) || usersToDelete.Contains(cred.ParentUser) {
  1879  			// Delete this user account and its policy mapping
  1880  			store.deleteMappedPolicy(ctx, user, userType, false)
  1881  			cache.iamUserPolicyMap.Delete(user)
  1882  
  1883  			// we are only logging errors, not handling them.
  1884  			err := store.deleteUserIdentity(ctx, user, userType)
  1885  			logger.LogIf(GlobalContext, err)
  1886  			delete(cache.iamUsersMap, user)
  1887  
  1888  			deleted = true
  1889  		}
  1890  	}
  1891  
  1892  	if deleted {
  1893  		cache.updatedAt = time.Now()
  1894  	}
  1895  
  1896  	return nil
  1897  }
  1898  
  1899  // ParentUserInfo contains extra info about a the parent user.
  1900  type ParentUserInfo struct {
  1901  	subClaimValue string
  1902  	roleArns      set.StringSet
  1903  }
  1904  
  1905  // GetAllParentUsers - returns all distinct "parent-users" associated with STS
  1906  // or service credentials, mapped to all distinct roleARNs associated with the
  1907  // parent user. The dummy role ARN is associated with parent users from
  1908  // policy-claim based OpenID providers.
  1909  func (store *IAMStoreSys) GetAllParentUsers() map[string]ParentUserInfo {
  1910  	cache := store.rlock()
  1911  	defer store.runlock()
  1912  
  1913  	res := map[string]ParentUserInfo{}
  1914  	for _, ui := range cache.iamUsersMap {
  1915  		cred := ui.Credentials
  1916  		// Only consider service account or STS credentials with
  1917  		// non-empty session tokens.
  1918  		if !(cred.IsServiceAccount() || cred.IsTemp()) ||
  1919  			cred.SessionToken == "" {
  1920  			continue
  1921  		}
  1922  
  1923  		var (
  1924  			err    error
  1925  			claims map[string]interface{} = cred.Claims
  1926  		)
  1927  
  1928  		if cred.IsServiceAccount() {
  1929  			claims, err = getClaimsFromTokenWithSecret(cred.SessionToken, cred.SecretKey)
  1930  		} else if cred.IsTemp() {
  1931  			var secretKey string
  1932  			secretKey, err = getTokenSigningKey()
  1933  			if err != nil {
  1934  				continue
  1935  			}
  1936  			claims, err = getClaimsFromTokenWithSecret(cred.SessionToken, secretKey)
  1937  		}
  1938  
  1939  		if err != nil {
  1940  			continue
  1941  		}
  1942  		if cred.ParentUser == "" {
  1943  			continue
  1944  		}
  1945  
  1946  		subClaimValue := cred.ParentUser
  1947  		if v, ok := claims[subClaim]; ok {
  1948  			subFromToken, ok := v.(string)
  1949  			if ok {
  1950  				subClaimValue = subFromToken
  1951  			}
  1952  		}
  1953  
  1954  		roleArn := openid.DummyRoleARN.String()
  1955  		s, ok := claims[roleArnClaim]
  1956  		val, ok2 := s.(string)
  1957  		if ok && ok2 {
  1958  			roleArn = val
  1959  		}
  1960  		v, ok := res[cred.ParentUser]
  1961  		if ok {
  1962  			res[cred.ParentUser] = ParentUserInfo{
  1963  				subClaimValue: subClaimValue,
  1964  				roleArns:      v.roleArns.Union(set.CreateStringSet(roleArn)),
  1965  			}
  1966  		} else {
  1967  			res[cred.ParentUser] = ParentUserInfo{
  1968  				subClaimValue: subClaimValue,
  1969  				roleArns:      set.CreateStringSet(roleArn),
  1970  			}
  1971  		}
  1972  	}
  1973  
  1974  	return res
  1975  }
  1976  
  1977  // Assumes store is locked by caller. If users is empty, returns all user mappings.
  1978  func (store *IAMStoreSys) listUserPolicyMappings(cache *iamCache, users []string,
  1979  	userPredicate func(string) bool,
  1980  ) []madmin.UserPolicyEntities {
  1981  	var r []madmin.UserPolicyEntities
  1982  	usersSet := set.CreateStringSet(users...)
  1983  	cache.iamUserPolicyMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
  1984  		if userPredicate != nil && !userPredicate(user) {
  1985  			return true
  1986  		}
  1987  
  1988  		if !usersSet.IsEmpty() && !usersSet.Contains(user) {
  1989  			return true
  1990  		}
  1991  
  1992  		ps := mappedPolicy.toSlice()
  1993  		sort.Strings(ps)
  1994  		r = append(r, madmin.UserPolicyEntities{
  1995  			User:     user,
  1996  			Policies: ps,
  1997  		})
  1998  		return true
  1999  	})
  2000  
  2001  	stsMap := xsync.NewMapOf[string, MappedPolicy]()
  2002  	for _, user := range users {
  2003  		// Attempt to load parent user mapping for STS accounts
  2004  		store.loadMappedPolicy(context.TODO(), user, stsUser, false, stsMap)
  2005  	}
  2006  
  2007  	stsMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
  2008  		if userPredicate != nil && !userPredicate(user) {
  2009  			return true
  2010  		}
  2011  
  2012  		ps := mappedPolicy.toSlice()
  2013  		sort.Strings(ps)
  2014  		r = append(r, madmin.UserPolicyEntities{
  2015  			User:     user,
  2016  			Policies: ps,
  2017  		})
  2018  		return true
  2019  	})
  2020  
  2021  	sort.Slice(r, func(i, j int) bool {
  2022  		return r[i].User < r[j].User
  2023  	})
  2024  
  2025  	return r
  2026  }
  2027  
  2028  // Assumes store is locked by caller. If groups is empty, returns all group mappings.
  2029  func (store *IAMStoreSys) listGroupPolicyMappings(cache *iamCache, groups []string,
  2030  	groupPredicate func(string) bool,
  2031  ) []madmin.GroupPolicyEntities {
  2032  	var r []madmin.GroupPolicyEntities
  2033  	groupsSet := set.CreateStringSet(groups...)
  2034  	cache.iamGroupPolicyMap.Range(func(group string, mappedPolicy MappedPolicy) bool {
  2035  		if groupPredicate != nil && !groupPredicate(group) {
  2036  			return true
  2037  		}
  2038  
  2039  		if !groupsSet.IsEmpty() && !groupsSet.Contains(group) {
  2040  			return true
  2041  		}
  2042  
  2043  		ps := mappedPolicy.toSlice()
  2044  		sort.Strings(ps)
  2045  		r = append(r, madmin.GroupPolicyEntities{
  2046  			Group:    group,
  2047  			Policies: ps,
  2048  		})
  2049  		return true
  2050  	})
  2051  
  2052  	sort.Slice(r, func(i, j int) bool {
  2053  		return r[i].Group < r[j].Group
  2054  	})
  2055  
  2056  	return r
  2057  }
  2058  
  2059  // Assumes store is locked by caller. If policies is empty, returns all policy mappings.
  2060  func (store *IAMStoreSys) listPolicyMappings(cache *iamCache, policies []string,
  2061  	userPredicate, groupPredicate func(string) bool,
  2062  ) []madmin.PolicyEntities {
  2063  	queryPolSet := set.CreateStringSet(policies...)
  2064  
  2065  	policyToUsersMap := make(map[string]set.StringSet)
  2066  	cache.iamUserPolicyMap.Range(func(user string, mappedPolicy MappedPolicy) bool {
  2067  		if userPredicate != nil && !userPredicate(user) {
  2068  			return true
  2069  		}
  2070  
  2071  		commonPolicySet := mappedPolicy.policySet()
  2072  		if !queryPolSet.IsEmpty() {
  2073  			commonPolicySet = commonPolicySet.Intersection(queryPolSet)
  2074  		}
  2075  		for _, policy := range commonPolicySet.ToSlice() {
  2076  			s, ok := policyToUsersMap[policy]
  2077  			if !ok {
  2078  				policyToUsersMap[policy] = set.CreateStringSet(user)
  2079  			} else {
  2080  				s.Add(user)
  2081  				policyToUsersMap[policy] = s
  2082  			}
  2083  		}
  2084  		return true
  2085  	})
  2086  
  2087  	if iamOS, ok := store.IAMStorageAPI.(*IAMObjectStore); ok {
  2088  		for item := range listIAMConfigItems(context.Background(), iamOS.objAPI, iamConfigPrefix+SlashSeparator+policyDBSTSUsersListKey) {
  2089  			user := strings.TrimSuffix(item.Item, ".json")
  2090  			if userPredicate != nil && !userPredicate(user) {
  2091  				continue
  2092  			}
  2093  
  2094  			var mappedPolicy MappedPolicy
  2095  			store.loadIAMConfig(context.Background(), &mappedPolicy, getMappedPolicyPath(user, stsUser, false))
  2096  
  2097  			commonPolicySet := mappedPolicy.policySet()
  2098  			if !queryPolSet.IsEmpty() {
  2099  				commonPolicySet = commonPolicySet.Intersection(queryPolSet)
  2100  			}
  2101  			for _, policy := range commonPolicySet.ToSlice() {
  2102  				s, ok := policyToUsersMap[policy]
  2103  				if !ok {
  2104  					policyToUsersMap[policy] = set.CreateStringSet(user)
  2105  				} else {
  2106  					s.Add(user)
  2107  					policyToUsersMap[policy] = s
  2108  				}
  2109  			}
  2110  		}
  2111  	}
  2112  
  2113  	policyToGroupsMap := make(map[string]set.StringSet)
  2114  	cache.iamGroupPolicyMap.Range(func(group string, mappedPolicy MappedPolicy) bool {
  2115  		if groupPredicate != nil && !groupPredicate(group) {
  2116  			return true
  2117  		}
  2118  
  2119  		commonPolicySet := mappedPolicy.policySet()
  2120  		if !queryPolSet.IsEmpty() {
  2121  			commonPolicySet = commonPolicySet.Intersection(queryPolSet)
  2122  		}
  2123  		for _, policy := range commonPolicySet.ToSlice() {
  2124  			s, ok := policyToGroupsMap[policy]
  2125  			if !ok {
  2126  				policyToGroupsMap[policy] = set.CreateStringSet(group)
  2127  			} else {
  2128  				s.Add(group)
  2129  				policyToGroupsMap[policy] = s
  2130  			}
  2131  		}
  2132  		return true
  2133  	})
  2134  
  2135  	m := make(map[string]madmin.PolicyEntities, len(policyToGroupsMap))
  2136  	for policy, groups := range policyToGroupsMap {
  2137  		s := groups.ToSlice()
  2138  		sort.Strings(s)
  2139  		m[policy] = madmin.PolicyEntities{
  2140  			Policy: policy,
  2141  			Groups: s,
  2142  		}
  2143  	}
  2144  	for policy, users := range policyToUsersMap {
  2145  		s := users.ToSlice()
  2146  		sort.Strings(s)
  2147  
  2148  		// Update existing value in map
  2149  		pe := m[policy]
  2150  		pe.Policy = policy
  2151  		pe.Users = s
  2152  		m[policy] = pe
  2153  	}
  2154  
  2155  	policyEntities := make([]madmin.PolicyEntities, 0, len(m))
  2156  	for _, v := range m {
  2157  		policyEntities = append(policyEntities, v)
  2158  	}
  2159  
  2160  	sort.Slice(policyEntities, func(i, j int) bool {
  2161  		return policyEntities[i].Policy < policyEntities[j].Policy
  2162  	})
  2163  
  2164  	return policyEntities
  2165  }
  2166  
  2167  // ListPolicyMappings - return users/groups mapped to policies.
  2168  func (store *IAMStoreSys) ListPolicyMappings(q madmin.PolicyEntitiesQuery,
  2169  	userPredicate, groupPredicate func(string) bool,
  2170  ) madmin.PolicyEntitiesResult {
  2171  	cache := store.rlock()
  2172  	defer store.runlock()
  2173  
  2174  	var result madmin.PolicyEntitiesResult
  2175  
  2176  	isAllPoliciesQuery := len(q.Users) == 0 && len(q.Groups) == 0 && len(q.Policy) == 0
  2177  
  2178  	if len(q.Users) > 0 {
  2179  		result.UserMappings = store.listUserPolicyMappings(cache, q.Users, userPredicate)
  2180  	}
  2181  	if len(q.Groups) > 0 {
  2182  		result.GroupMappings = store.listGroupPolicyMappings(cache, q.Groups, groupPredicate)
  2183  	}
  2184  	if len(q.Policy) > 0 || isAllPoliciesQuery {
  2185  		result.PolicyMappings = store.listPolicyMappings(cache, q.Policy, userPredicate, groupPredicate)
  2186  	}
  2187  	return result
  2188  }
  2189  
  2190  // SetUserStatus - sets current user status.
  2191  func (store *IAMStoreSys) SetUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) (updatedAt time.Time, err error) {
  2192  	if accessKey != "" && status != madmin.AccountEnabled && status != madmin.AccountDisabled {
  2193  		return updatedAt, errInvalidArgument
  2194  	}
  2195  
  2196  	cache := store.lock()
  2197  	defer store.unlock()
  2198  
  2199  	ui, ok := cache.iamUsersMap[accessKey]
  2200  	if !ok {
  2201  		return updatedAt, errNoSuchUser
  2202  	}
  2203  	cred := ui.Credentials
  2204  
  2205  	if cred.IsTemp() || cred.IsServiceAccount() {
  2206  		return updatedAt, errIAMActionNotAllowed
  2207  	}
  2208  
  2209  	uinfo := newUserIdentity(auth.Credentials{
  2210  		AccessKey: accessKey,
  2211  		SecretKey: cred.SecretKey,
  2212  		Status: func() string {
  2213  			switch string(status) {
  2214  			case string(madmin.AccountEnabled), string(auth.AccountOn):
  2215  				return auth.AccountOn
  2216  			}
  2217  			return auth.AccountOff
  2218  		}(),
  2219  	})
  2220  
  2221  	if err := store.saveUserIdentity(ctx, accessKey, regUser, uinfo); err != nil {
  2222  		return updatedAt, err
  2223  	}
  2224  
  2225  	if err := cache.updateUserWithClaims(accessKey, uinfo); err != nil {
  2226  		return updatedAt, err
  2227  	}
  2228  
  2229  	return uinfo.UpdatedAt, nil
  2230  }
  2231  
  2232  // AddServiceAccount - add a new service account
  2233  func (store *IAMStoreSys) AddServiceAccount(ctx context.Context, cred auth.Credentials) (updatedAt time.Time, err error) {
  2234  	cache := store.lock()
  2235  	defer store.unlock()
  2236  
  2237  	accessKey := cred.AccessKey
  2238  	parentUser := cred.ParentUser
  2239  
  2240  	// Found newly requested service account, to be an existing account -
  2241  	// reject such operation (updates to the service account are handled in
  2242  	// a different API).
  2243  	if su, found := cache.iamUsersMap[accessKey]; found {
  2244  		scred := su.Credentials
  2245  		if scred.ParentUser != parentUser {
  2246  			return updatedAt, fmt.Errorf("%w: the service account access key is taken by another user", errIAMServiceAccountNotAllowed)
  2247  		}
  2248  		return updatedAt, fmt.Errorf("%w: the service account access key already taken", errIAMServiceAccountNotAllowed)
  2249  	}
  2250  
  2251  	// Parent user must not be a service account.
  2252  	if u, found := cache.iamUsersMap[parentUser]; found && u.Credentials.IsServiceAccount() {
  2253  		return updatedAt, fmt.Errorf("%w: unable to create a service account for another service account", errIAMServiceAccountNotAllowed)
  2254  	}
  2255  
  2256  	u := newUserIdentity(cred)
  2257  	err = store.saveUserIdentity(ctx, u.Credentials.AccessKey, svcUser, u)
  2258  	if err != nil {
  2259  		return updatedAt, err
  2260  	}
  2261  
  2262  	cache.updateUserWithClaims(u.Credentials.AccessKey, u)
  2263  
  2264  	return u.UpdatedAt, nil
  2265  }
  2266  
  2267  // UpdateServiceAccount - updates a service account on storage.
  2268  func (store *IAMStoreSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) (updatedAt time.Time, err error) {
  2269  	cache := store.lock()
  2270  	defer store.unlock()
  2271  
  2272  	ui, ok := cache.iamUsersMap[accessKey]
  2273  	if !ok || !ui.Credentials.IsServiceAccount() {
  2274  		return updatedAt, errNoSuchServiceAccount
  2275  	}
  2276  	cr := ui.Credentials
  2277  	currentSecretKey := cr.SecretKey
  2278  	if opts.secretKey != "" {
  2279  		if !auth.IsSecretKeyValid(opts.secretKey) {
  2280  			return updatedAt, auth.ErrInvalidSecretKeyLength
  2281  		}
  2282  		cr.SecretKey = opts.secretKey
  2283  	}
  2284  
  2285  	if opts.name != "" {
  2286  		cr.Name = opts.name
  2287  	}
  2288  
  2289  	if opts.description != "" {
  2290  		cr.Description = opts.description
  2291  	}
  2292  
  2293  	if opts.expiration != nil {
  2294  		expirationInUTC := opts.expiration.UTC()
  2295  		if err := validateSvcExpirationInUTC(expirationInUTC); err != nil {
  2296  			return updatedAt, err
  2297  		}
  2298  		cr.Expiration = expirationInUTC
  2299  	}
  2300  
  2301  	switch opts.status {
  2302  	// The caller did not ask to update status account, do nothing
  2303  	case "":
  2304  	case string(madmin.AccountEnabled):
  2305  		cr.Status = auth.AccountOn
  2306  	case string(madmin.AccountDisabled):
  2307  		cr.Status = auth.AccountOff
  2308  	// Update account status
  2309  	case auth.AccountOn, auth.AccountOff:
  2310  		cr.Status = opts.status
  2311  	default:
  2312  		return updatedAt, errors.New("unknown account status value")
  2313  	}
  2314  
  2315  	m, err := getClaimsFromTokenWithSecret(cr.SessionToken, currentSecretKey)
  2316  	if err != nil {
  2317  		return updatedAt, fmt.Errorf("unable to get svc acc claims: %v", err)
  2318  	}
  2319  
  2320  	// Extracted session policy name string can be removed as its not useful
  2321  	// at this point.
  2322  	delete(m, sessionPolicyNameExtracted)
  2323  
  2324  	// sessionPolicy is nil and there is embedded policy attached we remove
  2325  	// embedded policy at that point.
  2326  	if _, ok := m[policy.SessionPolicyName]; ok && opts.sessionPolicy == nil {
  2327  		delete(m, policy.SessionPolicyName)
  2328  		m[iamPolicyClaimNameSA()] = inheritedPolicyType
  2329  	}
  2330  
  2331  	if opts.sessionPolicy != nil { // session policies is being updated
  2332  		if err := opts.sessionPolicy.Validate(); err != nil {
  2333  			return updatedAt, err
  2334  		}
  2335  
  2336  		policyBuf, err := json.Marshal(opts.sessionPolicy)
  2337  		if err != nil {
  2338  			return updatedAt, err
  2339  		}
  2340  
  2341  		if len(policyBuf) > 2048 {
  2342  			return updatedAt, errSessionPolicyTooLarge
  2343  		}
  2344  
  2345  		// Overwrite session policy claims.
  2346  		m[policy.SessionPolicyName] = base64.StdEncoding.EncodeToString(policyBuf)
  2347  		m[iamPolicyClaimNameSA()] = embeddedPolicyType
  2348  	}
  2349  
  2350  	cr.SessionToken, err = auth.JWTSignWithAccessKey(accessKey, m, cr.SecretKey)
  2351  	if err != nil {
  2352  		return updatedAt, err
  2353  	}
  2354  
  2355  	u := newUserIdentity(cr)
  2356  	if err := store.saveUserIdentity(ctx, u.Credentials.AccessKey, svcUser, u); err != nil {
  2357  		return updatedAt, err
  2358  	}
  2359  
  2360  	if err := cache.updateUserWithClaims(u.Credentials.AccessKey, u); err != nil {
  2361  		return updatedAt, err
  2362  	}
  2363  
  2364  	return u.UpdatedAt, nil
  2365  }
  2366  
  2367  // ListTempAccounts - lists only temporary accounts from the cache.
  2368  func (store *IAMStoreSys) ListTempAccounts(ctx context.Context, accessKey string) ([]UserIdentity, error) {
  2369  	cache := store.rlock()
  2370  	defer store.runlock()
  2371  
  2372  	userExists := false
  2373  	var tempAccounts []UserIdentity
  2374  	for _, v := range cache.iamUsersMap {
  2375  		isDerived := false
  2376  		if v.Credentials.IsServiceAccount() || v.Credentials.IsTemp() {
  2377  			isDerived = true
  2378  		}
  2379  
  2380  		if !isDerived && v.Credentials.AccessKey == accessKey {
  2381  			userExists = true
  2382  		} else if isDerived && v.Credentials.ParentUser == accessKey {
  2383  			userExists = true
  2384  			if v.Credentials.IsTemp() {
  2385  				// Hide secret key & session key here
  2386  				v.Credentials.SecretKey = ""
  2387  				v.Credentials.SessionToken = ""
  2388  				tempAccounts = append(tempAccounts, v)
  2389  			}
  2390  		}
  2391  	}
  2392  
  2393  	if !userExists {
  2394  		return nil, errNoSuchUser
  2395  	}
  2396  
  2397  	return tempAccounts, nil
  2398  }
  2399  
  2400  // ListServiceAccounts - lists only service accounts from the cache.
  2401  func (store *IAMStoreSys) ListServiceAccounts(ctx context.Context, accessKey string) ([]auth.Credentials, error) {
  2402  	cache := store.rlock()
  2403  	defer store.runlock()
  2404  
  2405  	var serviceAccounts []auth.Credentials
  2406  	for _, u := range cache.iamUsersMap {
  2407  		v := u.Credentials
  2408  		if accessKey != "" && v.ParentUser == accessKey {
  2409  			if v.IsServiceAccount() {
  2410  				// Hide secret key & session key here
  2411  				v.SecretKey = ""
  2412  				v.SessionToken = ""
  2413  				serviceAccounts = append(serviceAccounts, v)
  2414  			}
  2415  		}
  2416  	}
  2417  
  2418  	return serviceAccounts, nil
  2419  }
  2420  
  2421  // ListSTSAccounts - lists only STS accounts from the cache.
  2422  func (store *IAMStoreSys) ListSTSAccounts(ctx context.Context, accessKey string) ([]auth.Credentials, error) {
  2423  	cache := store.rlock()
  2424  	defer store.runlock()
  2425  
  2426  	var stsAccounts []auth.Credentials
  2427  	for _, u := range cache.iamSTSAccountsMap {
  2428  		v := u.Credentials
  2429  		if accessKey != "" && v.ParentUser == accessKey {
  2430  			if v.IsTemp() {
  2431  				// Hide secret key & session key here
  2432  				v.SecretKey = ""
  2433  				v.SessionToken = ""
  2434  				stsAccounts = append(stsAccounts, v)
  2435  			}
  2436  		}
  2437  	}
  2438  
  2439  	return stsAccounts, nil
  2440  }
  2441  
  2442  // AddUser - adds/updates long term user account to storage.
  2443  func (store *IAMStoreSys) AddUser(ctx context.Context, accessKey string, ureq madmin.AddOrUpdateUserReq) (updatedAt time.Time, err error) {
  2444  	cache := store.lock()
  2445  	defer store.unlock()
  2446  
  2447  	cache.updatedAt = time.Now()
  2448  
  2449  	ui, ok := cache.iamUsersMap[accessKey]
  2450  
  2451  	// It is not possible to update an STS account.
  2452  	if ok && ui.Credentials.IsTemp() {
  2453  		return updatedAt, errIAMActionNotAllowed
  2454  	}
  2455  
  2456  	u := newUserIdentity(auth.Credentials{
  2457  		AccessKey: accessKey,
  2458  		SecretKey: ureq.SecretKey,
  2459  		Status: func() string {
  2460  			switch string(ureq.Status) {
  2461  			case string(madmin.AccountEnabled), string(auth.AccountOn):
  2462  				return auth.AccountOn
  2463  			}
  2464  			return auth.AccountOff
  2465  		}(),
  2466  	})
  2467  
  2468  	if err := store.saveUserIdentity(ctx, accessKey, regUser, u); err != nil {
  2469  		return updatedAt, err
  2470  	}
  2471  	if err := cache.updateUserWithClaims(accessKey, u); err != nil {
  2472  		return updatedAt, err
  2473  	}
  2474  
  2475  	return u.UpdatedAt, nil
  2476  }
  2477  
  2478  // UpdateUserSecretKey - sets user secret key to storage.
  2479  func (store *IAMStoreSys) UpdateUserSecretKey(ctx context.Context, accessKey, secretKey string) error {
  2480  	cache := store.lock()
  2481  	defer store.unlock()
  2482  
  2483  	cache.updatedAt = time.Now()
  2484  
  2485  	ui, ok := cache.iamUsersMap[accessKey]
  2486  	if !ok {
  2487  		return errNoSuchUser
  2488  	}
  2489  	cred := ui.Credentials
  2490  	cred.SecretKey = secretKey
  2491  	u := newUserIdentity(cred)
  2492  	if err := store.saveUserIdentity(ctx, accessKey, regUser, u); err != nil {
  2493  		return err
  2494  	}
  2495  
  2496  	return cache.updateUserWithClaims(accessKey, u)
  2497  }
  2498  
  2499  // GetSTSAndServiceAccounts - returns all STS and Service account credentials.
  2500  func (store *IAMStoreSys) GetSTSAndServiceAccounts() []auth.Credentials {
  2501  	cache := store.rlock()
  2502  	defer store.runlock()
  2503  
  2504  	var res []auth.Credentials
  2505  	for _, u := range cache.iamUsersMap {
  2506  		cred := u.Credentials
  2507  		if cred.IsServiceAccount() {
  2508  			res = append(res, cred)
  2509  		}
  2510  	}
  2511  	for _, u := range cache.iamSTSAccountsMap {
  2512  		res = append(res, u.Credentials)
  2513  	}
  2514  
  2515  	return res
  2516  }
  2517  
  2518  // UpdateUserIdentity - updates a user credential.
  2519  func (store *IAMStoreSys) UpdateUserIdentity(ctx context.Context, cred auth.Credentials) error {
  2520  	cache := store.lock()
  2521  	defer store.unlock()
  2522  
  2523  	cache.updatedAt = time.Now()
  2524  
  2525  	userType := regUser
  2526  	if cred.IsServiceAccount() {
  2527  		userType = svcUser
  2528  	} else if cred.IsTemp() {
  2529  		userType = stsUser
  2530  	}
  2531  	ui := newUserIdentity(cred)
  2532  	// Overwrite the user identity here. As store should be
  2533  	// atomic, it shouldn't cause any corruption.
  2534  	if err := store.saveUserIdentity(ctx, cred.AccessKey, userType, ui); err != nil {
  2535  		return err
  2536  	}
  2537  
  2538  	return cache.updateUserWithClaims(cred.AccessKey, ui)
  2539  }
  2540  
  2541  // LoadUser - attempts to load user info from storage and updates cache.
  2542  func (store *IAMStoreSys) LoadUser(ctx context.Context, accessKey string) {
  2543  	cache := store.lock()
  2544  	defer store.unlock()
  2545  
  2546  	cache.updatedAt = time.Now()
  2547  
  2548  	_, found := cache.iamUsersMap[accessKey]
  2549  
  2550  	// Check for regular user access key
  2551  	if !found {
  2552  		store.loadUser(ctx, accessKey, regUser, cache.iamUsersMap)
  2553  		if _, found = cache.iamUsersMap[accessKey]; found {
  2554  			// load mapped policies
  2555  			store.loadMappedPolicyWithRetry(ctx, accessKey, regUser, false, cache.iamUserPolicyMap, 3)
  2556  		}
  2557  	}
  2558  
  2559  	// Check for service account
  2560  	if !found {
  2561  		store.loadUser(ctx, accessKey, svcUser, cache.iamUsersMap)
  2562  		var svc UserIdentity
  2563  		svc, found = cache.iamUsersMap[accessKey]
  2564  		if found {
  2565  			// Load parent user and mapped policies.
  2566  			if store.getUsersSysType() == MinIOUsersSysType {
  2567  				store.loadUser(ctx, svc.Credentials.ParentUser, regUser, cache.iamUsersMap)
  2568  				store.loadMappedPolicyWithRetry(ctx, svc.Credentials.ParentUser, regUser, false, cache.iamUserPolicyMap, 3)
  2569  			} else {
  2570  				// In case of LDAP the parent user's policy mapping needs to be
  2571  				// loaded into sts map
  2572  				store.loadMappedPolicyWithRetry(ctx, svc.Credentials.ParentUser, stsUser, false, cache.iamSTSPolicyMap, 3)
  2573  			}
  2574  		}
  2575  	}
  2576  
  2577  	// Check for STS account
  2578  	stsAccountFound := false
  2579  	var stsUserCred UserIdentity
  2580  	if !found {
  2581  		store.loadUser(ctx, accessKey, stsUser, cache.iamSTSAccountsMap)
  2582  		if stsUserCred, found = cache.iamSTSAccountsMap[accessKey]; found {
  2583  			// Load mapped policy
  2584  			store.loadMappedPolicyWithRetry(ctx, stsUserCred.Credentials.ParentUser, stsUser, false, cache.iamSTSPolicyMap, 3)
  2585  			stsAccountFound = true
  2586  		}
  2587  	}
  2588  
  2589  	// Load any associated policy definitions
  2590  	if !stsAccountFound {
  2591  		pols, _ := cache.iamUserPolicyMap.Load(accessKey)
  2592  		for _, policy := range pols.toSlice() {
  2593  			if _, found = cache.iamPolicyDocsMap[policy]; !found {
  2594  				store.loadPolicyDocWithRetry(ctx, policy, cache.iamPolicyDocsMap, 3)
  2595  			}
  2596  		}
  2597  	} else {
  2598  		pols, _ := cache.iamSTSPolicyMap.Load(stsUserCred.Credentials.AccessKey)
  2599  		for _, policy := range pols.toSlice() {
  2600  			if _, found = cache.iamPolicyDocsMap[policy]; !found {
  2601  				store.loadPolicyDocWithRetry(ctx, policy, cache.iamPolicyDocsMap, 3)
  2602  			}
  2603  		}
  2604  	}
  2605  }
  2606  
  2607  func extractJWTClaims(u UserIdentity) (*jwt.MapClaims, error) {
  2608  	jwtClaims, err := auth.ExtractClaims(u.Credentials.SessionToken, u.Credentials.SecretKey)
  2609  	if err != nil {
  2610  		secretKey, err := getTokenSigningKey()
  2611  		if err != nil {
  2612  			return nil, err
  2613  		}
  2614  		// Session tokens for STS creds will be generated with root secret or site-replicator-0 secret
  2615  		jwtClaims, err = auth.ExtractClaims(u.Credentials.SessionToken, secretKey)
  2616  		if err != nil {
  2617  			return nil, err
  2618  		}
  2619  	}
  2620  	return jwtClaims, nil
  2621  }
  2622  
  2623  func validateSvcExpirationInUTC(expirationInUTC time.Time) error {
  2624  	if expirationInUTC.IsZero() || expirationInUTC.Equal(timeSentinel) {
  2625  		// Service accounts might not have expiration in older releases.
  2626  		return nil
  2627  	}
  2628  
  2629  	currentTime := time.Now().UTC()
  2630  	minExpiration := currentTime.Add(minServiceAccountExpiry)
  2631  	maxExpiration := currentTime.Add(maxServiceAccountExpiry)
  2632  	if expirationInUTC.Before(minExpiration) || expirationInUTC.After(maxExpiration) {
  2633  		return errInvalidSvcAcctExpiration
  2634  	}
  2635  
  2636  	return nil
  2637  }