mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
				
	
	
		
			1817 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			1817 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
|  * MinIO Cloud Storage, (C) 2018-2019 MinIO, Inc.
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package cmd
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"context"
 | |
| 	"encoding/base64"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/minio/minio-go/v6/pkg/set"
 | |
| 	"github.com/minio/minio/cmd/config"
 | |
| 	"github.com/minio/minio/cmd/logger"
 | |
| 	"github.com/minio/minio/pkg/auth"
 | |
| 	"github.com/minio/minio/pkg/bucket/policy"
 | |
| 	iampolicy "github.com/minio/minio/pkg/iam/policy"
 | |
| 	"github.com/minio/minio/pkg/madmin"
 | |
| )
 | |
| 
 | |
| // UsersSysType - defines the type of users and groups system that is
 | |
| // active on the server.
 | |
| type UsersSysType string
 | |
| 
 | |
| // Types of users configured in the server.
 | |
| const (
 | |
| 	// This mode uses the internal users system in MinIO.
 | |
| 	MinIOUsersSysType UsersSysType = "MinIOUsersSys"
 | |
| 
 | |
| 	// This mode uses users and groups from a configured LDAP
 | |
| 	// server.
 | |
| 	LDAPUsersSysType UsersSysType = "LDAPUsersSys"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// IAM configuration directory.
 | |
| 	iamConfigPrefix = minioConfigPrefix + "/iam"
 | |
| 
 | |
| 	// IAM users directory.
 | |
| 	iamConfigUsersPrefix = iamConfigPrefix + "/users/"
 | |
| 
 | |
| 	// IAM service accounts directory.
 | |
| 	iamConfigServiceAccountsPrefix = iamConfigPrefix + "/service-accounts/"
 | |
| 
 | |
| 	// IAM groups directory.
 | |
| 	iamConfigGroupsPrefix = iamConfigPrefix + "/groups/"
 | |
| 
 | |
| 	// IAM policies directory.
 | |
| 	iamConfigPoliciesPrefix = iamConfigPrefix + "/policies/"
 | |
| 
 | |
| 	// IAM sts directory.
 | |
| 	iamConfigSTSPrefix = iamConfigPrefix + "/sts/"
 | |
| 
 | |
| 	// IAM Policy DB prefixes.
 | |
| 	iamConfigPolicyDBPrefix                = iamConfigPrefix + "/policydb/"
 | |
| 	iamConfigPolicyDBUsersPrefix           = iamConfigPolicyDBPrefix + "users/"
 | |
| 	iamConfigPolicyDBSTSUsersPrefix        = iamConfigPolicyDBPrefix + "sts-users/"
 | |
| 	iamConfigPolicyDBServiceAccountsPrefix = iamConfigPolicyDBPrefix + "service-accounts/"
 | |
| 	iamConfigPolicyDBGroupsPrefix          = iamConfigPolicyDBPrefix + "groups/"
 | |
| 
 | |
| 	// IAM identity file which captures identity credentials.
 | |
| 	iamIdentityFile = "identity.json"
 | |
| 
 | |
| 	// IAM policy file which provides policies for each users.
 | |
| 	iamPolicyFile = "policy.json"
 | |
| 
 | |
| 	// IAM group members file
 | |
| 	iamGroupMembersFile = "members.json"
 | |
| 
 | |
| 	// IAM format file
 | |
| 	iamFormatFile = "format.json"
 | |
| 
 | |
| 	iamFormatVersion1 = 1
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	statusEnabled  = "enabled"
 | |
| 	statusDisabled = "disabled"
 | |
| )
 | |
| 
 | |
| type iamFormat struct {
 | |
| 	Version int `json:"version"`
 | |
| }
 | |
| 
 | |
| func newIAMFormatVersion1() iamFormat {
 | |
| 	return iamFormat{Version: iamFormatVersion1}
 | |
| }
 | |
| 
 | |
| func getIAMFormatFilePath() string {
 | |
| 	return iamConfigPrefix + SlashSeparator + iamFormatFile
 | |
| }
 | |
| 
 | |
| func getUserIdentityPath(user string, userType IAMUserType) string {
 | |
| 	var basePath string
 | |
| 	switch userType {
 | |
| 	case srvAccUser:
 | |
| 		basePath = iamConfigServiceAccountsPrefix
 | |
| 	case stsUser:
 | |
| 		basePath = iamConfigSTSPrefix
 | |
| 	default:
 | |
| 		basePath = iamConfigUsersPrefix
 | |
| 	}
 | |
| 	return pathJoin(basePath, user, iamIdentityFile)
 | |
| }
 | |
| 
 | |
| func getGroupInfoPath(group string) string {
 | |
| 	return pathJoin(iamConfigGroupsPrefix, group, iamGroupMembersFile)
 | |
| }
 | |
| 
 | |
| func getPolicyDocPath(name string) string {
 | |
| 	return pathJoin(iamConfigPoliciesPrefix, name, iamPolicyFile)
 | |
| }
 | |
| 
 | |
| func getMappedPolicyPath(name string, userType IAMUserType, isGroup bool) string {
 | |
| 	if isGroup {
 | |
| 		return pathJoin(iamConfigPolicyDBGroupsPrefix, name+".json")
 | |
| 	}
 | |
| 	switch userType {
 | |
| 	case srvAccUser:
 | |
| 		return pathJoin(iamConfigPolicyDBServiceAccountsPrefix, name+".json")
 | |
| 	case stsUser:
 | |
| 		return pathJoin(iamConfigPolicyDBSTSUsersPrefix, name+".json")
 | |
| 	default:
 | |
| 		return pathJoin(iamConfigPolicyDBUsersPrefix, name+".json")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // UserIdentity represents a user's secret key and their status
 | |
| type UserIdentity struct {
 | |
| 	Version     int              `json:"version"`
 | |
| 	Credentials auth.Credentials `json:"credentials"`
 | |
| }
 | |
| 
 | |
| func newUserIdentity(creds auth.Credentials) UserIdentity {
 | |
| 	return UserIdentity{Version: 1, Credentials: creds}
 | |
| }
 | |
| 
 | |
| // GroupInfo contains info about a group
 | |
| type GroupInfo struct {
 | |
| 	Version int      `json:"version"`
 | |
| 	Status  string   `json:"status"`
 | |
| 	Members []string `json:"members"`
 | |
| }
 | |
| 
 | |
| func newGroupInfo(members []string) GroupInfo {
 | |
| 	return GroupInfo{Version: 1, Status: statusEnabled, Members: members}
 | |
| }
 | |
| 
 | |
| // MappedPolicy represents a policy name mapped to a user or group
 | |
| type MappedPolicy struct {
 | |
| 	Version int    `json:"version"`
 | |
| 	Policy  string `json:"policy"`
 | |
| }
 | |
| 
 | |
| func newMappedPolicy(policy string) MappedPolicy {
 | |
| 	return MappedPolicy{Version: 1, Policy: policy}
 | |
| }
 | |
| 
 | |
| // IAMSys - config system.
 | |
| type IAMSys struct {
 | |
| 	sync.RWMutex
 | |
| 
 | |
| 	usersSysType UsersSysType
 | |
| 
 | |
| 	// map of policy names to policy definitions
 | |
| 	iamPolicyDocsMap map[string]iampolicy.Policy
 | |
| 	// map of usernames to credentials
 | |
| 	iamUsersMap map[string]auth.Credentials
 | |
| 	// map of group names to group info
 | |
| 	iamGroupsMap map[string]GroupInfo
 | |
| 	// map of user names to groups they are a member of
 | |
| 	iamUserGroupMemberships map[string]set.StringSet
 | |
| 	// map of usernames/temporary access keys to policy names
 | |
| 	iamUserPolicyMap map[string]MappedPolicy
 | |
| 	// map of group names to policy names
 | |
| 	iamGroupPolicyMap map[string]MappedPolicy
 | |
| 
 | |
| 	// Persistence layer for IAM subsystem
 | |
| 	store IAMStorageAPI
 | |
| }
 | |
| 
 | |
| // IAMUserType represents a user type inside MinIO server
 | |
| type IAMUserType int
 | |
| 
 | |
| const (
 | |
| 	regularUser IAMUserType = iota
 | |
| 	stsUser
 | |
| 	srvAccUser
 | |
| )
 | |
| 
 | |
| // IAMStorageAPI defines an interface for the IAM persistence layer
 | |
| type IAMStorageAPI interface {
 | |
| 	migrateBackendFormat(ObjectLayer) error
 | |
| 
 | |
| 	loadPolicyDoc(policy string, m map[string]iampolicy.Policy) error
 | |
| 	loadPolicyDocs(m map[string]iampolicy.Policy) error
 | |
| 
 | |
| 	loadUser(user string, userType IAMUserType, m map[string]auth.Credentials) error
 | |
| 	loadUsers(userType IAMUserType, m map[string]auth.Credentials) error
 | |
| 
 | |
| 	loadGroup(group string, m map[string]GroupInfo) error
 | |
| 	loadGroups(m map[string]GroupInfo) error
 | |
| 
 | |
| 	loadMappedPolicy(name string, userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error
 | |
| 	loadMappedPolicies(userType IAMUserType, isGroup bool, m map[string]MappedPolicy) error
 | |
| 
 | |
| 	loadAll(*IAMSys, ObjectLayer) error
 | |
| 
 | |
| 	saveIAMConfig(item interface{}, path string) error
 | |
| 	loadIAMConfig(item interface{}, path string) error
 | |
| 	deleteIAMConfig(path string) error
 | |
| 
 | |
| 	savePolicyDoc(policyName string, p iampolicy.Policy) error
 | |
| 	saveMappedPolicy(name string, userType IAMUserType, isGroup bool, mp MappedPolicy) error
 | |
| 	saveUserIdentity(name string, userType IAMUserType, u UserIdentity) error
 | |
| 	saveGroupInfo(group string, gi GroupInfo) error
 | |
| 
 | |
| 	deletePolicyDoc(policyName string) error
 | |
| 	deleteMappedPolicy(name string, userType IAMUserType, isGroup bool) error
 | |
| 	deleteUserIdentity(name string, userType IAMUserType) error
 | |
| 	deleteGroupInfo(name string) error
 | |
| 
 | |
| 	watch(*IAMSys)
 | |
| }
 | |
| 
 | |
| // LoadGroup - loads a specific group from storage, and updates the
 | |
| // memberships cache. If the specified group does not exist in
 | |
| // storage, it is removed from in-memory maps as well - this
 | |
| // simplifies the implementation for group removal. This is called
 | |
| // only via IAM notifications.
 | |
| func (sys *IAMSys) LoadGroup(objAPI ObjectLayer, group string) error {
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if objAPI == nil || sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if globalEtcdClient != nil {
 | |
| 		// Watch APIs cover this case, so nothing to do.
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	err := sys.store.loadGroup(group, sys.iamGroupsMap)
 | |
| 	if err != nil && err != errConfigNotFound {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if err == errConfigNotFound {
 | |
| 		// group does not exist - so remove from memory.
 | |
| 		sys.removeGroupFromMembershipsMap(group)
 | |
| 		delete(sys.iamGroupsMap, group)
 | |
| 		delete(sys.iamGroupPolicyMap, group)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	gi := sys.iamGroupsMap[group]
 | |
| 
 | |
| 	// Updating the group memberships cache happens in two steps:
 | |
| 	//
 | |
| 	// 1. Remove the group from each user's list of memberships.
 | |
| 	// 2. Add the group to each member's list of memberships.
 | |
| 	//
 | |
| 	// This ensures that regardless of members being added or
 | |
| 	// removed, the cache stays current.
 | |
| 	sys.removeGroupFromMembershipsMap(group)
 | |
| 	sys.updateGroupMembershipsMap(group, &gi)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // LoadPolicy - reloads a specific canned policy from backend disks or etcd.
 | |
| func (sys *IAMSys) LoadPolicy(objAPI ObjectLayer, policyName string) error {
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if objAPI == nil || sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if globalEtcdClient == nil {
 | |
| 		return sys.store.loadPolicyDoc(policyName, sys.iamPolicyDocsMap)
 | |
| 	}
 | |
| 
 | |
| 	// When etcd is set, we use watch APIs so this code is not needed.
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // LoadPolicyMapping - loads the mapped policy for a user or group
 | |
| // from storage into server memory.
 | |
| func (sys *IAMSys) LoadPolicyMapping(objAPI ObjectLayer, userOrGroup string, isGroup bool) error {
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if objAPI == nil || sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if globalEtcdClient == nil {
 | |
| 		var err error
 | |
| 		if isGroup {
 | |
| 			err = sys.store.loadMappedPolicy(userOrGroup, regularUser, isGroup, sys.iamGroupPolicyMap)
 | |
| 		} else {
 | |
| 			err = sys.store.loadMappedPolicy(userOrGroup, regularUser, isGroup, sys.iamUserPolicyMap)
 | |
| 		}
 | |
| 
 | |
| 		// Ignore policy not mapped error
 | |
| 		if err != nil && err != errConfigNotFound {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	// When etcd is set, we use watch APIs so this code is not needed.
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // LoadUser - reloads a specific user from backend disks or etcd.
 | |
| func (sys *IAMSys) LoadUser(objAPI ObjectLayer, accessKey string, userType IAMUserType) error {
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if objAPI == nil || sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if globalEtcdClient == nil {
 | |
| 		err := sys.store.loadUser(accessKey, userType, sys.iamUsersMap)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		err = sys.store.loadMappedPolicy(accessKey, userType, false, sys.iamUserPolicyMap)
 | |
| 		// Ignore policy not mapped error
 | |
| 		if err != nil && err != errConfigNotFound {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	// When etcd is set, we use watch APIs so this code is not needed.
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Load - loads iam subsystem
 | |
| func (sys *IAMSys) Load() error {
 | |
| 	// Pass nil objectlayer here - it will be loaded internally
 | |
| 	// from the IAMStorageAPI.
 | |
| 	return sys.store.loadAll(sys, nil)
 | |
| }
 | |
| 
 | |
| // Perform IAM configuration migration.
 | |
| func (sys *IAMSys) doIAMConfigMigration(objAPI ObjectLayer) error {
 | |
| 	return sys.store.migrateBackendFormat(objAPI)
 | |
| }
 | |
| 
 | |
| // Init - initializes config system from iam.json
 | |
| func (sys *IAMSys) Init(objAPI ObjectLayer) error {
 | |
| 	if objAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	if globalEtcdClient == nil {
 | |
| 		sys.store = newIAMObjectStore()
 | |
| 	} else {
 | |
| 		sys.store = newIAMEtcdStore()
 | |
| 	}
 | |
| 	sys.Unlock()
 | |
| 
 | |
| 	// Migrate IAM configuration
 | |
| 	if err := sys.doIAMConfigMigration(objAPI); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sys.store.watch(sys)
 | |
| 	err := sys.store.loadAll(sys, objAPI)
 | |
| 
 | |
| 	// Invalidate the old cred after finishing IAM initialization
 | |
| 	globalOldCred = auth.Credentials{}
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // DeletePolicy - deletes a canned policy from backend or etcd.
 | |
| func (sys *IAMSys) DeletePolicy(policyName string) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if policyName == "" {
 | |
| 		return errInvalidArgument
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	err := sys.store.deletePolicyDoc(policyName)
 | |
| 	switch err.(type) {
 | |
| 	case ObjectNotFound:
 | |
| 		// Ignore error if policy is already deleted.
 | |
| 		err = nil
 | |
| 	}
 | |
| 
 | |
| 	delete(sys.iamPolicyDocsMap, policyName)
 | |
| 
 | |
| 	// Delete user-policy mappings that will no longer apply
 | |
| 	var usersToDel []string
 | |
| 	var usersType []IAMUserType
 | |
| 	for u, mp := range sys.iamUserPolicyMap {
 | |
| 		if mp.Policy == policyName {
 | |
| 			usersToDel = append(usersToDel, u)
 | |
| 			cr, ok := sys.iamUsersMap[u]
 | |
| 			if !ok {
 | |
| 				// This case cannot happen
 | |
| 				return errNoSuchUser
 | |
| 			}
 | |
| 			// User is from STS if the creds are temporary
 | |
| 			if cr.IsTemp() {
 | |
| 				usersType = append(usersType, stsUser)
 | |
| 			} else {
 | |
| 				usersType = append(usersType, regularUser)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	for i, u := range usersToDel {
 | |
| 		sys.policyDBSet(u, "", usersType[i], false)
 | |
| 	}
 | |
| 
 | |
| 	// Delete group-policy mappings that will no longer apply
 | |
| 	var groupsToDel []string
 | |
| 	for g, mp := range sys.iamGroupPolicyMap {
 | |
| 		if mp.Policy == policyName {
 | |
| 			groupsToDel = append(groupsToDel, g)
 | |
| 		}
 | |
| 	}
 | |
| 	for _, g := range groupsToDel {
 | |
| 		sys.policyDBSet(g, "", regularUser, true)
 | |
| 	}
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // InfoPolicy - expands the canned policy into its JSON structure.
 | |
| func (sys *IAMSys) InfoPolicy(policyName string) ([]byte, error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return nil, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	v, ok := sys.iamPolicyDocsMap[policyName]
 | |
| 	if !ok {
 | |
| 		return nil, errNoSuchPolicy
 | |
| 	}
 | |
| 	return json.Marshal(v)
 | |
| }
 | |
| 
 | |
| // ListPolicies - lists all canned policies.
 | |
| func (sys *IAMSys) ListPolicies() (map[string][]byte, error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return nil, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	var policyDocsMap = make(map[string][]byte)
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	for k, v := range sys.iamPolicyDocsMap {
 | |
| 		data, err := json.Marshal(v)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		policyDocsMap[k] = data
 | |
| 	}
 | |
| 
 | |
| 	return policyDocsMap, nil
 | |
| }
 | |
| 
 | |
| // SetPolicy - sets a new name policy.
 | |
| func (sys *IAMSys) SetPolicy(policyName string, p iampolicy.Policy) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if p.IsEmpty() || policyName == "" {
 | |
| 		return errInvalidArgument
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if err := sys.store.savePolicyDoc(policyName, p); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sys.iamPolicyDocsMap[policyName] = p
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // DeleteUser - delete user (only for long-term users not STS users).
 | |
| func (sys *IAMSys) DeleteUser(accessKey string) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	// First we remove the user from their groups.
 | |
| 	userInfo, getErr := sys.GetUserInfo(accessKey)
 | |
| 	if getErr != nil {
 | |
| 		return getErr
 | |
| 	}
 | |
| 	for _, group := range userInfo.MemberOf {
 | |
| 		removeErr := sys.RemoveUsersFromGroup(group, []string{accessKey})
 | |
| 		if removeErr != nil {
 | |
| 			return removeErr
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Next we can remove the user from memory and IAM store
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	// It is ok to ignore deletion error on the mapped policy
 | |
| 	sys.store.deleteMappedPolicy(accessKey, regularUser, false)
 | |
| 	err := sys.store.deleteUserIdentity(accessKey, regularUser)
 | |
| 	switch err.(type) {
 | |
| 	case ObjectNotFound:
 | |
| 		// ignore if user is already deleted.
 | |
| 		err = nil
 | |
| 	}
 | |
| 
 | |
| 	delete(sys.iamUsersMap, accessKey)
 | |
| 	delete(sys.iamUserPolicyMap, accessKey)
 | |
| 
 | |
| 	for _, u := range sys.iamUsersMap {
 | |
| 		if u.IsServiceAccount() {
 | |
| 			if u.ParentUser == accessKey {
 | |
| 				_ = sys.store.deleteUserIdentity(u.AccessKey, srvAccUser)
 | |
| 				delete(sys.iamUsersMap, u.AccessKey)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // SetTempUser - set temporary user credentials, these credentials have an expiry.
 | |
| func (sys *IAMSys) SetTempUser(accessKey string, cred auth.Credentials, policyName string) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	// If OPA is not set we honor any policy claims for this
 | |
| 	// temporary user which match with pre-configured canned
 | |
| 	// policies for this server.
 | |
| 	if globalPolicyOPA == nil && policyName != "" {
 | |
| 		p, ok := sys.iamPolicyDocsMap[policyName]
 | |
| 		if !ok {
 | |
| 			return errInvalidArgument
 | |
| 		}
 | |
| 		if p.IsEmpty() {
 | |
| 			delete(sys.iamUserPolicyMap, accessKey)
 | |
| 			return nil
 | |
| 		}
 | |
| 
 | |
| 		if sys.store == nil {
 | |
| 			return errServerNotInitialized
 | |
| 		}
 | |
| 
 | |
| 		mp := newMappedPolicy(policyName)
 | |
| 		if err := sys.store.saveMappedPolicy(accessKey, stsUser, false, mp); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		sys.iamUserPolicyMap[accessKey] = mp
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	u := newUserIdentity(cred)
 | |
| 	if err := sys.store.saveUserIdentity(accessKey, stsUser, u); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sys.iamUsersMap[accessKey] = cred
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // ListUsers - list all users.
 | |
| func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return nil, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	var users = make(map[string]madmin.UserInfo)
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return nil, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	for k, v := range sys.iamUsersMap {
 | |
| 		if !v.IsTemp() && !v.IsServiceAccount() {
 | |
| 			users[k] = madmin.UserInfo{
 | |
| 				PolicyName: sys.iamUserPolicyMap[k].Policy,
 | |
| 				Status: func() madmin.AccountStatus {
 | |
| 					if v.IsValid() {
 | |
| 						return madmin.AccountEnabled
 | |
| 					}
 | |
| 					return madmin.AccountDisabled
 | |
| 				}(),
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return users, nil
 | |
| }
 | |
| 
 | |
| // IsTempUser - returns if given key is a temporary user.
 | |
| func (sys *IAMSys) IsTempUser(name string) (bool, error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return false, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	creds, found := sys.iamUsersMap[name]
 | |
| 	if !found {
 | |
| 		return false, errNoSuchUser
 | |
| 	}
 | |
| 
 | |
| 	return creds.IsTemp(), nil
 | |
| }
 | |
| 
 | |
| // IsServiceAccount - returns if given key is a service account
 | |
| func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return false, "", errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	creds, found := sys.iamUsersMap[name]
 | |
| 	if !found {
 | |
| 		return false, "", errNoSuchUser
 | |
| 	}
 | |
| 
 | |
| 	if creds.IsServiceAccount() {
 | |
| 		return true, creds.ParentUser, nil
 | |
| 	}
 | |
| 
 | |
| 	return false, "", nil
 | |
| }
 | |
| 
 | |
| // GetUserInfo - get info on a user.
 | |
| func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return u, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return madmin.UserInfo{
 | |
| 			PolicyName: sys.iamUserPolicyMap[name].Policy,
 | |
| 			MemberOf:   sys.iamUserGroupMemberships[name].ToSlice(),
 | |
| 		}, nil
 | |
| 	}
 | |
| 
 | |
| 	creds, found := sys.iamUsersMap[name]
 | |
| 	if !found {
 | |
| 		return u, errNoSuchUser
 | |
| 	}
 | |
| 
 | |
| 	if creds.IsTemp() {
 | |
| 		return u, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	u = madmin.UserInfo{
 | |
| 		PolicyName: sys.iamUserPolicyMap[name].Policy,
 | |
| 		Status: func() madmin.AccountStatus {
 | |
| 			if creds.IsValid() {
 | |
| 				return madmin.AccountEnabled
 | |
| 			}
 | |
| 			return madmin.AccountDisabled
 | |
| 		}(),
 | |
| 		MemberOf: sys.iamUserGroupMemberships[name].ToSlice(),
 | |
| 	}
 | |
| 	return u, nil
 | |
| }
 | |
| 
 | |
| // SetUserStatus - sets current user status, supports disabled or enabled.
 | |
| func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if status != madmin.AccountEnabled && status != madmin.AccountDisabled {
 | |
| 		return errInvalidArgument
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	cred, ok := sys.iamUsersMap[accessKey]
 | |
| 	if !ok {
 | |
| 		return errNoSuchUser
 | |
| 	}
 | |
| 
 | |
| 	if cred.IsTemp() {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	uinfo := newUserIdentity(auth.Credentials{
 | |
| 		AccessKey: accessKey,
 | |
| 		SecretKey: cred.SecretKey,
 | |
| 		Status: func() string {
 | |
| 			if status == madmin.AccountEnabled {
 | |
| 				return config.EnableOn
 | |
| 			}
 | |
| 			return config.EnableOff
 | |
| 		}(),
 | |
| 	})
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if err := sys.store.saveUserIdentity(accessKey, regularUser, uinfo); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sys.iamUsersMap[accessKey] = uinfo.Credentials
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // NewServiceAccount - create a new service account
 | |
| func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser, sessionPolicy string) (auth.Credentials, error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return auth.Credentials{}, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if len(sessionPolicy) > 16*1024 {
 | |
| 		return auth.Credentials{}, fmt.Errorf("Session policy should not exceed 16*1024 characters")
 | |
| 	}
 | |
| 
 | |
| 	policy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(sessionPolicy)))
 | |
| 	if err != nil {
 | |
| 		return auth.Credentials{}, err
 | |
| 	}
 | |
| 
 | |
| 	// Version in policy must not be empty
 | |
| 	if policy.Version == "" {
 | |
| 		return auth.Credentials{}, fmt.Errorf("Invalid session policy version")
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return auth.Credentials{}, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return auth.Credentials{}, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if parentUser == globalActiveCred.AccessKey {
 | |
| 		return auth.Credentials{}, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	cr, ok := sys.iamUsersMap[parentUser]
 | |
| 	if !ok {
 | |
| 		return auth.Credentials{}, errNoSuchUser
 | |
| 	}
 | |
| 
 | |
| 	if cr.IsTemp() {
 | |
| 		return auth.Credentials{}, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	m := make(map[string]interface{})
 | |
| 	m[iampolicy.SessionPolicyName] = base64.StdEncoding.EncodeToString([]byte(sessionPolicy))
 | |
| 	m[parentClaim] = parentUser
 | |
| 	m[iamPolicyClaimName()] = "embedded-policy"
 | |
| 
 | |
| 	secret := globalActiveCred.SecretKey
 | |
| 	cred, err := auth.GetNewCredentialsWithMetadata(m, secret)
 | |
| 	if err != nil {
 | |
| 		return auth.Credentials{}, err
 | |
| 	}
 | |
| 
 | |
| 	cred.ParentUser = parentUser
 | |
| 	u := newUserIdentity(cred)
 | |
| 
 | |
| 	if err := sys.store.saveUserIdentity(u.Credentials.AccessKey, srvAccUser, u); err != nil {
 | |
| 		return auth.Credentials{}, err
 | |
| 	}
 | |
| 
 | |
| 	sys.iamUsersMap[u.Credentials.AccessKey] = u.Credentials
 | |
| 
 | |
| 	return cred, nil
 | |
| }
 | |
| 
 | |
| // GetServiceAccount - returns the credentials of the given service account
 | |
| func (sys *IAMSys) GetServiceAccount(ctx context.Context, serviceAccountAccessKey string) (auth.Credentials, error) {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return auth.Credentials{}, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return auth.Credentials{}, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return auth.Credentials{}, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	cr, ok := sys.iamUsersMap[serviceAccountAccessKey]
 | |
| 	if !ok {
 | |
| 		return auth.Credentials{}, errNoSuchUser
 | |
| 	}
 | |
| 
 | |
| 	if !cr.IsServiceAccount() {
 | |
| 		return auth.Credentials{}, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	return cr, nil
 | |
| }
 | |
| 
 | |
| // SetUser - set user credentials and policy.
 | |
| func (sys *IAMSys) SetUser(accessKey string, uinfo madmin.UserInfo) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	u := newUserIdentity(auth.Credentials{
 | |
| 		AccessKey: accessKey,
 | |
| 		SecretKey: uinfo.SecretKey,
 | |
| 		Status:    string(uinfo.Status),
 | |
| 	})
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	cr, ok := sys.iamUsersMap[accessKey]
 | |
| 	if cr.IsTemp() && ok {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	if err := sys.store.saveUserIdentity(accessKey, regularUser, u); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sys.iamUsersMap[accessKey] = u.Credentials
 | |
| 
 | |
| 	// Set policy if specified.
 | |
| 	if uinfo.PolicyName != "" {
 | |
| 		return sys.policyDBSet(accessKey, uinfo.PolicyName, regularUser, false)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // SetUserSecretKey - sets user secret key
 | |
| func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	cred, ok := sys.iamUsersMap[accessKey]
 | |
| 	if !ok {
 | |
| 		return errNoSuchUser
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	cred.SecretKey = secretKey
 | |
| 	u := newUserIdentity(cred)
 | |
| 	if err := sys.store.saveUserIdentity(accessKey, regularUser, u); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sys.iamUsersMap[accessKey] = cred
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetUser - get user credentials
 | |
| func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) {
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	cred, ok = sys.iamUsersMap[accessKey]
 | |
| 	return cred, ok && cred.IsValid()
 | |
| }
 | |
| 
 | |
| // AddUsersToGroup - adds users to a group, creating the group if
 | |
| // needed. No error if user(s) already are in the group.
 | |
| func (sys *IAMSys) AddUsersToGroup(group string, members []string) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if group == "" {
 | |
| 		return errInvalidArgument
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	// Validate that all members exist.
 | |
| 	for _, member := range members {
 | |
| 		cr, ok := sys.iamUsersMap[member]
 | |
| 		if !ok {
 | |
| 			return errNoSuchUser
 | |
| 		}
 | |
| 		if cr.IsTemp() {
 | |
| 			return errIAMActionNotAllowed
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	gi, ok := sys.iamGroupsMap[group]
 | |
| 	if !ok {
 | |
| 		// Set group as enabled by default when it doesn't
 | |
| 		// exist.
 | |
| 		gi = newGroupInfo(members)
 | |
| 	} else {
 | |
| 		mergedMembers := append(gi.Members, members...)
 | |
| 		uniqMembers := set.CreateStringSet(mergedMembers...).ToSlice()
 | |
| 		gi.Members = uniqMembers
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if err := sys.store.saveGroupInfo(group, gi); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sys.iamGroupsMap[group] = gi
 | |
| 
 | |
| 	// update user-group membership map
 | |
| 	for _, member := range members {
 | |
| 		gset := sys.iamUserGroupMemberships[member]
 | |
| 		if gset == nil {
 | |
| 			gset = set.CreateStringSet(group)
 | |
| 		} else {
 | |
| 			gset.Add(group)
 | |
| 		}
 | |
| 		sys.iamUserGroupMemberships[member] = gset
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // RemoveUsersFromGroup - remove users from group. If no users are
 | |
| // given, and the group is empty, deletes the group as well.
 | |
| func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if group == "" {
 | |
| 		return errInvalidArgument
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	// Validate that all members exist.
 | |
| 	for _, member := range members {
 | |
| 		cr, ok := sys.iamUsersMap[member]
 | |
| 		if !ok {
 | |
| 			return errNoSuchUser
 | |
| 		}
 | |
| 		if cr.IsTemp() {
 | |
| 			return errIAMActionNotAllowed
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	gi, ok := sys.iamGroupsMap[group]
 | |
| 	if !ok {
 | |
| 		return errNoSuchGroup
 | |
| 	}
 | |
| 
 | |
| 	// Check if attempting to delete a non-empty group.
 | |
| 	if len(members) == 0 && len(gi.Members) != 0 {
 | |
| 		return errGroupNotEmpty
 | |
| 	}
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if len(members) == 0 {
 | |
| 		// len(gi.Members) == 0 here.
 | |
| 
 | |
| 		// Remove the group from storage. First delete the
 | |
| 		// mapped policy.
 | |
| 		err := sys.store.deleteMappedPolicy(group, regularUser, true)
 | |
| 		// No-mapped-policy case is ignored.
 | |
| 		if err != nil && err != errConfigNotFound {
 | |
| 			return err
 | |
| 		}
 | |
| 		err = sys.store.deleteGroupInfo(group)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		// Delete from server memory
 | |
| 		delete(sys.iamGroupsMap, group)
 | |
| 		delete(sys.iamGroupPolicyMap, group)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// Only removing members.
 | |
| 	s := set.CreateStringSet(gi.Members...)
 | |
| 	d := set.CreateStringSet(members...)
 | |
| 	gi.Members = s.Difference(d).ToSlice()
 | |
| 
 | |
| 	err := sys.store.saveGroupInfo(group, gi)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	sys.iamGroupsMap[group] = gi
 | |
| 
 | |
| 	// update user-group membership map
 | |
| 	for _, member := range members {
 | |
| 		gset := sys.iamUserGroupMemberships[member]
 | |
| 		if gset == nil {
 | |
| 			continue
 | |
| 		}
 | |
| 		gset.Remove(group)
 | |
| 		sys.iamUserGroupMemberships[member] = gset
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // SetGroupStatus - enable/disabled a group
 | |
| func (sys *IAMSys) SetGroupStatus(group string, enabled bool) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	if group == "" {
 | |
| 		return errInvalidArgument
 | |
| 	}
 | |
| 
 | |
| 	gi, ok := sys.iamGroupsMap[group]
 | |
| 	if !ok {
 | |
| 		return errNoSuchGroup
 | |
| 	}
 | |
| 
 | |
| 	if enabled {
 | |
| 		gi.Status = statusEnabled
 | |
| 	} else {
 | |
| 		gi.Status = statusDisabled
 | |
| 	}
 | |
| 
 | |
| 	if err := sys.store.saveGroupInfo(group, gi); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	sys.iamGroupsMap[group] = gi
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetGroupDescription - builds up group description
 | |
| func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err error) {
 | |
| 	ps, err := sys.PolicyDBGet(group, true)
 | |
| 	if err != nil {
 | |
| 		return gd, err
 | |
| 	}
 | |
| 
 | |
| 	// A group may be mapped to at most one policy.
 | |
| 	policy := ""
 | |
| 	if len(ps) > 0 {
 | |
| 		policy = ps[0]
 | |
| 	}
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return madmin.GroupDesc{
 | |
| 			Name:   group,
 | |
| 			Policy: policy,
 | |
| 		}, nil
 | |
| 	}
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	gi, ok := sys.iamGroupsMap[group]
 | |
| 	if !ok {
 | |
| 		return gd, errNoSuchGroup
 | |
| 	}
 | |
| 
 | |
| 	return madmin.GroupDesc{
 | |
| 		Name:    group,
 | |
| 		Status:  gi.Status,
 | |
| 		Members: gi.Members,
 | |
| 		Policy:  policy,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // ListGroups - lists groups.
 | |
| func (sys *IAMSys) ListGroups() (r []string, err error) {
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	if sys.usersSysType != MinIOUsersSysType {
 | |
| 		return nil, errIAMActionNotAllowed
 | |
| 	}
 | |
| 
 | |
| 	for k := range sys.iamGroupsMap {
 | |
| 		r = append(r, k)
 | |
| 	}
 | |
| 	return r, nil
 | |
| }
 | |
| 
 | |
| // PolicyDBSet - sets a policy for a user or group in the
 | |
| // PolicyDB. This function applies only long-term users. For STS
 | |
| // users, policy is set directly by called sys.policyDBSet().
 | |
| func (sys *IAMSys) PolicyDBSet(name, policy string, isGroup bool) error {
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.Lock()
 | |
| 	defer sys.Unlock()
 | |
| 
 | |
| 	// isSTS is always false when called via PolicyDBSet as policy
 | |
| 	// is never set by an external API call for STS users.
 | |
| 	return sys.policyDBSet(name, policy, regularUser, isGroup)
 | |
| }
 | |
| 
 | |
| // policyDBSet - sets a policy for user in the policy db. Assumes that caller
 | |
| // has sys.Lock(). If policy == "", then policy mapping is removed.
 | |
| func (sys *IAMSys) policyDBSet(name, policy string, userType IAMUserType, isGroup bool) error {
 | |
| 	if sys.store == nil {
 | |
| 		return errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	if name == "" {
 | |
| 		return errInvalidArgument
 | |
| 	}
 | |
| 	if _, ok := sys.iamPolicyDocsMap[policy]; !ok && policy != "" {
 | |
| 		return errNoSuchPolicy
 | |
| 	}
 | |
| 
 | |
| 	if sys.usersSysType == MinIOUsersSysType {
 | |
| 		if !isGroup {
 | |
| 			if _, ok := sys.iamUsersMap[name]; !ok {
 | |
| 				return errNoSuchUser
 | |
| 			}
 | |
| 		} else {
 | |
| 			if _, ok := sys.iamGroupsMap[name]; !ok {
 | |
| 				return errNoSuchGroup
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Handle policy mapping removal
 | |
| 	if policy == "" {
 | |
| 		if err := sys.store.deleteMappedPolicy(name, userType, isGroup); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if !isGroup {
 | |
| 			delete(sys.iamUserPolicyMap, name)
 | |
| 		} else {
 | |
| 			delete(sys.iamGroupPolicyMap, name)
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// Handle policy mapping set/update
 | |
| 	mp := newMappedPolicy(policy)
 | |
| 	if err := sys.store.saveMappedPolicy(name, userType, isGroup, mp); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if !isGroup {
 | |
| 		sys.iamUserPolicyMap[name] = mp
 | |
| 	} else {
 | |
| 		sys.iamGroupPolicyMap[name] = mp
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| var iamAccountReadAccessActions = iampolicy.NewActionSet(
 | |
| 	iampolicy.ListMultipartUploadPartsAction,
 | |
| 	iampolicy.ListBucketMultipartUploadsAction,
 | |
| 	iampolicy.ListBucketAction,
 | |
| 	iampolicy.HeadBucketAction,
 | |
| 	iampolicy.GetObjectAction,
 | |
| 	iampolicy.GetBucketLocationAction,
 | |
| 
 | |
| 	// iampolicy.ListAllMyBucketsAction,
 | |
| )
 | |
| 
 | |
| var iamAccountWriteAccessActions = iampolicy.NewActionSet(
 | |
| 	iampolicy.AbortMultipartUploadAction,
 | |
| 	iampolicy.CreateBucketAction,
 | |
| 	iampolicy.PutObjectAction,
 | |
| 	iampolicy.DeleteObjectAction,
 | |
| 	iampolicy.DeleteBucketAction,
 | |
| )
 | |
| 
 | |
| var iamAccountOtherAccessActions = iampolicy.NewActionSet(
 | |
| 	iampolicy.BypassGovernanceModeAction,
 | |
| 	iampolicy.BypassGovernanceRetentionAction,
 | |
| 	iampolicy.PutObjectRetentionAction,
 | |
| 	iampolicy.GetObjectRetentionAction,
 | |
| 	iampolicy.GetObjectLegalHoldAction,
 | |
| 	iampolicy.PutObjectLegalHoldAction,
 | |
| 	iampolicy.GetBucketObjectLockConfigurationAction,
 | |
| 	iampolicy.PutBucketObjectLockConfigurationAction,
 | |
| 
 | |
| 	iampolicy.ListenBucketNotificationAction,
 | |
| 
 | |
| 	iampolicy.PutBucketLifecycleAction,
 | |
| 	iampolicy.GetBucketLifecycleAction,
 | |
| 
 | |
| 	iampolicy.PutBucketNotificationAction,
 | |
| 	iampolicy.GetBucketNotificationAction,
 | |
| 
 | |
| 	iampolicy.PutBucketPolicyAction,
 | |
| 	iampolicy.DeleteBucketPolicyAction,
 | |
| 	iampolicy.GetBucketPolicyAction,
 | |
| 
 | |
| 	iampolicy.PutBucketEncryptionAction,
 | |
| 	iampolicy.GetBucketEncryptionAction,
 | |
| )
 | |
| 
 | |
| // GetAccountAccess iterates over all policies documents associated to a user
 | |
| // and returns if the user has read and/or write access to any resource.
 | |
| func (sys *IAMSys) GetAccountAccess(accountName, bucket string) (rd, wr, o bool) {
 | |
| 	policies, err := sys.PolicyDBGet(accountName, false)
 | |
| 	if err != nil {
 | |
| 		logger.LogIf(context.Background(), err)
 | |
| 		return false, false, false
 | |
| 	}
 | |
| 
 | |
| 	if len(policies) == 0 {
 | |
| 		// No policy found.
 | |
| 		return false, false, false
 | |
| 	}
 | |
| 
 | |
| 	// Policies were found, evaluate all of them.
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	var availablePolicies []iampolicy.Policy
 | |
| 	for _, pname := range policies {
 | |
| 		p, found := sys.iamPolicyDocsMap[pname]
 | |
| 		if found {
 | |
| 			availablePolicies = append(availablePolicies, p)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(availablePolicies) == 0 {
 | |
| 		return false, false, false
 | |
| 	}
 | |
| 
 | |
| 	combinedPolicy := availablePolicies[0]
 | |
| 	for i := 1; i < len(availablePolicies); i++ {
 | |
| 		combinedPolicy.Statements = append(combinedPolicy.Statements,
 | |
| 			availablePolicies[i].Statements...)
 | |
| 	}
 | |
| 
 | |
| 	allActions := iampolicy.NewActionSet(iampolicy.AllActions)
 | |
| 	for _, st := range combinedPolicy.Statements {
 | |
| 		// Ignore if this is not an allow policy statement
 | |
| 		if st.Effect != policy.Allow {
 | |
| 			continue
 | |
| 		}
 | |
| 		// Fast calculation if there is s3:* permissions to any resource
 | |
| 		if !st.Actions.Intersection(allActions).IsEmpty() {
 | |
| 			rd, wr, o = true, true, true
 | |
| 			break
 | |
| 		}
 | |
| 		if !st.Actions.Intersection(iamAccountReadAccessActions).IsEmpty() {
 | |
| 			rd = true
 | |
| 		}
 | |
| 		if !st.Actions.Intersection(iamAccountWriteAccessActions).IsEmpty() {
 | |
| 			wr = true
 | |
| 		}
 | |
| 		if !st.Actions.Intersection(iamAccountOtherAccessActions).IsEmpty() {
 | |
| 			o = true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // PolicyDBGet - gets policy set on a user or group. Since a user may
 | |
| // be a member of multiple groups, this function returns an array of
 | |
| // applicable policies (each group is mapped to at most one policy).
 | |
| func (sys *IAMSys) PolicyDBGet(name string, isGroup bool) ([]string, error) {
 | |
| 	if name == "" {
 | |
| 		return nil, errInvalidArgument
 | |
| 	}
 | |
| 
 | |
| 	objectAPI := newObjectLayerWithoutSafeModeFn()
 | |
| 	if objectAPI == nil {
 | |
| 		return nil, errServerNotInitialized
 | |
| 	}
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	return sys.policyDBGet(name, isGroup)
 | |
| }
 | |
| 
 | |
| // This call assumes that caller has the sys.RLock()
 | |
| func (sys *IAMSys) policyDBGet(name string, isGroup bool) ([]string, error) {
 | |
| 	if isGroup {
 | |
| 		if _, ok := sys.iamGroupsMap[name]; !ok {
 | |
| 			return nil, errNoSuchGroup
 | |
| 		}
 | |
| 
 | |
| 		policy := sys.iamGroupPolicyMap[name]
 | |
| 		// returned policy could be empty
 | |
| 		if policy.Policy == "" {
 | |
| 			return nil, nil
 | |
| 		}
 | |
| 		return []string{policy.Policy}, nil
 | |
| 	}
 | |
| 
 | |
| 	// When looking for a user's policies, we also check if the
 | |
| 	// user and the groups they are member of are enabled.
 | |
| 	if u, ok := sys.iamUsersMap[name]; !ok {
 | |
| 		return nil, errNoSuchUser
 | |
| 	} else if u.Status == statusDisabled {
 | |
| 		// User is disabled, so we return no policy - this
 | |
| 		// ensures the request is denied.
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 
 | |
| 	result := []string{}
 | |
| 	policy := sys.iamUserPolicyMap[name]
 | |
| 	// returned policy could be empty
 | |
| 	if policy.Policy != "" {
 | |
| 		result = append(result, policy.Policy)
 | |
| 	}
 | |
| 	for _, group := range sys.iamUserGroupMemberships[name].ToSlice() {
 | |
| 		// Skip missing or disabled groups
 | |
| 		gi, ok := sys.iamGroupsMap[group]
 | |
| 		if !ok || gi.Status == statusDisabled {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		p, ok := sys.iamGroupPolicyMap[group]
 | |
| 		if ok && p.Policy != "" {
 | |
| 			result = append(result, p.Policy)
 | |
| 		}
 | |
| 	}
 | |
| 	return result, nil
 | |
| }
 | |
| 
 | |
| // IsAllowedServiceAccount - checks if the given service account is allowed to perform
 | |
| // actions. The permission of the parent user is checked first
 | |
| func (sys *IAMSys) IsAllowedServiceAccount(args iampolicy.Args, parent string) bool {
 | |
| 	// Now check if we have a subject claim
 | |
| 	p, ok := args.Claims[parentClaim]
 | |
| 	if ok {
 | |
| 		parentInClaim, ok := p.(string)
 | |
| 		if !ok {
 | |
| 			// Reject malformed/malicious requests.
 | |
| 			return false
 | |
| 		}
 | |
| 		// The parent claim in the session token should be equal
 | |
| 		// to the parent detected in the backend
 | |
| 		if parentInClaim != parent {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Check if the parent is allowed to perform this action, reject if not
 | |
| 	parentUserPolicies, err := sys.PolicyDBGet(parent, false)
 | |
| 	if err != nil {
 | |
| 		logger.LogIf(context.Background(), err)
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	if len(parentUserPolicies) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	var availablePolicies []iampolicy.Policy
 | |
| 
 | |
| 	// Policies were found, evaluate all of them.
 | |
| 	sys.RLock()
 | |
| 	for _, pname := range parentUserPolicies {
 | |
| 		p, found := sys.iamPolicyDocsMap[pname]
 | |
| 		if found {
 | |
| 			availablePolicies = append(availablePolicies, p)
 | |
| 		}
 | |
| 	}
 | |
| 	sys.RUnlock()
 | |
| 
 | |
| 	if len(availablePolicies) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	combinedPolicy := availablePolicies[0]
 | |
| 	for i := 1; i < len(availablePolicies); i++ {
 | |
| 		combinedPolicy.Statements = append(combinedPolicy.Statements,
 | |
| 			availablePolicies[i].Statements...)
 | |
| 	}
 | |
| 
 | |
| 	serviceAcc := args.AccountName
 | |
| 	args.AccountName = parent
 | |
| 	if !combinedPolicy.IsAllowed(args) {
 | |
| 		return false
 | |
| 	}
 | |
| 	args.AccountName = serviceAcc
 | |
| 
 | |
| 	// Now check if we have a sessionPolicy.
 | |
| 	spolicy, ok := args.Claims[iampolicy.SessionPolicyName]
 | |
| 	if ok {
 | |
| 		spolicyStr, ok := spolicy.(string)
 | |
| 		if !ok {
 | |
| 			// Sub policy if set, should be a string reject
 | |
| 			// malformed/malicious requests.
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		// Check if policy is parseable.
 | |
| 		subPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(spolicyStr)))
 | |
| 		if err != nil {
 | |
| 			// Log any error in input session policy config.
 | |
| 			logger.LogIf(context.Background(), err)
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		// Policy without Version string value reject it.
 | |
| 		if subPolicy.Version == "" {
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		return subPolicy.IsAllowed(args)
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // IsAllowedSTS is meant for STS based temporary credentials,
 | |
| // which implements claims validation and verification other than
 | |
| // applying policies.
 | |
| func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
 | |
| 	// If it is an LDAP request, check that user and group
 | |
| 	// policies allow the request.
 | |
| 	if userIface, ok := args.Claims[ldapUser]; ok {
 | |
| 		var user string
 | |
| 		if u, ok := userIface.(string); ok {
 | |
| 			user = u
 | |
| 		} else {
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		var groups []string
 | |
| 		groupsVal := args.Claims[ldapGroups]
 | |
| 		if g, ok := groupsVal.([]interface{}); ok {
 | |
| 			for _, eachG := range g {
 | |
| 				if eachGStr, ok := eachG.(string); ok {
 | |
| 					groups = append(groups, eachGStr)
 | |
| 				}
 | |
| 			}
 | |
| 		} else {
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		sys.RLock()
 | |
| 		defer sys.RUnlock()
 | |
| 
 | |
| 		// We look up the policy mapping directly to bypass
 | |
| 		// users exists, group exists validations that do not
 | |
| 		// apply here.
 | |
| 		var policies []iampolicy.Policy
 | |
| 		if policy, ok := sys.iamUserPolicyMap[user]; ok {
 | |
| 			p, found := sys.iamPolicyDocsMap[policy.Policy]
 | |
| 			if found {
 | |
| 				policies = append(policies, p)
 | |
| 			}
 | |
| 		}
 | |
| 		for _, group := range groups {
 | |
| 			policy, ok := sys.iamGroupPolicyMap[group]
 | |
| 			if !ok {
 | |
| 				continue
 | |
| 			}
 | |
| 			p, found := sys.iamPolicyDocsMap[policy.Policy]
 | |
| 			if found {
 | |
| 				policies = append(policies, p)
 | |
| 			}
 | |
| 		}
 | |
| 		if len(policies) == 0 {
 | |
| 			return false
 | |
| 		}
 | |
| 		combinedPolicy := policies[0]
 | |
| 		for i := 1; i < len(policies); i++ {
 | |
| 			combinedPolicy.Statements =
 | |
| 				append(combinedPolicy.Statements,
 | |
| 					policies[i].Statements...)
 | |
| 		}
 | |
| 		return combinedPolicy.IsAllowed(args)
 | |
| 	}
 | |
| 
 | |
| 	pnameSlice, ok := args.GetPolicies(iamPolicyClaimName())
 | |
| 	if !ok {
 | |
| 		// When claims are set, it should have a policy claim field.
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	// When claims are set, it should have a policy claim field.
 | |
| 	if len(pnameSlice) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	// If policy is available for given user, check the policy.
 | |
| 	mp, ok := sys.iamUserPolicyMap[args.AccountName]
 | |
| 	if !ok {
 | |
| 		// No policy available reject.
 | |
| 		return false
 | |
| 	}
 | |
| 	name := mp.Policy
 | |
| 
 | |
| 	if pnameSlice[0] != name {
 | |
| 		// When claims has a policy, it should match the
 | |
| 		// policy of args.AccountName which server remembers.
 | |
| 		// if not reject such requests.
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	// Now check if we have a sessionPolicy.
 | |
| 	spolicy, ok := args.Claims[iampolicy.SessionPolicyName]
 | |
| 	if ok {
 | |
| 		spolicyStr, ok := spolicy.(string)
 | |
| 		if !ok {
 | |
| 			// Sub policy if set, should be a string reject
 | |
| 			// malformed/malicious requests.
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		// Check if policy is parseable.
 | |
| 		subPolicy, err := iampolicy.ParseConfig(bytes.NewReader([]byte(spolicyStr)))
 | |
| 		if err != nil {
 | |
| 			// Log any error in input session policy config.
 | |
| 			logger.LogIf(context.Background(), err)
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		// Policy without Version string value reject it.
 | |
| 		if subPolicy.Version == "" {
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		// Sub policy is set and valid.
 | |
| 		p, ok := sys.iamPolicyDocsMap[pnameSlice[0]]
 | |
| 		return ok && p.IsAllowed(args) && subPolicy.IsAllowed(args)
 | |
| 	}
 | |
| 
 | |
| 	// Sub policy not set, this is most common since subPolicy
 | |
| 	// is optional, use the top level policy only.
 | |
| 	p, ok := sys.iamPolicyDocsMap[pnameSlice[0]]
 | |
| 	return ok && p.IsAllowed(args)
 | |
| }
 | |
| 
 | |
| // IsAllowed - checks given policy args is allowed to continue the Rest API.
 | |
| func (sys *IAMSys) IsAllowed(args iampolicy.Args) bool {
 | |
| 	// If opa is configured, use OPA always.
 | |
| 	if globalPolicyOPA != nil {
 | |
| 		ok, err := globalPolicyOPA.IsAllowed(args)
 | |
| 		if err != nil {
 | |
| 			logger.LogIf(context.Background(), err)
 | |
| 		}
 | |
| 		return ok
 | |
| 	}
 | |
| 
 | |
| 	// Policies don't apply to the owner.
 | |
| 	if args.IsOwner {
 | |
| 		return true
 | |
| 	}
 | |
| 
 | |
| 	// If the credential is temporary, perform STS related checks.
 | |
| 	ok, err := sys.IsTempUser(args.AccountName)
 | |
| 	if err != nil {
 | |
| 		logger.LogIf(context.Background(), err)
 | |
| 		return false
 | |
| 	}
 | |
| 	if ok {
 | |
| 		return sys.IsAllowedSTS(args)
 | |
| 	}
 | |
| 
 | |
| 	// If the credential is for a service account, perform related check
 | |
| 	ok, parentUser, err := sys.IsServiceAccount(args.AccountName)
 | |
| 	if err != nil {
 | |
| 		logger.LogIf(context.Background(), err)
 | |
| 		return false
 | |
| 	}
 | |
| 	if ok {
 | |
| 		return sys.IsAllowedServiceAccount(args, parentUser)
 | |
| 	}
 | |
| 
 | |
| 	// Continue with the assumption of a regular user
 | |
| 	policies, err := sys.PolicyDBGet(args.AccountName, false)
 | |
| 	if err != nil {
 | |
| 		logger.LogIf(context.Background(), err)
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	if len(policies) == 0 {
 | |
| 		// No policy found.
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	// Policies were found, evaluate all of them.
 | |
| 	sys.RLock()
 | |
| 	defer sys.RUnlock()
 | |
| 
 | |
| 	var availablePolicies []iampolicy.Policy
 | |
| 	for _, pname := range policies {
 | |
| 		p, found := sys.iamPolicyDocsMap[pname]
 | |
| 		if found {
 | |
| 			availablePolicies = append(availablePolicies, p)
 | |
| 		}
 | |
| 	}
 | |
| 	if len(availablePolicies) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 	combinedPolicy := availablePolicies[0]
 | |
| 	for i := 1; i < len(availablePolicies); i++ {
 | |
| 		combinedPolicy.Statements = append(combinedPolicy.Statements,
 | |
| 			availablePolicies[i].Statements...)
 | |
| 	}
 | |
| 	return combinedPolicy.IsAllowed(args)
 | |
| }
 | |
| 
 | |
| // Set default canned policies only if not already overridden by users.
 | |
| func setDefaultCannedPolicies(policies map[string]iampolicy.Policy) {
 | |
| 	_, ok := policies["writeonly"]
 | |
| 	if !ok {
 | |
| 		policies["writeonly"] = iampolicy.WriteOnly
 | |
| 	}
 | |
| 	_, ok = policies["readonly"]
 | |
| 	if !ok {
 | |
| 		policies["readonly"] = iampolicy.ReadOnly
 | |
| 	}
 | |
| 	_, ok = policies["readwrite"]
 | |
| 	if !ok {
 | |
| 		policies["readwrite"] = iampolicy.ReadWrite
 | |
| 	}
 | |
| 	_, ok = policies["diagnostics"]
 | |
| 	if !ok {
 | |
| 		policies["diagnostics"] = iampolicy.AdminDiagnostics
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // buildUserGroupMemberships - builds the memberships map. IMPORTANT:
 | |
| // Assumes that sys.Lock is held by caller.
 | |
| func (sys *IAMSys) buildUserGroupMemberships() {
 | |
| 	for group, gi := range sys.iamGroupsMap {
 | |
| 		sys.updateGroupMembershipsMap(group, &gi)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // updateGroupMembershipsMap - updates the memberships map for a
 | |
| // group. IMPORTANT: Assumes sys.Lock() is held by caller.
 | |
| func (sys *IAMSys) updateGroupMembershipsMap(group string, gi *GroupInfo) {
 | |
| 	if gi == nil {
 | |
| 		return
 | |
| 	}
 | |
| 	for _, member := range gi.Members {
 | |
| 		v := sys.iamUserGroupMemberships[member]
 | |
| 		if v == nil {
 | |
| 			v = set.CreateStringSet(group)
 | |
| 		} else {
 | |
| 			v.Add(group)
 | |
| 		}
 | |
| 		sys.iamUserGroupMemberships[member] = v
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // removeGroupFromMembershipsMap - removes the group from every member
 | |
| // in the cache. IMPORTANT: Assumes sys.Lock() is held by caller.
 | |
| func (sys *IAMSys) removeGroupFromMembershipsMap(group string) {
 | |
| 	for member, groups := range sys.iamUserGroupMemberships {
 | |
| 		if !groups.Contains(group) {
 | |
| 			continue
 | |
| 		}
 | |
| 		groups.Remove(group)
 | |
| 		sys.iamUserGroupMemberships[member] = groups
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewIAMSys - creates new config system object.
 | |
| func NewIAMSys() *IAMSys {
 | |
| 	// Check global server configuration to determine the type of
 | |
| 	// users system configured.
 | |
| 
 | |
| 	// The default users system
 | |
| 	var utype UsersSysType
 | |
| 	switch {
 | |
| 	case globalLDAPConfig.Enabled:
 | |
| 		utype = LDAPUsersSysType
 | |
| 	default:
 | |
| 		utype = MinIOUsersSysType
 | |
| 	}
 | |
| 
 | |
| 	return &IAMSys{
 | |
| 		usersSysType:            utype,
 | |
| 		iamUsersMap:             make(map[string]auth.Credentials),
 | |
| 		iamPolicyDocsMap:        make(map[string]iampolicy.Policy),
 | |
| 		iamUserPolicyMap:        make(map[string]MappedPolicy),
 | |
| 		iamGroupsMap:            make(map[string]GroupInfo),
 | |
| 		iamUserGroupMemberships: make(map[string]set.StringSet),
 | |
| 	}
 | |
| }
 |