storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/iam.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018-2019 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/base64"
    23  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"math/rand"
    27  	"strings"
    28  	"sync"
    29  	"time"
    30  
    31  	humanize "github.com/dustin/go-humanize"
    32  	"github.com/minio/minio-go/v7/pkg/set"
    33  
    34  	"storj.io/minio/cmd/logger"
    35  	"storj.io/minio/pkg/auth"
    36  	iampolicy "storj.io/minio/pkg/iam/policy"
    37  	"storj.io/minio/pkg/madmin"
    38  )
    39  
    40  // UsersSysType - defines the type of users and groups system that is
    41  // active on the server.
    42  type UsersSysType string
    43  
    44  // Types of users configured in the server.
    45  const (
    46  	// This mode uses the internal users system in MinIO.
    47  	MinIOUsersSysType UsersSysType = "MinIOUsersSys"
    48  
    49  	// This mode uses users and groups from a configured LDAP
    50  	// server.
    51  	LDAPUsersSysType UsersSysType = "LDAPUsersSys"
    52  )
    53  
    54  const (
    55  	// IAM configuration directory.
    56  	iamConfigPrefix = minioConfigPrefix + "/iam"
    57  
    58  	// IAM users directory.
    59  	iamConfigUsersPrefix = iamConfigPrefix + "/users/"
    60  
    61  	// IAM service accounts directory.
    62  	iamConfigServiceAccountsPrefix = iamConfigPrefix + "/service-accounts/"
    63  
    64  	// IAM groups directory.
    65  	iamConfigGroupsPrefix = iamConfigPrefix + "/groups/"
    66  
    67  	// IAM policies directory.
    68  	iamConfigPoliciesPrefix = iamConfigPrefix + "/policies/"
    69  
    70  	// IAM sts directory.
    71  	iamConfigSTSPrefix = iamConfigPrefix + "/sts/"
    72  
    73  	// IAM Policy DB prefixes.
    74  	iamConfigPolicyDBPrefix                = iamConfigPrefix + "/policydb/"
    75  	iamConfigPolicyDBUsersPrefix           = iamConfigPolicyDBPrefix + "users/"
    76  	iamConfigPolicyDBSTSUsersPrefix        = iamConfigPolicyDBPrefix + "sts-users/"
    77  	iamConfigPolicyDBServiceAccountsPrefix = iamConfigPolicyDBPrefix + "service-accounts/"
    78  	iamConfigPolicyDBGroupsPrefix          = iamConfigPolicyDBPrefix + "groups/"
    79  
    80  	// IAM identity file which captures identity credentials.
    81  	iamIdentityFile = "identity.json"
    82  
    83  	// IAM policy file which provides policies for each users.
    84  	iamPolicyFile = "policy.json"
    85  
    86  	// IAM group members file
    87  	iamGroupMembersFile = "members.json"
    88  
    89  	// IAM format file
    90  	iamFormatFile = "format.json"
    91  
    92  	iamFormatVersion1 = 1
    93  )
    94  
    95  const (
    96  	statusEnabled  = "enabled"
    97  	statusDisabled = "disabled"
    98  )
    99  
   100  type iamFormat struct {
   101  	Version int `json:"version"`
   102  }
   103  
   104  func newIAMFormatVersion1() iamFormat {
   105  	return iamFormat{Version: iamFormatVersion1}
   106  }
   107  
   108  func getIAMFormatFilePath() string {
   109  	return iamConfigPrefix + SlashSeparator + iamFormatFile
   110  }
   111  
   112  func getUserIdentityPath(user string, userType IAMUserType) string {
   113  	var basePath string
   114  	switch userType {
   115  	case srvAccUser:
   116  		basePath = iamConfigServiceAccountsPrefix
   117  	case stsUser:
   118  		basePath = iamConfigSTSPrefix
   119  	default:
   120  		basePath = iamConfigUsersPrefix
   121  	}
   122  	return pathJoin(basePath, user, iamIdentityFile)
   123  }
   124  
   125  func getGroupInfoPath(group string) string {
   126  	return pathJoin(iamConfigGroupsPrefix, group, iamGroupMembersFile)
   127  }
   128  
   129  func getPolicyDocPath(name string) string {
   130  	return pathJoin(iamConfigPoliciesPrefix, name, iamPolicyFile)
   131  }
   132  
   133  func getMappedPolicyPath(name string, userType IAMUserType, isGroup bool) string {
   134  	if isGroup {
   135  		return pathJoin(iamConfigPolicyDBGroupsPrefix, name+".json")
   136  	}
   137  	switch userType {
   138  	case srvAccUser:
   139  		return pathJoin(iamConfigPolicyDBServiceAccountsPrefix, name+".json")
   140  	case stsUser:
   141  		return pathJoin(iamConfigPolicyDBSTSUsersPrefix, name+".json")
   142  	default:
   143  		return pathJoin(iamConfigPolicyDBUsersPrefix, name+".json")
   144  	}
   145  }
   146  
   147  // UserIdentity represents a user's secret key and their status
   148  type UserIdentity struct {
   149  	Version     int              `json:"version"`
   150  	Credentials auth.Credentials `json:"credentials"`
   151  }
   152  
   153  func newUserIdentity(cred auth.Credentials) UserIdentity {
   154  	return UserIdentity{Version: 1, Credentials: cred}
   155  }
   156  
   157  // GroupInfo contains info about a group
   158  type GroupInfo struct {
   159  	Version int      `json:"version"`
   160  	Status  string   `json:"status"`
   161  	Members []string `json:"members"`
   162  }
   163  
   164  func newGroupInfo(members []string) GroupInfo {
   165  	return GroupInfo{Version: 1, Status: statusEnabled, Members: members}
   166  }
   167  
   168  // MappedPolicy represents a policy name mapped to a user or group
   169  type MappedPolicy struct {
   170  	Version  int    `json:"version"`
   171  	Policies string `json:"policy"`
   172  }
   173  
   174  // converts a mapped policy into a slice of distinct policies
   175  func (mp MappedPolicy) toSlice() []string {
   176  	var policies []string
   177  	for _, policy := range strings.Split(mp.Policies, ",") {
   178  		policy = strings.TrimSpace(policy)
   179  		if policy == "" {
   180  			continue
   181  		}
   182  		policies = append(policies, policy)
   183  	}
   184  	return policies
   185  }
   186  
   187  func (mp MappedPolicy) policySet() set.StringSet {
   188  	var policies []string
   189  	for _, policy := range strings.Split(mp.Policies, ",") {
   190  		policy = strings.TrimSpace(policy)
   191  		if policy == "" {
   192  			continue
   193  		}
   194  		policies = append(policies, policy)
   195  	}
   196  	return set.CreateStringSet(policies...)
   197  }
   198  
   199  func newMappedPolicy(policy string) MappedPolicy {
   200  	return MappedPolicy{Version: 1, Policies: policy}
   201  }
   202  
   203  // IAMSys - config system.
   204  type IAMSys struct {
   205  	sync.Mutex
   206  
   207  	usersSysType UsersSysType
   208  
   209  	// map of policy names to policy definitions
   210  	iamPolicyDocsMap map[string]iampolicy.Policy
   211  	// map of usernames to credentials
   212  	iamUsersMap map[string]auth.Credentials
   213  	// map of group names to group info
   214  	iamGroupsMap map[string]GroupInfo
   215  	// map of user names to groups they are a member of
   216  	iamUserGroupMemberships map[string]set.StringSet
   217  	// map of usernames/temporary access keys to policy names
   218  	iamUserPolicyMap map[string]MappedPolicy
   219  	// map of group names to policy names
   220  	iamGroupPolicyMap map[string]MappedPolicy
   221  
   222  	// Persistence layer for IAM subsystem
   223  	store IAMStorageAPI
   224  
   225  	// configLoaded will be closed and remain so after first load.
   226  	configLoaded chan struct{}
   227  }
   228  
   229  // IAMUserType represents a user type inside MinIO server
   230  type IAMUserType int
   231  
   232  const (
   233  	regularUser IAMUserType = iota
   234  	stsUser
   235  	srvAccUser
   236  )
   237  
   238  // key options
   239  type options struct {
   240  	ttl int64 //expiry in seconds
   241  }
   242  
   243  // IAMStorageAPI defines an interface for the IAM persistence layer
   244  type IAMStorageAPI interface {
   245  	lock()
   246  	unlock()
   247  
   248  	rlock()
   249  	runlock()
   250  
   251  	migrateBackendFormat(context.Context) error
   252  
   253  	loadPolicyDoc(ctx context.Context, policy string, m map[string]iampolicy.Policy) error
   254  	loadPolicyDocs(ctx context.Context, m map[string]iampolicy.Policy) error
   255  
   256  	loadUser(ctx context.Context, user string, userType IAMUserType, m map[string]auth.Credentials) error
   257  	loadUsers(ctx context.Context, userType IAMUserType, m map[string]auth.Credentials) error
   258  
   259  	loadGroup(ctx context.Context, group string, m map[string]GroupInfo) error
   260  	loadGroups(ctx context.Context, m map[string]GroupInfo) error
   261  
   262  	loadMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error
   263  	loadMappedPolicies(ctx context.Context, userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error
   264  
   265  	loadAll(context.Context, *IAMSys) error
   266  
   267  	saveIAMConfig(ctx context.Context, item interface{}, path string, opts ...options) error
   268  	loadIAMConfig(ctx context.Context, item interface{}, path string) error
   269  	deleteIAMConfig(ctx context.Context, path string) error
   270  
   271  	savePolicyDoc(ctx context.Context, policyName string, p iampolicy.Policy) error
   272  	saveMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool, mp MappedPolicy, opts ...options) error
   273  	saveUserIdentity(ctx context.Context, name string, userType IAMUserType, u UserIdentity, opts ...options) error
   274  	saveGroupInfo(ctx context.Context, group string, gi GroupInfo) error
   275  
   276  	deletePolicyDoc(ctx context.Context, policyName string) error
   277  	deleteMappedPolicy(ctx context.Context, name string, userType IAMUserType, isGroup bool) error
   278  	deleteUserIdentity(ctx context.Context, name string, userType IAMUserType) error
   279  	deleteGroupInfo(ctx context.Context, name string) error
   280  
   281  	watch(context.Context, *IAMSys)
   282  }
   283  
   284  // LoadGroup - loads a specific group from storage, and updates the
   285  // memberships cache. If the specified group does not exist in
   286  // storage, it is removed from in-memory maps as well - this
   287  // simplifies the implementation for group removal. This is called
   288  // only via IAM notifications.
   289  func (sys *IAMSys) LoadGroup(objAPI ObjectLayer, group string) error {
   290  	if !sys.Initialized() {
   291  		return errServerNotInitialized
   292  	}
   293  
   294  	sys.store.lock()
   295  	defer sys.store.unlock()
   296  
   297  	err := sys.store.loadGroup(context.Background(), group, sys.iamGroupsMap)
   298  	if err != nil && err != errNoSuchGroup {
   299  		return err
   300  	}
   301  
   302  	if err == errNoSuchGroup {
   303  		// group does not exist - so remove from memory.
   304  		sys.removeGroupFromMembershipsMap(group)
   305  		delete(sys.iamGroupsMap, group)
   306  		delete(sys.iamGroupPolicyMap, group)
   307  		return nil
   308  	}
   309  
   310  	gi := sys.iamGroupsMap[group]
   311  
   312  	// Updating the group memberships cache happens in two steps:
   313  	//
   314  	// 1. Remove the group from each user's list of memberships.
   315  	// 2. Add the group to each member's list of memberships.
   316  	//
   317  	// This ensures that regardless of members being added or
   318  	// removed, the cache stays current.
   319  	sys.removeGroupFromMembershipsMap(group)
   320  	sys.updateGroupMembershipsMap(group, &gi)
   321  	return nil
   322  }
   323  
   324  // LoadPolicy - reloads a specific canned policy from backend disks or etcd.
   325  func (sys *IAMSys) LoadPolicy(objAPI ObjectLayer, policyName string) error {
   326  	if !sys.Initialized() {
   327  		return errServerNotInitialized
   328  	}
   329  
   330  	sys.store.lock()
   331  	defer sys.store.unlock()
   332  
   333  	return sys.store.loadPolicyDoc(context.Background(), policyName, sys.iamPolicyDocsMap)
   334  }
   335  
   336  // LoadPolicyMapping - loads the mapped policy for a user or group
   337  // from storage into server memory.
   338  func (sys *IAMSys) LoadPolicyMapping(objAPI ObjectLayer, userOrGroup string, isGroup bool) error {
   339  	if !sys.Initialized() {
   340  		return errServerNotInitialized
   341  	}
   342  
   343  	sys.store.lock()
   344  	defer sys.store.unlock()
   345  
   346  	var err error
   347  	if isGroup {
   348  		err = sys.store.loadMappedPolicy(context.Background(), userOrGroup, regularUser, isGroup, sys.iamGroupPolicyMap)
   349  	} else {
   350  		err = sys.store.loadMappedPolicy(context.Background(), userOrGroup, regularUser, isGroup, sys.iamUserPolicyMap)
   351  	}
   352  
   353  	// Ignore policy not mapped error
   354  	if err != nil && err != errNoSuchPolicy {
   355  		return err
   356  	}
   357  
   358  	return nil
   359  }
   360  
   361  // LoadUser - reloads a specific user from backend disks or etcd.
   362  func (sys *IAMSys) LoadUser(objAPI ObjectLayer, accessKey string, userType IAMUserType) error {
   363  	if !sys.Initialized() {
   364  		return errServerNotInitialized
   365  	}
   366  
   367  	sys.store.lock()
   368  	defer sys.store.unlock()
   369  
   370  	err := sys.store.loadUser(context.Background(), accessKey, userType, sys.iamUsersMap)
   371  	if err != nil {
   372  		return err
   373  	}
   374  	err = sys.store.loadMappedPolicy(context.Background(), accessKey, userType, false, sys.iamUserPolicyMap)
   375  	// Ignore policy not mapped error
   376  	if err != nil && err != errNoSuchPolicy {
   377  		return err
   378  	}
   379  
   380  	return nil
   381  }
   382  
   383  // LoadServiceAccount - reloads a specific service account from backend disks or etcd.
   384  func (sys *IAMSys) LoadServiceAccount(accessKey string) error {
   385  	if !sys.Initialized() {
   386  		return errServerNotInitialized
   387  	}
   388  
   389  	sys.store.lock()
   390  	defer sys.store.unlock()
   391  
   392  	err := sys.store.loadUser(context.Background(), accessKey, srvAccUser, sys.iamUsersMap)
   393  	if err != nil {
   394  		return err
   395  	}
   396  
   397  	return nil
   398  }
   399  
   400  // Perform IAM configuration migration.
   401  func (sys *IAMSys) doIAMConfigMigration(ctx context.Context) error {
   402  	return sys.store.migrateBackendFormat(ctx)
   403  }
   404  
   405  // InitStore initializes IAM stores
   406  func (sys *IAMSys) InitStore(objAPI ObjectLayer) {
   407  	sys.Lock()
   408  	defer sys.Unlock()
   409  
   410  	sys.store = newIAMObjectStore(objAPI)
   411  
   412  	if globalLDAPConfig.Enabled {
   413  		sys.EnableLDAPSys()
   414  	}
   415  }
   416  
   417  // Initialized check if IAM is initialized
   418  func (sys *IAMSys) Initialized() bool {
   419  	if sys == nil {
   420  		return false
   421  	}
   422  	sys.Lock()
   423  	defer sys.Unlock()
   424  	return sys.store != nil
   425  }
   426  
   427  // Load - loads all credentials
   428  func (sys *IAMSys) Load(ctx context.Context, store IAMStorageAPI) error {
   429  	iamUsersMap := make(map[string]auth.Credentials)
   430  	iamGroupsMap := make(map[string]GroupInfo)
   431  	iamUserPolicyMap := make(map[string]MappedPolicy)
   432  	iamGroupPolicyMap := make(map[string]MappedPolicy)
   433  	iamPolicyDocsMap := make(map[string]iampolicy.Policy)
   434  
   435  	store.rlock()
   436  	isMinIOUsersSys := sys.usersSysType == MinIOUsersSysType
   437  	store.runlock()
   438  
   439  	if err := store.loadPolicyDocs(ctx, iamPolicyDocsMap); err != nil {
   440  		return err
   441  	}
   442  
   443  	// Sets default canned policies, if none are set.
   444  	setDefaultCannedPolicies(iamPolicyDocsMap)
   445  
   446  	if isMinIOUsersSys {
   447  		if err := store.loadUsers(ctx, regularUser, iamUsersMap); err != nil {
   448  			return err
   449  		}
   450  		if err := store.loadGroups(ctx, iamGroupsMap); err != nil {
   451  			return err
   452  		}
   453  	}
   454  
   455  	// load polices mapped to users
   456  	if err := store.loadMappedPolicies(ctx, regularUser, false, iamUserPolicyMap); err != nil {
   457  		return err
   458  	}
   459  
   460  	// load policies mapped to groups
   461  	if err := store.loadMappedPolicies(ctx, regularUser, true, iamGroupPolicyMap); err != nil {
   462  		return err
   463  	}
   464  
   465  	if err := store.loadUsers(ctx, srvAccUser, iamUsersMap); err != nil {
   466  		return err
   467  	}
   468  
   469  	// load STS temp users
   470  	if err := store.loadUsers(ctx, stsUser, iamUsersMap); err != nil {
   471  		return err
   472  	}
   473  
   474  	// load STS policy mappings
   475  	if err := store.loadMappedPolicies(ctx, stsUser, false, iamUserPolicyMap); err != nil {
   476  		return err
   477  	}
   478  
   479  	store.lock()
   480  	defer store.unlock()
   481  
   482  	for k, v := range iamPolicyDocsMap {
   483  		sys.iamPolicyDocsMap[k] = v
   484  	}
   485  
   486  	// Merge the new reloaded entries into global map.
   487  	// See issue https://github.com/minio/minio/issues/9651
   488  	// where the present list of entries on disk are not yet
   489  	// latest, there is a small window where this can make
   490  	// valid users invalid.
   491  	for k, v := range iamUsersMap {
   492  		sys.iamUsersMap[k] = v
   493  	}
   494  
   495  	for k, v := range iamUserPolicyMap {
   496  		sys.iamUserPolicyMap[k] = v
   497  	}
   498  
   499  	// purge any expired entries which became expired now.
   500  	var expiredEntries []string
   501  	for k, v := range sys.iamUsersMap {
   502  		if v.IsExpired() {
   503  			delete(sys.iamUsersMap, k)
   504  			delete(sys.iamUserPolicyMap, k)
   505  			expiredEntries = append(expiredEntries, k)
   506  			// Deleting on the disk is taken care of in the next cycle
   507  		}
   508  	}
   509  
   510  	for _, v := range sys.iamUsersMap {
   511  		if v.IsServiceAccount() {
   512  			for _, accessKey := range expiredEntries {
   513  				if v.ParentUser == accessKey {
   514  					_ = store.deleteUserIdentity(ctx, v.AccessKey, srvAccUser)
   515  					delete(sys.iamUsersMap, v.AccessKey)
   516  				}
   517  			}
   518  		}
   519  	}
   520  
   521  	// purge any expired entries which became expired now.
   522  	for k, v := range sys.iamUsersMap {
   523  		if v.IsExpired() {
   524  			delete(sys.iamUsersMap, k)
   525  			delete(sys.iamUserPolicyMap, k)
   526  			// Deleting on the etcd is taken care of in the next cycle
   527  		}
   528  	}
   529  
   530  	for k, v := range iamGroupPolicyMap {
   531  		sys.iamGroupPolicyMap[k] = v
   532  	}
   533  
   534  	for k, v := range iamGroupsMap {
   535  		sys.iamGroupsMap[k] = v
   536  	}
   537  
   538  	sys.buildUserGroupMemberships()
   539  	select {
   540  	case <-sys.configLoaded:
   541  	default:
   542  		close(sys.configLoaded)
   543  	}
   544  	return nil
   545  }
   546  
   547  // Init - initializes config system by reading entries from config/iam
   548  func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer) {
   549  	// Initialize IAM store
   550  	sys.InitStore(objAPI)
   551  
   552  	retryCtx, cancel := context.WithCancel(ctx)
   553  
   554  	// Indicate to our routine to exit cleanly upon return.
   555  	defer cancel()
   556  
   557  	// Hold the lock for migration only.
   558  	txnLk := objAPI.NewNSLock(minioMetaBucket, minioConfigPrefix+"/iam.lock")
   559  
   560  	// allocate dynamic timeout once before the loop
   561  	iamLockTimeout := newDynamicTimeout(5*time.Second, 3*time.Second)
   562  
   563  	r := rand.New(rand.NewSource(time.Now().UnixNano()))
   564  
   565  	for {
   566  		// let one of the server acquire the lock, if not let them timeout.
   567  		// which shall be retried again by this loop.
   568  		if _, err := txnLk.GetLock(retryCtx, iamLockTimeout); err != nil {
   569  			logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. trying to acquire lock")
   570  			time.Sleep(time.Duration(r.Float64() * float64(5*time.Second)))
   571  			continue
   572  		}
   573  
   574  		// These messages only meant primarily for distributed setup, so only log during distributed setup.
   575  		if globalIsDistErasure {
   576  			logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. lock acquired")
   577  		}
   578  
   579  		// Migrate IAM configuration, if necessary.
   580  		if err := sys.doIAMConfigMigration(ctx); err != nil {
   581  			txnLk.Unlock()
   582  			if configRetriableErrors(err) {
   583  				logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. possible cause (%v)", err)
   584  				continue
   585  			}
   586  			logger.LogIf(ctx, fmt.Errorf("Unable to migrate IAM users and policies to new format: %w", err))
   587  			logger.LogIf(ctx, errors.New("IAM sub-system is partially initialized, some users may not be available"))
   588  			return
   589  		}
   590  
   591  		// Successfully migrated, proceed to load the users.
   592  		txnLk.Unlock()
   593  		break
   594  	}
   595  
   596  	for {
   597  		if err := sys.store.loadAll(ctx, sys); err != nil {
   598  			if configRetriableErrors(err) {
   599  				logger.Info("Waiting for all MinIO IAM sub-system to be initialized.. possible cause (%v)", err)
   600  				time.Sleep(time.Duration(r.Float64() * float64(5*time.Second)))
   601  				continue
   602  			}
   603  			if err != nil {
   604  				logger.LogIf(ctx, fmt.Errorf("Unable to initialize IAM sub-system, some users may not be available %w", err))
   605  			}
   606  		}
   607  		break
   608  	}
   609  
   610  	// Invalidate the old cred always, even upon error to avoid any leakage.
   611  	globalOldCred = auth.Credentials{}
   612  	go sys.store.watch(ctx, sys)
   613  
   614  	logger.Info("IAM initialization complete")
   615  }
   616  
   617  // DeletePolicy - deletes a canned policy from backend or etcd.
   618  func (sys *IAMSys) DeletePolicy(policyName string) error {
   619  	if !sys.Initialized() {
   620  		return errServerNotInitialized
   621  	}
   622  
   623  	if policyName == "" {
   624  		return errInvalidArgument
   625  	}
   626  
   627  	sys.store.lock()
   628  	defer sys.store.unlock()
   629  
   630  	err := sys.store.deletePolicyDoc(context.Background(), policyName)
   631  	if err == errNoSuchPolicy {
   632  		// Ignore error if policy is already deleted.
   633  		err = nil
   634  	}
   635  
   636  	delete(sys.iamPolicyDocsMap, policyName)
   637  
   638  	// Delete user-policy mappings that will no longer apply
   639  	for u, mp := range sys.iamUserPolicyMap {
   640  		pset := mp.policySet()
   641  		if pset.Contains(policyName) {
   642  			cr, ok := sys.iamUsersMap[u]
   643  			if !ok {
   644  				// This case can happen when an temporary account
   645  				// is deleted or expired, removed it from userPolicyMap.
   646  				delete(sys.iamUserPolicyMap, u)
   647  				continue
   648  			}
   649  			pset.Remove(policyName)
   650  			// User is from STS if the cred are temporary
   651  			if cr.IsTemp() {
   652  				sys.policyDBSet(u, strings.Join(pset.ToSlice(), ","), stsUser, false)
   653  			} else {
   654  				sys.policyDBSet(u, strings.Join(pset.ToSlice(), ","), regularUser, false)
   655  			}
   656  		}
   657  	}
   658  
   659  	// Delete group-policy mappings that will no longer apply
   660  	for g, mp := range sys.iamGroupPolicyMap {
   661  		pset := mp.policySet()
   662  		if pset.Contains(policyName) {
   663  			pset.Remove(policyName)
   664  			sys.policyDBSet(g, strings.Join(pset.ToSlice(), ","), regularUser, true)
   665  		}
   666  	}
   667  
   668  	return err
   669  }
   670  
   671  // InfoPolicy - expands the canned policy into its JSON structure.
   672  func (sys *IAMSys) InfoPolicy(policyName string) (iampolicy.Policy, error) {
   673  	if !sys.Initialized() {
   674  		return iampolicy.Policy{}, errServerNotInitialized
   675  	}
   676  
   677  	sys.store.rlock()
   678  	defer sys.store.runlock()
   679  
   680  	v, ok := sys.iamPolicyDocsMap[policyName]
   681  	if !ok {
   682  		return iampolicy.Policy{}, errNoSuchPolicy
   683  	}
   684  
   685  	return v, nil
   686  }
   687  
   688  // ListPolicies - lists all canned policies.
   689  func (sys *IAMSys) ListPolicies() (map[string]iampolicy.Policy, error) {
   690  	if !sys.Initialized() {
   691  		return nil, errServerNotInitialized
   692  	}
   693  
   694  	<-sys.configLoaded
   695  
   696  	sys.store.rlock()
   697  	defer sys.store.runlock()
   698  
   699  	policyDocsMap := make(map[string]iampolicy.Policy, len(sys.iamPolicyDocsMap))
   700  	for k, v := range sys.iamPolicyDocsMap {
   701  		policyDocsMap[k] = v
   702  	}
   703  
   704  	return policyDocsMap, nil
   705  }
   706  
   707  // SetPolicy - sets a new name policy.
   708  func (sys *IAMSys) SetPolicy(policyName string, p iampolicy.Policy) error {
   709  	if !sys.Initialized() {
   710  		return errServerNotInitialized
   711  	}
   712  
   713  	if p.IsEmpty() || policyName == "" {
   714  		return errInvalidArgument
   715  	}
   716  
   717  	sys.store.lock()
   718  	defer sys.store.unlock()
   719  
   720  	if err := sys.store.savePolicyDoc(context.Background(), policyName, p); err != nil {
   721  		return err
   722  	}
   723  
   724  	sys.iamPolicyDocsMap[policyName] = p
   725  	return nil
   726  }
   727  
   728  // DeleteUser - delete user (only for long-term users not STS users).
   729  func (sys *IAMSys) DeleteUser(accessKey string) error {
   730  	if !sys.Initialized() {
   731  		return errServerNotInitialized
   732  	}
   733  
   734  	if sys.usersSysType != MinIOUsersSysType {
   735  		return errIAMActionNotAllowed
   736  	}
   737  
   738  	// First we remove the user from their groups.
   739  	userInfo, getErr := sys.GetUserInfo(context.Background(), accessKey)
   740  	if getErr != nil {
   741  		return getErr
   742  	}
   743  
   744  	for _, group := range userInfo.MemberOf {
   745  		removeErr := sys.RemoveUsersFromGroup(group, []string{accessKey})
   746  		if removeErr != nil {
   747  			return removeErr
   748  		}
   749  	}
   750  
   751  	// Next we can remove the user from memory and IAM store
   752  	sys.store.lock()
   753  	defer sys.store.unlock()
   754  
   755  	for _, u := range sys.iamUsersMap {
   756  		// Delete any service accounts if any first.
   757  		if u.IsServiceAccount() {
   758  			if u.ParentUser == accessKey {
   759  				_ = sys.store.deleteUserIdentity(context.Background(), u.AccessKey, srvAccUser)
   760  				delete(sys.iamUsersMap, u.AccessKey)
   761  			}
   762  		}
   763  		// Delete any associated STS users.
   764  		if u.IsTemp() {
   765  			if u.ParentUser == accessKey {
   766  				_ = sys.store.deleteUserIdentity(context.Background(), u.AccessKey, stsUser)
   767  				delete(sys.iamUsersMap, u.AccessKey)
   768  			}
   769  		}
   770  	}
   771  
   772  	// It is ok to ignore deletion error on the mapped policy
   773  	sys.store.deleteMappedPolicy(context.Background(), accessKey, regularUser, false)
   774  	err := sys.store.deleteUserIdentity(context.Background(), accessKey, regularUser)
   775  	if err == errNoSuchUser {
   776  		// ignore if user is already deleted.
   777  		err = nil
   778  	}
   779  
   780  	delete(sys.iamUsersMap, accessKey)
   781  	delete(sys.iamUserPolicyMap, accessKey)
   782  
   783  	return err
   784  }
   785  
   786  // CurrentPolicies - returns comma separated policy string, from
   787  // an input policy after validating if there are any current
   788  // policies which exist on MinIO corresponding to the input.
   789  func (sys *IAMSys) CurrentPolicies(policyName string) string {
   790  	if !sys.Initialized() {
   791  		return ""
   792  	}
   793  
   794  	sys.store.rlock()
   795  	defer sys.store.runlock()
   796  
   797  	var policies []string
   798  	mp := newMappedPolicy(policyName)
   799  	for _, policy := range mp.toSlice() {
   800  		_, found := sys.iamPolicyDocsMap[policy]
   801  		if found {
   802  			policies = append(policies, policy)
   803  		}
   804  	}
   805  	return strings.Join(policies, ",")
   806  }
   807  
   808  // SetTempUser - set temporary user credentials, these credentials have an expiry.
   809  func (sys *IAMSys) SetTempUser(accessKey string, cred auth.Credentials, policyName string) error {
   810  	if !sys.Initialized() {
   811  		return errServerNotInitialized
   812  	}
   813  
   814  	ttl := int64(cred.Expiration.Sub(UTCNow()).Seconds())
   815  
   816  	// If OPA is not set we honor any policy claims for this
   817  	// temporary user which match with pre-configured canned
   818  	// policies for this server.
   819  	if GlobalPolicyOPA == nil && policyName != "" {
   820  		mp := newMappedPolicy(policyName)
   821  		combinedPolicy := sys.GetCombinedPolicy(mp.toSlice()...)
   822  
   823  		if combinedPolicy.IsEmpty() {
   824  			return fmt.Errorf("specified policy %s, not found %w", policyName, errNoSuchPolicy)
   825  		}
   826  
   827  		sys.store.lock()
   828  		defer sys.store.unlock()
   829  
   830  		if err := sys.store.saveMappedPolicy(context.Background(), accessKey, stsUser, false, mp, options{ttl: ttl}); err != nil {
   831  			sys.store.unlock()
   832  			return err
   833  		}
   834  
   835  		sys.iamUserPolicyMap[accessKey] = mp
   836  	} else {
   837  		sys.store.lock()
   838  		defer sys.store.unlock()
   839  	}
   840  
   841  	u := newUserIdentity(cred)
   842  	if err := sys.store.saveUserIdentity(context.Background(), accessKey, stsUser, u, options{ttl: ttl}); err != nil {
   843  		return err
   844  	}
   845  
   846  	sys.iamUsersMap[accessKey] = cred
   847  	return nil
   848  }
   849  
   850  // ListUsers - list all users.
   851  func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) {
   852  	if !sys.Initialized() {
   853  		return nil, errServerNotInitialized
   854  	}
   855  
   856  	if sys.usersSysType != MinIOUsersSysType {
   857  		return nil, errIAMActionNotAllowed
   858  	}
   859  
   860  	<-sys.configLoaded
   861  
   862  	sys.store.rlock()
   863  	defer sys.store.runlock()
   864  
   865  	var users = make(map[string]madmin.UserInfo)
   866  
   867  	for k, v := range sys.iamUsersMap {
   868  		if !v.IsTemp() && !v.IsServiceAccount() {
   869  			users[k] = madmin.UserInfo{
   870  				PolicyName: sys.iamUserPolicyMap[k].Policies,
   871  				Status: func() madmin.AccountStatus {
   872  					if v.IsValid() {
   873  						return madmin.AccountEnabled
   874  					}
   875  					return madmin.AccountDisabled
   876  				}(),
   877  			}
   878  		}
   879  	}
   880  
   881  	return users, nil
   882  }
   883  
   884  // IsTempUser - returns if given key is a temporary user.
   885  func (sys *IAMSys) IsTempUser(name string) (bool, string, error) {
   886  	if !sys.Initialized() {
   887  		return false, "", errServerNotInitialized
   888  	}
   889  
   890  	sys.store.rlock()
   891  	defer sys.store.runlock()
   892  
   893  	cred, found := sys.iamUsersMap[name]
   894  	if !found {
   895  		return false, "", errNoSuchUser
   896  	}
   897  
   898  	if cred.IsTemp() {
   899  		return true, cred.ParentUser, nil
   900  	}
   901  
   902  	return false, "", nil
   903  }
   904  
   905  // IsServiceAccount - returns if given key is a service account
   906  func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) {
   907  	if !sys.Initialized() {
   908  		return false, "", errServerNotInitialized
   909  	}
   910  
   911  	sys.store.rlock()
   912  	defer sys.store.runlock()
   913  
   914  	cred, found := sys.iamUsersMap[name]
   915  	if !found {
   916  		return false, "", errNoSuchUser
   917  	}
   918  
   919  	if cred.IsServiceAccount() {
   920  		return true, cred.ParentUser, nil
   921  	}
   922  
   923  	return false, "", nil
   924  }
   925  
   926  // GetUserInfo - get info on a user.
   927  func (sys *IAMSys) GetUserInfo(ctx context.Context, name string) (u madmin.UserInfo, err error) {
   928  	if !sys.Initialized() {
   929  		return u, errServerNotInitialized
   930  	}
   931  
   932  	select {
   933  	case <-sys.configLoaded:
   934  	default:
   935  		sys.loadUserFromStore(ctx, name)
   936  	}
   937  
   938  	if sys.usersSysType != MinIOUsersSysType {
   939  		sys.store.rlock()
   940  		// If the user has a mapped policy or is a member of a group, we
   941  		// return that info. Otherwise we return error.
   942  		mappedPolicy, ok1 := sys.iamUserPolicyMap[name]
   943  		memberships, ok2 := sys.iamUserGroupMemberships[name]
   944  		sys.store.runlock()
   945  		if !ok1 && !ok2 {
   946  			return u, errNoSuchUser
   947  		}
   948  		return madmin.UserInfo{
   949  			PolicyName: mappedPolicy.Policies,
   950  			MemberOf:   memberships.ToSlice(),
   951  		}, nil
   952  	}
   953  
   954  	sys.store.rlock()
   955  	defer sys.store.runlock()
   956  
   957  	cred, found := sys.iamUsersMap[name]
   958  	if !found {
   959  		return u, errNoSuchUser
   960  	}
   961  
   962  	if cred.IsTemp() || cred.IsServiceAccount() {
   963  		return u, errIAMActionNotAllowed
   964  	}
   965  
   966  	return madmin.UserInfo{
   967  		PolicyName: sys.iamUserPolicyMap[name].Policies,
   968  		Status: func() madmin.AccountStatus {
   969  			if cred.IsValid() {
   970  				return madmin.AccountEnabled
   971  			}
   972  			return madmin.AccountDisabled
   973  		}(),
   974  		MemberOf: sys.iamUserGroupMemberships[name].ToSlice(),
   975  	}, nil
   976  
   977  }
   978  
   979  // SetUserStatus - sets current user status, supports disabled or enabled.
   980  func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus) error {
   981  	if !sys.Initialized() {
   982  		return errServerNotInitialized
   983  	}
   984  
   985  	if sys.usersSysType != MinIOUsersSysType {
   986  		return errIAMActionNotAllowed
   987  	}
   988  
   989  	if status != madmin.AccountEnabled && status != madmin.AccountDisabled {
   990  		return errInvalidArgument
   991  	}
   992  
   993  	sys.store.lock()
   994  	defer sys.store.unlock()
   995  
   996  	cred, ok := sys.iamUsersMap[accessKey]
   997  	if !ok {
   998  		return errNoSuchUser
   999  	}
  1000  
  1001  	if cred.IsTemp() || cred.IsServiceAccount() {
  1002  		return errIAMActionNotAllowed
  1003  	}
  1004  
  1005  	uinfo := newUserIdentity(auth.Credentials{
  1006  		AccessKey: accessKey,
  1007  		SecretKey: cred.SecretKey,
  1008  		Status: func() string {
  1009  			if status == madmin.AccountEnabled {
  1010  				return auth.AccountOn
  1011  			}
  1012  			return auth.AccountOff
  1013  		}(),
  1014  	})
  1015  
  1016  	if err := sys.store.saveUserIdentity(context.Background(), accessKey, regularUser, uinfo); err != nil {
  1017  		return err
  1018  	}
  1019  
  1020  	sys.iamUsersMap[accessKey] = uinfo.Credentials
  1021  	return nil
  1022  }
  1023  
  1024  type newServiceAccountOpts struct {
  1025  	sessionPolicy *iampolicy.Policy
  1026  	accessKey     string
  1027  	secretKey     string
  1028  }
  1029  
  1030  // NewServiceAccount - create a new service account
  1031  func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, groups []string, opts newServiceAccountOpts) (auth.Credentials, error) {
  1032  	if !sys.Initialized() {
  1033  		return auth.Credentials{}, errServerNotInitialized
  1034  	}
  1035  
  1036  	var policyBuf []byte
  1037  	if opts.sessionPolicy != nil {
  1038  		err := opts.sessionPolicy.Validate()
  1039  		if err != nil {
  1040  			return auth.Credentials{}, err
  1041  		}
  1042  		policyBuf, err = json.Marshal(opts.sessionPolicy)
  1043  		if err != nil {
  1044  			return auth.Credentials{}, err
  1045  		}
  1046  		if len(policyBuf) > 16*humanize.KiByte {
  1047  			return auth.Credentials{}, fmt.Errorf("Session policy should not exceed 16 KiB characters")
  1048  		}
  1049  	}
  1050  
  1051  	sys.store.lock()
  1052  	defer sys.store.unlock()
  1053  
  1054  	if parentUser == globalActiveCred.AccessKey {
  1055  		return auth.Credentials{}, errIAMActionNotAllowed
  1056  	}
  1057  
  1058  	cr, ok := sys.iamUsersMap[parentUser]
  1059  	if !ok {
  1060  		// For LDAP users we would need this fallback
  1061  		if sys.usersSysType != MinIOUsersSysType {
  1062  			_, ok = sys.iamUserPolicyMap[parentUser]
  1063  			if !ok {
  1064  				var found bool
  1065  				for _, group := range groups {
  1066  					_, ok = sys.iamGroupPolicyMap[group]
  1067  					if !ok {
  1068  						continue
  1069  					}
  1070  					found = true
  1071  					break
  1072  				}
  1073  				if !found {
  1074  					return auth.Credentials{}, errNoSuchUser
  1075  				}
  1076  			}
  1077  		}
  1078  	}
  1079  
  1080  	// Disallow service accounts to further create more service accounts.
  1081  	if cr.IsServiceAccount() {
  1082  		return auth.Credentials{}, errIAMActionNotAllowed
  1083  	}
  1084  
  1085  	m := make(map[string]interface{})
  1086  	m[parentClaim] = parentUser
  1087  
  1088  	if len(policyBuf) > 0 {
  1089  		m[iampolicy.SessionPolicyName] = base64.StdEncoding.EncodeToString(policyBuf)
  1090  		m[iamPolicyClaimNameSA()] = "embedded-policy"
  1091  	} else {
  1092  		m[iamPolicyClaimNameSA()] = "inherited-policy"
  1093  	}
  1094  
  1095  	var (
  1096  		cred auth.Credentials
  1097  		err  error
  1098  	)
  1099  
  1100  	if len(opts.accessKey) > 0 {
  1101  		cred, err = auth.CreateNewCredentialsWithMetadata(opts.accessKey, opts.secretKey, m, globalActiveCred.SecretKey)
  1102  	} else {
  1103  		cred, err = auth.GetNewCredentialsWithMetadata(m, globalActiveCred.SecretKey)
  1104  	}
  1105  	if err != nil {
  1106  		return auth.Credentials{}, err
  1107  	}
  1108  	cred.ParentUser = parentUser
  1109  	cred.Groups = groups
  1110  	cred.Status = string(auth.AccountOn)
  1111  
  1112  	u := newUserIdentity(cred)
  1113  
  1114  	if err := sys.store.saveUserIdentity(context.Background(), u.Credentials.AccessKey, srvAccUser, u); err != nil {
  1115  		return auth.Credentials{}, err
  1116  	}
  1117  
  1118  	sys.iamUsersMap[u.Credentials.AccessKey] = u.Credentials
  1119  
  1120  	return cred, nil
  1121  }
  1122  
  1123  type updateServiceAccountOpts struct {
  1124  	sessionPolicy *iampolicy.Policy
  1125  	secretKey     string
  1126  	status        string
  1127  }
  1128  
  1129  // UpdateServiceAccount - edit a service account
  1130  func (sys *IAMSys) UpdateServiceAccount(ctx context.Context, accessKey string, opts updateServiceAccountOpts) error {
  1131  	if !sys.Initialized() {
  1132  		return errServerNotInitialized
  1133  	}
  1134  
  1135  	sys.store.lock()
  1136  	defer sys.store.unlock()
  1137  
  1138  	cr, ok := sys.iamUsersMap[accessKey]
  1139  	if !ok || !cr.IsServiceAccount() {
  1140  		return errNoSuchServiceAccount
  1141  	}
  1142  
  1143  	if opts.secretKey != "" {
  1144  		cr.SecretKey = opts.secretKey
  1145  	}
  1146  
  1147  	if opts.status != "" {
  1148  		cr.Status = opts.status
  1149  	}
  1150  
  1151  	if opts.sessionPolicy != nil {
  1152  		m := make(map[string]interface{})
  1153  		err := opts.sessionPolicy.Validate()
  1154  		if err != nil {
  1155  			return err
  1156  		}
  1157  		policyBuf, err := json.Marshal(opts.sessionPolicy)
  1158  		if err != nil {
  1159  			return err
  1160  		}
  1161  		if len(policyBuf) > 16*humanize.KiByte {
  1162  			return fmt.Errorf("Session policy should not exceed 16 KiB characters")
  1163  		}
  1164  
  1165  		m[iampolicy.SessionPolicyName] = base64.StdEncoding.EncodeToString(policyBuf)
  1166  		m[iamPolicyClaimNameSA()] = "embedded-policy"
  1167  		m[parentClaim] = cr.ParentUser
  1168  		cr.SessionToken, err = auth.JWTSignWithAccessKey(accessKey, m, globalActiveCred.SecretKey)
  1169  		if err != nil {
  1170  			return err
  1171  		}
  1172  	}
  1173  
  1174  	u := newUserIdentity(cr)
  1175  	if err := sys.store.saveUserIdentity(context.Background(), u.Credentials.AccessKey, srvAccUser, u); err != nil {
  1176  		return err
  1177  	}
  1178  
  1179  	sys.iamUsersMap[u.Credentials.AccessKey] = u.Credentials
  1180  
  1181  	return nil
  1182  }
  1183  
  1184  // ListServiceAccounts - lists all services accounts associated to a specific user
  1185  func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([]auth.Credentials, error) {
  1186  	if !sys.Initialized() {
  1187  		return nil, errServerNotInitialized
  1188  	}
  1189  
  1190  	<-sys.configLoaded
  1191  
  1192  	sys.store.rlock()
  1193  	defer sys.store.runlock()
  1194  
  1195  	var serviceAccounts []auth.Credentials
  1196  	for _, v := range sys.iamUsersMap {
  1197  		if v.IsServiceAccount() && v.ParentUser == accessKey {
  1198  			// Hide secret key & session key here
  1199  			v.SecretKey = ""
  1200  			v.SessionToken = ""
  1201  			serviceAccounts = append(serviceAccounts, v)
  1202  		}
  1203  	}
  1204  
  1205  	return serviceAccounts, nil
  1206  }
  1207  
  1208  // GetServiceAccount - gets information about a service account
  1209  func (sys *IAMSys) GetServiceAccount(ctx context.Context, accessKey string) (auth.Credentials, *iampolicy.Policy, error) {
  1210  	if !sys.Initialized() {
  1211  		return auth.Credentials{}, nil, errServerNotInitialized
  1212  	}
  1213  
  1214  	sys.store.rlock()
  1215  	defer sys.store.runlock()
  1216  
  1217  	sa, ok := sys.iamUsersMap[accessKey]
  1218  	if !ok || !sa.IsServiceAccount() {
  1219  		return auth.Credentials{}, nil, errNoSuchServiceAccount
  1220  	}
  1221  
  1222  	var embeddedPolicy *iampolicy.Policy
  1223  
  1224  	jwtClaims, err := auth.ExtractClaims(sa.SessionToken, globalActiveCred.SecretKey)
  1225  	if err == nil {
  1226  		pt, ptok := jwtClaims.Lookup(iamPolicyClaimNameSA())
  1227  		sp, spok := jwtClaims.Lookup(iampolicy.SessionPolicyName)
  1228  		if ptok && spok && pt == "embedded-policy" {
  1229  			policyBytes, err := base64.StdEncoding.DecodeString(sp)
  1230  			if err == nil {
  1231  				p, err := iampolicy.ParseConfig(bytes.NewReader(policyBytes))
  1232  				if err == nil {
  1233  					policy := iampolicy.Policy{}.Merge(*p)
  1234  					embeddedPolicy = &policy
  1235  				}
  1236  			}
  1237  		}
  1238  	}
  1239  
  1240  	// Hide secret & session keys
  1241  	sa.SecretKey = ""
  1242  	sa.SessionToken = ""
  1243  
  1244  	return sa, embeddedPolicy, nil
  1245  }
  1246  
  1247  // DeleteServiceAccount - delete a service account
  1248  func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string) error {
  1249  	if !sys.Initialized() {
  1250  		return errServerNotInitialized
  1251  	}
  1252  
  1253  	sys.store.lock()
  1254  	defer sys.store.unlock()
  1255  
  1256  	sa, ok := sys.iamUsersMap[accessKey]
  1257  	if !ok || !sa.IsServiceAccount() {
  1258  		return nil
  1259  	}
  1260  
  1261  	// It is ok to ignore deletion error on the mapped policy
  1262  	err := sys.store.deleteUserIdentity(context.Background(), accessKey, srvAccUser)
  1263  	if err != nil {
  1264  		// ignore if user is already deleted.
  1265  		if err == errNoSuchUser {
  1266  			return nil
  1267  		}
  1268  		return err
  1269  	}
  1270  
  1271  	delete(sys.iamUsersMap, accessKey)
  1272  	return nil
  1273  }
  1274  
  1275  // CreateUser - create new user credentials and policy, if user already exists
  1276  // they shall be rewritten with new inputs.
  1277  func (sys *IAMSys) CreateUser(accessKey string, uinfo madmin.UserInfo) error {
  1278  	if !sys.Initialized() {
  1279  		return errServerNotInitialized
  1280  	}
  1281  
  1282  	if sys.usersSysType != MinIOUsersSysType {
  1283  		return errIAMActionNotAllowed
  1284  	}
  1285  
  1286  	sys.store.lock()
  1287  	defer sys.store.unlock()
  1288  
  1289  	cr, ok := sys.iamUsersMap[accessKey]
  1290  	if cr.IsTemp() && ok {
  1291  		return errIAMActionNotAllowed
  1292  	}
  1293  
  1294  	u := newUserIdentity(auth.Credentials{
  1295  		AccessKey: accessKey,
  1296  		SecretKey: uinfo.SecretKey,
  1297  		Status: func() string {
  1298  			if uinfo.Status == madmin.AccountEnabled {
  1299  				return auth.AccountOn
  1300  			}
  1301  			return auth.AccountOff
  1302  		}(),
  1303  	})
  1304  
  1305  	if err := sys.store.saveUserIdentity(context.Background(), accessKey, regularUser, u); err != nil {
  1306  		return err
  1307  	}
  1308  
  1309  	sys.iamUsersMap[accessKey] = u.Credentials
  1310  
  1311  	// Set policy if specified.
  1312  	if uinfo.PolicyName != "" {
  1313  		return sys.policyDBSet(accessKey, uinfo.PolicyName, regularUser, false)
  1314  	}
  1315  	return nil
  1316  }
  1317  
  1318  // SetUserSecretKey - sets user secret key
  1319  func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error {
  1320  	if !sys.Initialized() {
  1321  		return errServerNotInitialized
  1322  	}
  1323  
  1324  	if sys.usersSysType != MinIOUsersSysType {
  1325  		return errIAMActionNotAllowed
  1326  	}
  1327  
  1328  	sys.store.lock()
  1329  	defer sys.store.unlock()
  1330  
  1331  	cred, ok := sys.iamUsersMap[accessKey]
  1332  	if !ok {
  1333  		return errNoSuchUser
  1334  	}
  1335  
  1336  	cred.SecretKey = secretKey
  1337  	u := newUserIdentity(cred)
  1338  	if err := sys.store.saveUserIdentity(context.Background(), accessKey, regularUser, u); err != nil {
  1339  		return err
  1340  	}
  1341  
  1342  	sys.iamUsersMap[accessKey] = cred
  1343  	return nil
  1344  }
  1345  
  1346  func (sys *IAMSys) loadUserFromStore(ctx context.Context, accessKey string) {
  1347  	sys.store.lock()
  1348  	// If user is already found proceed.
  1349  	if _, found := sys.iamUsersMap[accessKey]; !found {
  1350  		sys.store.loadUser(ctx, accessKey, regularUser, sys.iamUsersMap)
  1351  		if _, found = sys.iamUsersMap[accessKey]; found {
  1352  			// found user, load its mapped policies
  1353  			sys.store.loadMappedPolicy(ctx, accessKey, regularUser, false, sys.iamUserPolicyMap)
  1354  		} else {
  1355  			sys.store.loadUser(ctx, accessKey, srvAccUser, sys.iamUsersMap)
  1356  			if svc, found := sys.iamUsersMap[accessKey]; found {
  1357  				// Found service account, load its parent user and its mapped policies.
  1358  				if sys.usersSysType == MinIOUsersSysType {
  1359  					sys.store.loadUser(ctx, svc.ParentUser, regularUser, sys.iamUsersMap)
  1360  				}
  1361  				sys.store.loadMappedPolicy(ctx, svc.ParentUser, regularUser, false, sys.iamUserPolicyMap)
  1362  			} else {
  1363  				// None found fall back to STS users.
  1364  				sys.store.loadUser(ctx, accessKey, stsUser, sys.iamUsersMap)
  1365  				if _, found = sys.iamUsersMap[accessKey]; found {
  1366  					// STS user found, load its mapped policy.
  1367  					sys.store.loadMappedPolicy(context.Background(), accessKey, stsUser, false, sys.iamUserPolicyMap)
  1368  				}
  1369  			}
  1370  		}
  1371  	}
  1372  
  1373  	// Load associated policies if any.
  1374  	for _, policy := range sys.iamUserPolicyMap[accessKey].toSlice() {
  1375  		if _, found := sys.iamPolicyDocsMap[policy]; !found {
  1376  			sys.store.loadPolicyDoc(context.Background(), policy, sys.iamPolicyDocsMap)
  1377  		}
  1378  	}
  1379  
  1380  	sys.buildUserGroupMemberships()
  1381  	sys.store.unlock()
  1382  }
  1383  
  1384  // GetUser - get user credentials
  1385  func (sys *IAMSys) GetUser(ctx context.Context, accessKey string) (cred auth.Credentials, ok bool) {
  1386  	if !sys.Initialized() {
  1387  		return cred, false
  1388  	}
  1389  
  1390  	fallback := false
  1391  	select {
  1392  	case <-sys.configLoaded:
  1393  	default:
  1394  		sys.loadUserFromStore(ctx, accessKey)
  1395  		fallback = true
  1396  	}
  1397  
  1398  	sys.store.rlock()
  1399  	cred, ok = sys.iamUsersMap[accessKey]
  1400  	if !ok && !fallback {
  1401  		sys.store.runlock()
  1402  		// accessKey not found, also
  1403  		// IAM store is not in fallback mode
  1404  		// we can try to reload again from
  1405  		// the IAM store and see if credential
  1406  		// exists now. If it doesn't proceed to
  1407  		// fail.
  1408  		sys.loadUserFromStore(ctx, accessKey)
  1409  
  1410  		sys.store.rlock()
  1411  		cred, ok = sys.iamUsersMap[accessKey]
  1412  	}
  1413  	defer sys.store.runlock()
  1414  
  1415  	if ok && cred.IsValid() {
  1416  		if cred.ParentUser != "" && sys.usersSysType == MinIOUsersSysType {
  1417  			_, ok = sys.iamUsersMap[cred.ParentUser]
  1418  		}
  1419  		// for LDAP service accounts with ParentUser set
  1420  		// we have no way to validate, either because user
  1421  		// doesn't need an explicit policy as it can come
  1422  		// automatically from a group. We are safe to ignore
  1423  		// this and continue as policies would fail eventually
  1424  		// the policies are missing or not configured.
  1425  	}
  1426  	return cred, ok && cred.IsValid()
  1427  }
  1428  
  1429  // AddUsersToGroup - adds users to a group, creating the group if
  1430  // needed. No error if user(s) already are in the group.
  1431  func (sys *IAMSys) AddUsersToGroup(group string, members []string) error {
  1432  	if !sys.Initialized() {
  1433  		return errServerNotInitialized
  1434  	}
  1435  
  1436  	if group == "" {
  1437  		return errInvalidArgument
  1438  	}
  1439  
  1440  	if sys.usersSysType != MinIOUsersSysType {
  1441  		return errIAMActionNotAllowed
  1442  	}
  1443  
  1444  	sys.store.lock()
  1445  	defer sys.store.unlock()
  1446  
  1447  	// Validate that all members exist.
  1448  	for _, member := range members {
  1449  		cr, ok := sys.iamUsersMap[member]
  1450  		if !ok {
  1451  			return errNoSuchUser
  1452  		}
  1453  		if cr.IsTemp() {
  1454  			return errIAMActionNotAllowed
  1455  		}
  1456  	}
  1457  
  1458  	gi, ok := sys.iamGroupsMap[group]
  1459  	if !ok {
  1460  		// Set group as enabled by default when it doesn't
  1461  		// exist.
  1462  		gi = newGroupInfo(members)
  1463  	} else {
  1464  		mergedMembers := append(gi.Members, members...)
  1465  		uniqMembers := set.CreateStringSet(mergedMembers...).ToSlice()
  1466  		gi.Members = uniqMembers
  1467  	}
  1468  
  1469  	if err := sys.store.saveGroupInfo(context.Background(), group, gi); err != nil {
  1470  		return err
  1471  	}
  1472  
  1473  	sys.iamGroupsMap[group] = gi
  1474  
  1475  	// update user-group membership map
  1476  	for _, member := range members {
  1477  		gset := sys.iamUserGroupMemberships[member]
  1478  		if gset == nil {
  1479  			gset = set.CreateStringSet(group)
  1480  		} else {
  1481  			gset.Add(group)
  1482  		}
  1483  		sys.iamUserGroupMemberships[member] = gset
  1484  	}
  1485  
  1486  	return nil
  1487  }
  1488  
  1489  // RemoveUsersFromGroup - remove users from group. If no users are
  1490  // given, and the group is empty, deletes the group as well.
  1491  func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error {
  1492  	if !sys.Initialized() {
  1493  		return errServerNotInitialized
  1494  	}
  1495  
  1496  	if sys.usersSysType != MinIOUsersSysType {
  1497  		return errIAMActionNotAllowed
  1498  	}
  1499  
  1500  	if group == "" {
  1501  		return errInvalidArgument
  1502  	}
  1503  
  1504  	sys.store.lock()
  1505  	defer sys.store.unlock()
  1506  
  1507  	// Validate that all members exist.
  1508  	for _, member := range members {
  1509  		cr, ok := sys.iamUsersMap[member]
  1510  		if !ok {
  1511  			return errNoSuchUser
  1512  		}
  1513  		if cr.IsTemp() {
  1514  			return errIAMActionNotAllowed
  1515  		}
  1516  	}
  1517  
  1518  	gi, ok := sys.iamGroupsMap[group]
  1519  	if !ok {
  1520  		return errNoSuchGroup
  1521  	}
  1522  
  1523  	// Check if attempting to delete a non-empty group.
  1524  	if len(members) == 0 && len(gi.Members) != 0 {
  1525  		return errGroupNotEmpty
  1526  	}
  1527  
  1528  	if len(members) == 0 {
  1529  		// len(gi.Members) == 0 here.
  1530  
  1531  		// Remove the group from storage. First delete the
  1532  		// mapped policy. No-mapped-policy case is ignored.
  1533  		if err := sys.store.deleteMappedPolicy(context.Background(), group, regularUser, true); err != nil && err != errNoSuchPolicy {
  1534  			return err
  1535  		}
  1536  		if err := sys.store.deleteGroupInfo(context.Background(), group); err != nil && err != errNoSuchGroup {
  1537  			return err
  1538  		}
  1539  
  1540  		// Delete from server memory
  1541  		delete(sys.iamGroupsMap, group)
  1542  		delete(sys.iamGroupPolicyMap, group)
  1543  		return nil
  1544  	}
  1545  
  1546  	// Only removing members.
  1547  	s := set.CreateStringSet(gi.Members...)
  1548  	d := set.CreateStringSet(members...)
  1549  	gi.Members = s.Difference(d).ToSlice()
  1550  
  1551  	err := sys.store.saveGroupInfo(context.Background(), group, gi)
  1552  	if err != nil {
  1553  		return err
  1554  	}
  1555  	sys.iamGroupsMap[group] = gi
  1556  
  1557  	// update user-group membership map
  1558  	for _, member := range members {
  1559  		gset := sys.iamUserGroupMemberships[member]
  1560  		if gset == nil {
  1561  			continue
  1562  		}
  1563  		gset.Remove(group)
  1564  		sys.iamUserGroupMemberships[member] = gset
  1565  	}
  1566  
  1567  	return nil
  1568  }
  1569  
  1570  // SetGroupStatus - enable/disabled a group
  1571  func (sys *IAMSys) SetGroupStatus(group string, enabled bool) error {
  1572  	if !sys.Initialized() {
  1573  		return errServerNotInitialized
  1574  	}
  1575  
  1576  	if sys.usersSysType != MinIOUsersSysType {
  1577  		return errIAMActionNotAllowed
  1578  	}
  1579  
  1580  	sys.store.lock()
  1581  	defer sys.store.unlock()
  1582  
  1583  	if group == "" {
  1584  		return errInvalidArgument
  1585  	}
  1586  
  1587  	gi, ok := sys.iamGroupsMap[group]
  1588  	if !ok {
  1589  		return errNoSuchGroup
  1590  	}
  1591  
  1592  	if enabled {
  1593  		gi.Status = statusEnabled
  1594  	} else {
  1595  		gi.Status = statusDisabled
  1596  	}
  1597  
  1598  	if err := sys.store.saveGroupInfo(context.Background(), group, gi); err != nil {
  1599  		return err
  1600  	}
  1601  	sys.iamGroupsMap[group] = gi
  1602  	return nil
  1603  }
  1604  
  1605  // GetGroupDescription - builds up group description
  1606  func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err error) {
  1607  	if !sys.Initialized() {
  1608  		return gd, errServerNotInitialized
  1609  	}
  1610  
  1611  	ps, err := sys.PolicyDBGet(group, true)
  1612  	if err != nil {
  1613  		return gd, err
  1614  	}
  1615  
  1616  	policy := strings.Join(ps, ",")
  1617  
  1618  	if sys.usersSysType != MinIOUsersSysType {
  1619  		return madmin.GroupDesc{
  1620  			Name:   group,
  1621  			Policy: policy,
  1622  		}, nil
  1623  	}
  1624  
  1625  	sys.store.rlock()
  1626  	defer sys.store.runlock()
  1627  
  1628  	gi, ok := sys.iamGroupsMap[group]
  1629  	if !ok {
  1630  		return gd, errNoSuchGroup
  1631  	}
  1632  
  1633  	return madmin.GroupDesc{
  1634  		Name:    group,
  1635  		Status:  gi.Status,
  1636  		Members: gi.Members,
  1637  		Policy:  policy,
  1638  	}, nil
  1639  }
  1640  
  1641  // ListGroups - lists groups.
  1642  func (sys *IAMSys) ListGroups() (r []string, err error) {
  1643  	if !sys.Initialized() {
  1644  		return r, errServerNotInitialized
  1645  	}
  1646  
  1647  	if sys.usersSysType != MinIOUsersSysType {
  1648  		return nil, errIAMActionNotAllowed
  1649  	}
  1650  
  1651  	<-sys.configLoaded
  1652  
  1653  	sys.store.rlock()
  1654  	defer sys.store.runlock()
  1655  
  1656  	r = make([]string, 0, len(sys.iamGroupsMap))
  1657  	for k := range sys.iamGroupsMap {
  1658  		r = append(r, k)
  1659  	}
  1660  
  1661  	return r, nil
  1662  }
  1663  
  1664  // PolicyDBSet - sets a policy for a user or group in the PolicyDB.
  1665  func (sys *IAMSys) PolicyDBSet(name, policy string, isGroup bool) error {
  1666  	if !sys.Initialized() {
  1667  		return errServerNotInitialized
  1668  	}
  1669  
  1670  	sys.store.lock()
  1671  	defer sys.store.unlock()
  1672  
  1673  	if sys.usersSysType == LDAPUsersSysType {
  1674  		return sys.policyDBSet(name, policy, stsUser, isGroup)
  1675  	}
  1676  
  1677  	return sys.policyDBSet(name, policy, regularUser, isGroup)
  1678  }
  1679  
  1680  // policyDBSet - sets a policy for user in the policy db. Assumes that caller
  1681  // has sys.Lock(). If policy == "", then policy mapping is removed.
  1682  func (sys *IAMSys) policyDBSet(name, policyName string, userType IAMUserType, isGroup bool) error {
  1683  	if name == "" {
  1684  		return errInvalidArgument
  1685  	}
  1686  
  1687  	if sys.usersSysType == MinIOUsersSysType {
  1688  		if !isGroup {
  1689  			if _, ok := sys.iamUsersMap[name]; !ok {
  1690  				return errNoSuchUser
  1691  			}
  1692  		} else {
  1693  			if _, ok := sys.iamGroupsMap[name]; !ok {
  1694  				return errNoSuchGroup
  1695  			}
  1696  		}
  1697  	}
  1698  
  1699  	// Handle policy mapping removal
  1700  	if policyName == "" {
  1701  		if sys.usersSysType == LDAPUsersSysType {
  1702  			// Add a fallback removal towards previous content that may come back
  1703  			// as a ghost user due to lack of delete, this change occurred
  1704  			// introduced in PR #11840
  1705  			sys.store.deleteMappedPolicy(context.Background(), name, regularUser, false)
  1706  		}
  1707  		err := sys.store.deleteMappedPolicy(context.Background(), name, userType, isGroup)
  1708  		if err != nil && err != errNoSuchPolicy {
  1709  			return err
  1710  		}
  1711  		if !isGroup {
  1712  			delete(sys.iamUserPolicyMap, name)
  1713  		} else {
  1714  			delete(sys.iamGroupPolicyMap, name)
  1715  		}
  1716  		return nil
  1717  	}
  1718  
  1719  	mp := newMappedPolicy(policyName)
  1720  	for _, policy := range mp.toSlice() {
  1721  		if _, found := sys.iamPolicyDocsMap[policy]; !found {
  1722  			logger.LogIf(GlobalContext, fmt.Errorf("%w: (%s)", errNoSuchPolicy, policy))
  1723  			return errNoSuchPolicy
  1724  		}
  1725  	}
  1726  
  1727  	// Handle policy mapping set/update
  1728  	if err := sys.store.saveMappedPolicy(context.Background(), name, userType, isGroup, mp); err != nil {
  1729  		return err
  1730  	}
  1731  	if !isGroup {
  1732  		sys.iamUserPolicyMap[name] = mp
  1733  	} else {
  1734  		sys.iamGroupPolicyMap[name] = mp
  1735  	}
  1736  	return nil
  1737  }
  1738  
  1739  // PolicyDBGet - gets policy set on a user or group. If a list of groups is
  1740  // given, policies associated with them are included as well.
  1741  func (sys *IAMSys) PolicyDBGet(name string, isGroup bool, groups ...string) ([]string, error) {
  1742  	if !sys.Initialized() {
  1743  		return nil, errServerNotInitialized
  1744  	}
  1745  
  1746  	if name == "" {
  1747  		return nil, errInvalidArgument
  1748  	}
  1749  
  1750  	sys.store.rlock()
  1751  	defer sys.store.runlock()
  1752  
  1753  	policies, err := sys.policyDBGet(name, isGroup)
  1754  	if err != nil {
  1755  		return nil, err
  1756  	}
  1757  
  1758  	if !isGroup {
  1759  		for _, group := range groups {
  1760  			ps, err := sys.policyDBGet(group, true)
  1761  			if err != nil {
  1762  				return nil, err
  1763  			}
  1764  			policies = append(policies, ps...)
  1765  		}
  1766  	}
  1767  
  1768  	return policies, nil
  1769  }
  1770  
  1771  // This call assumes that caller has the sys.RLock().
  1772  //
  1773  // If a group is passed, it returns policies associated with the group.
  1774  //
  1775  // If a user is passed, it returns policies of the user along with any groups
  1776  // that the server knows the user is a member of.
  1777  //
  1778  // In LDAP users mode, the server does not store any group membership
  1779  // information in IAM (i.e sys.iam*Map) - this info is stored only in the STS
  1780  // generated credentials. Thus we skip looking up group memberships, user map,
  1781  // and group map and check the appropriate policy maps directly.
  1782  func (sys *IAMSys) policyDBGet(name string, isGroup bool) (policies []string, err error) {
  1783  	if isGroup {
  1784  		if sys.usersSysType == MinIOUsersSysType {
  1785  			g, ok := sys.iamGroupsMap[name]
  1786  			if !ok {
  1787  				return nil, errNoSuchGroup
  1788  			}
  1789  
  1790  			// Group is disabled, so we return no policy - this
  1791  			// ensures the request is denied.
  1792  			if g.Status == statusDisabled {
  1793  				return nil, nil
  1794  			}
  1795  		}
  1796  
  1797  		return sys.iamGroupPolicyMap[name].toSlice(), nil
  1798  	}
  1799  
  1800  	var u auth.Credentials
  1801  	var ok bool
  1802  	if sys.usersSysType == MinIOUsersSysType {
  1803  		// When looking for a user's policies, we also check if the user
  1804  		// and the groups they are member of are enabled.
  1805  
  1806  		u, ok = sys.iamUsersMap[name]
  1807  		if !ok {
  1808  			return nil, errNoSuchUser
  1809  		}
  1810  		if !u.IsValid() {
  1811  			return nil, nil
  1812  		}
  1813  	}
  1814  
  1815  	mp, ok := sys.iamUserPolicyMap[name]
  1816  	if !ok {
  1817  		if u.ParentUser != "" {
  1818  			mp = sys.iamUserPolicyMap[u.ParentUser]
  1819  		}
  1820  	}
  1821  
  1822  	// returned policy could be empty
  1823  	policies = append(policies, mp.toSlice()...)
  1824  
  1825  	for _, group := range sys.iamUserGroupMemberships[name].ToSlice() {
  1826  		// Skip missing or disabled groups
  1827  		gi, ok := sys.iamGroupsMap[group]
  1828  		if !ok || gi.Status == statusDisabled {
  1829  			continue
  1830  		}
  1831  
  1832  		policies = append(policies, sys.iamGroupPolicyMap[group].toSlice()...)
  1833  	}
  1834  
  1835  	return policies, nil
  1836  }
  1837  
  1838  // IsAllowedServiceAccount - checks if the given service account is allowed to perform
  1839  // actions. The permission of the parent user is checked first
  1840  func (sys *IAMSys) IsAllowedServiceAccount(args iampolicy.Args, parent string) bool {
  1841  	// Now check if we have a subject claim
  1842  	p, ok := args.Claims[parentClaim]
  1843  	if ok {
  1844  		parentInClaim, ok := p.(string)
  1845  		if !ok {
  1846  			// Reject malformed/malicious requests.
  1847  			return false
  1848  		}
  1849  		// The parent claim in the session token should be equal
  1850  		// to the parent detected in the backend
  1851  		if parentInClaim != parent {
  1852  			return false
  1853  		}
  1854  	} else {
  1855  		// This is needed so a malicious user cannot
  1856  		// use a leaked session key of another user
  1857  		// to widen its privileges.
  1858  		return false
  1859  	}
  1860  
  1861  	// Check policy for this service account.
  1862  	svcPolicies, err := sys.PolicyDBGet(parent, false, args.Groups...)
  1863  	if err != nil {
  1864  		logger.LogIf(GlobalContext, err)
  1865  		return false
  1866  	}
  1867  
  1868  	if len(svcPolicies) == 0 {
  1869  		return false
  1870  	}
  1871  
  1872  	var availablePolicies []iampolicy.Policy
  1873  
  1874  	// Policies were found, evaluate all of them.
  1875  	sys.store.rlock()
  1876  	for _, pname := range svcPolicies {
  1877  		p, found := sys.iamPolicyDocsMap[pname]
  1878  		if found {
  1879  			availablePolicies = append(availablePolicies, p)
  1880  		}
  1881  	}
  1882  	sys.store.runlock()
  1883  
  1884  	if len(availablePolicies) == 0 {
  1885  		return false
  1886  	}
  1887  
  1888  	combinedPolicy := availablePolicies[0]
  1889  	for i := 1; i < len(availablePolicies); i++ {
  1890  		combinedPolicy.Statements = append(combinedPolicy.Statements,
  1891  			availablePolicies[i].Statements...)
  1892  	}
  1893  
  1894  	parentArgs := args
  1895  	parentArgs.AccountName = parent
  1896  
  1897  	saPolicyClaim, ok := args.Claims[iamPolicyClaimNameSA()]
  1898  	if !ok {
  1899  		return false
  1900  	}
  1901  
  1902  	saPolicyClaimStr, ok := saPolicyClaim.(string)
  1903  	if !ok {
  1904  		// Sub policy if set, should be a string reject
  1905  		// malformed/malicious requests.
  1906  		return false
  1907  	}
  1908  
  1909  	if saPolicyClaimStr == "inherited-policy" {
  1910  		return combinedPolicy.IsAllowed(parentArgs)
  1911  	}
  1912  
  1913  	// Now check if we have a sessionPolicy.
  1914  	spolicy, ok := args.Claims[iampolicy.SessionPolicyName]
  1915  	if !ok {
  1916  		return false
  1917  	}
  1918  
  1919  	spolicyStr, ok := spolicy.(string)
  1920  	if !ok {
  1921  		// Sub policy if set, should be a string reject
  1922  		// malformed/malicious requests.
  1923  		return false
  1924  	}
  1925  
  1926  	// Check if policy is parseable.
  1927  	subPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(spolicyStr)))
  1928  	if err != nil {
  1929  		// Log any error in input session policy config.
  1930  		logger.LogIf(GlobalContext, err)
  1931  		return false
  1932  	}
  1933  
  1934  	// Policy without Version string value reject it.
  1935  	if subPolicy.Version == "" {
  1936  		return false
  1937  	}
  1938  
  1939  	return combinedPolicy.IsAllowed(parentArgs) && subPolicy.IsAllowed(parentArgs)
  1940  }
  1941  
  1942  // IsAllowedLDAPSTS - checks for LDAP specific claims and values
  1943  func (sys *IAMSys) IsAllowedLDAPSTS(args iampolicy.Args, parentUser string) bool {
  1944  	parentInClaimIface, ok := args.Claims[ldapUser]
  1945  	if ok {
  1946  		parentInClaim, ok := parentInClaimIface.(string)
  1947  		if !ok {
  1948  			// ldap parentInClaim name is not a string reject it.
  1949  			return false
  1950  		}
  1951  
  1952  		if parentInClaim != parentUser {
  1953  			// ldap claim has been modified maliciously reject it.
  1954  			return false
  1955  		}
  1956  	} else {
  1957  		// no ldap parentInClaim claim present reject it.
  1958  		return false
  1959  	}
  1960  
  1961  	// Check policy for this LDAP user.
  1962  	ldapPolicies, err := sys.PolicyDBGet(parentUser, false, args.Groups...)
  1963  	if err != nil {
  1964  		return false
  1965  	}
  1966  
  1967  	if len(ldapPolicies) == 0 {
  1968  		return false
  1969  	}
  1970  
  1971  	var availablePolicies []iampolicy.Policy
  1972  
  1973  	// Policies were found, evaluate all of them.
  1974  	sys.store.rlock()
  1975  	for _, pname := range ldapPolicies {
  1976  		p, found := sys.iamPolicyDocsMap[pname]
  1977  		if found {
  1978  			availablePolicies = append(availablePolicies, p)
  1979  		}
  1980  	}
  1981  	sys.store.runlock()
  1982  
  1983  	if len(availablePolicies) == 0 {
  1984  		return false
  1985  	}
  1986  
  1987  	combinedPolicy := availablePolicies[0]
  1988  	for i := 1; i < len(availablePolicies); i++ {
  1989  		combinedPolicy.Statements =
  1990  			append(combinedPolicy.Statements,
  1991  				availablePolicies[i].Statements...)
  1992  	}
  1993  
  1994  	return combinedPolicy.IsAllowed(args)
  1995  }
  1996  
  1997  // IsAllowedSTS is meant for STS based temporary credentials,
  1998  // which implements claims validation and verification other than
  1999  // applying policies.
  2000  func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args, parentUser string) bool {
  2001  	// If it is an LDAP request, check that user and group
  2002  	// policies allow the request.
  2003  	if sys.usersSysType == LDAPUsersSysType {
  2004  		return sys.IsAllowedLDAPSTS(args, parentUser)
  2005  	}
  2006  
  2007  	policies, ok := args.GetPolicies(iamPolicyClaimNameOpenID())
  2008  	if !ok {
  2009  		// When claims are set, it should have a policy claim field.
  2010  		return false
  2011  	}
  2012  
  2013  	// When claims are set, it should have policies as claim.
  2014  	if policies.IsEmpty() {
  2015  		// No policy, no access!
  2016  		return false
  2017  	}
  2018  
  2019  	sys.store.rlock()
  2020  	defer sys.store.runlock()
  2021  
  2022  	// If policy is available for given user, check the policy.
  2023  	mp, ok := sys.iamUserPolicyMap[args.AccountName]
  2024  	if !ok {
  2025  		// No policy set for the user that we can find, no access!
  2026  		return false
  2027  	}
  2028  
  2029  	if !policies.Equals(mp.policySet()) {
  2030  		// When claims has a policy, it should match the
  2031  		// policy of args.AccountName which server remembers.
  2032  		// if not reject such requests.
  2033  		return false
  2034  	}
  2035  
  2036  	var availablePolicies []iampolicy.Policy
  2037  	for pname := range policies {
  2038  		p, found := sys.iamPolicyDocsMap[pname]
  2039  		if !found {
  2040  			// all policies presented in the claim should exist
  2041  			logger.LogIf(GlobalContext, fmt.Errorf("expected policy (%s) missing from the JWT claim %s, rejecting the request", pname, iamPolicyClaimNameOpenID()))
  2042  			return false
  2043  		}
  2044  		availablePolicies = append(availablePolicies, p)
  2045  	}
  2046  
  2047  	combinedPolicy := availablePolicies[0]
  2048  	for i := 1; i < len(availablePolicies); i++ {
  2049  		combinedPolicy.Statements = append(combinedPolicy.Statements,
  2050  			availablePolicies[i].Statements...)
  2051  	}
  2052  
  2053  	// Now check if we have a sessionPolicy.
  2054  	spolicy, ok := args.Claims[iampolicy.SessionPolicyName]
  2055  	if ok {
  2056  		spolicyStr, ok := spolicy.(string)
  2057  		if !ok {
  2058  			// Sub policy if set, should be a string reject
  2059  			// malformed/malicious requests.
  2060  			return false
  2061  		}
  2062  
  2063  		// Check if policy is parseable.
  2064  		subPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(spolicyStr)))
  2065  		if err != nil {
  2066  			// Log any error in input session policy config.
  2067  			logger.LogIf(GlobalContext, err)
  2068  			return false
  2069  		}
  2070  
  2071  		// Policy without Version string value reject it.
  2072  		if subPolicy.Version == "" {
  2073  			return false
  2074  		}
  2075  
  2076  		// Sub policy is set and valid.
  2077  		return combinedPolicy.IsAllowed(args) && subPolicy.IsAllowed(args)
  2078  	}
  2079  
  2080  	// Sub policy not set, this is most common since subPolicy
  2081  	// is optional, use the inherited policies.
  2082  	return combinedPolicy.IsAllowed(args)
  2083  }
  2084  
  2085  // GetCombinedPolicy returns a combined policy combining all policies
  2086  func (sys *IAMSys) GetCombinedPolicy(policies ...string) iampolicy.Policy {
  2087  	// Policies were found, evaluate all of them.
  2088  	sys.store.rlock()
  2089  	defer sys.store.runlock()
  2090  
  2091  	var availablePolicies []iampolicy.Policy
  2092  	for _, pname := range policies {
  2093  		p, found := sys.iamPolicyDocsMap[pname]
  2094  		if found {
  2095  			availablePolicies = append(availablePolicies, p)
  2096  		}
  2097  	}
  2098  
  2099  	if len(availablePolicies) == 0 {
  2100  		return iampolicy.Policy{}
  2101  	}
  2102  
  2103  	combinedPolicy := availablePolicies[0]
  2104  	for i := 1; i < len(availablePolicies); i++ {
  2105  		combinedPolicy.Statements = append(combinedPolicy.Statements,
  2106  			availablePolicies[i].Statements...)
  2107  	}
  2108  
  2109  	return combinedPolicy
  2110  }
  2111  
  2112  // IsAllowed - checks given policy args is allowed to continue the Rest API.
  2113  func (sys *IAMSys) IsAllowed(args iampolicy.Args) bool {
  2114  	// If opa is configured, use OPA always.
  2115  	if GlobalPolicyOPA != nil {
  2116  		ok, err := GlobalPolicyOPA.IsAllowed(args)
  2117  		if err != nil {
  2118  			logger.LogIf(GlobalContext, err)
  2119  		}
  2120  		return ok
  2121  	}
  2122  
  2123  	// Policies don't apply to the owner.
  2124  	if args.IsOwner {
  2125  		return true
  2126  	}
  2127  
  2128  	// If the credential is temporary, perform STS related checks.
  2129  	ok, parentUser, err := sys.IsTempUser(args.AccountName)
  2130  	if err != nil {
  2131  		return false
  2132  	}
  2133  	if ok {
  2134  		return sys.IsAllowedSTS(args, parentUser)
  2135  	}
  2136  
  2137  	// If the credential is for a service account, perform related check
  2138  	ok, parentUser, err = sys.IsServiceAccount(args.AccountName)
  2139  	if err != nil {
  2140  		return false
  2141  	}
  2142  	if ok {
  2143  		return sys.IsAllowedServiceAccount(args, parentUser)
  2144  	}
  2145  
  2146  	// Continue with the assumption of a regular user
  2147  	policies, err := sys.PolicyDBGet(args.AccountName, false, args.Groups...)
  2148  	if err != nil {
  2149  		return false
  2150  	}
  2151  
  2152  	if len(policies) == 0 {
  2153  		// No policy found.
  2154  		return false
  2155  	}
  2156  
  2157  	// Policies were found, evaluate all of them.
  2158  	return sys.GetCombinedPolicy(policies...).IsAllowed(args)
  2159  }
  2160  
  2161  // Set default canned policies only if not already overridden by users.
  2162  func setDefaultCannedPolicies(policies map[string]iampolicy.Policy) {
  2163  	_, ok := policies["writeonly"]
  2164  	if !ok {
  2165  		policies["writeonly"] = iampolicy.WriteOnly
  2166  	}
  2167  	_, ok = policies["readonly"]
  2168  	if !ok {
  2169  		policies["readonly"] = iampolicy.ReadOnly
  2170  	}
  2171  	_, ok = policies["readwrite"]
  2172  	if !ok {
  2173  		policies["readwrite"] = iampolicy.ReadWrite
  2174  	}
  2175  	_, ok = policies["diagnostics"]
  2176  	if !ok {
  2177  		policies["diagnostics"] = iampolicy.AdminDiagnostics
  2178  	}
  2179  	_, ok = policies["consoleAdmin"]
  2180  	if !ok {
  2181  		policies["consoleAdmin"] = iampolicy.Admin
  2182  	}
  2183  }
  2184  
  2185  // buildUserGroupMemberships - builds the memberships map. IMPORTANT:
  2186  // Assumes that sys.Lock is held by caller.
  2187  func (sys *IAMSys) buildUserGroupMemberships() {
  2188  	for group, gi := range sys.iamGroupsMap {
  2189  		sys.updateGroupMembershipsMap(group, &gi)
  2190  	}
  2191  }
  2192  
  2193  // updateGroupMembershipsMap - updates the memberships map for a
  2194  // group. IMPORTANT: Assumes sys.Lock() is held by caller.
  2195  func (sys *IAMSys) updateGroupMembershipsMap(group string, gi *GroupInfo) {
  2196  	if gi == nil {
  2197  		return
  2198  	}
  2199  	for _, member := range gi.Members {
  2200  		v := sys.iamUserGroupMemberships[member]
  2201  		if v == nil {
  2202  			v = set.CreateStringSet(group)
  2203  		} else {
  2204  			v.Add(group)
  2205  		}
  2206  		sys.iamUserGroupMemberships[member] = v
  2207  	}
  2208  }
  2209  
  2210  // removeGroupFromMembershipsMap - removes the group from every member
  2211  // in the cache. IMPORTANT: Assumes sys.Lock() is held by caller.
  2212  func (sys *IAMSys) removeGroupFromMembershipsMap(group string) {
  2213  	for member, groups := range sys.iamUserGroupMemberships {
  2214  		if !groups.Contains(group) {
  2215  			continue
  2216  		}
  2217  		groups.Remove(group)
  2218  		sys.iamUserGroupMemberships[member] = groups
  2219  	}
  2220  }
  2221  
  2222  // EnableLDAPSys - enable ldap system users type.
  2223  func (sys *IAMSys) EnableLDAPSys() {
  2224  	sys.usersSysType = LDAPUsersSysType
  2225  }
  2226  
  2227  // NewIAMSys - creates new config system object.
  2228  func NewIAMSys() *IAMSys {
  2229  	return &IAMSys{
  2230  		usersSysType:            MinIOUsersSysType,
  2231  		iamUsersMap:             make(map[string]auth.Credentials),
  2232  		iamPolicyDocsMap:        make(map[string]iampolicy.Policy),
  2233  		iamUserPolicyMap:        make(map[string]MappedPolicy),
  2234  		iamGroupPolicyMap:       make(map[string]MappedPolicy),
  2235  		iamGroupsMap:            make(map[string]GroupInfo),
  2236  		iamUserGroupMemberships: make(map[string]set.StringSet),
  2237  		configLoaded:            make(chan struct{}),
  2238  	}
  2239  }