mirror of
https://github.com/minio/minio.git
synced 2025-03-30 17:23:42 -04:00
support multiple policies for temporary users (#9550)
This commit is contained in:
parent
337c2a7cb4
commit
f8edc233ab
@ -1649,7 +1649,7 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return ErrNone
|
return ErrNone
|
||||||
}
|
}
|
||||||
// Verify if the underlying error is signature mismatch.
|
|
||||||
switch err {
|
switch err {
|
||||||
case errInvalidArgument:
|
case errInvalidArgument:
|
||||||
apiErr = ErrAdminInvalidArgument
|
apiErr = ErrAdminInvalidArgument
|
||||||
|
84
cmd/iam.go
84
cmd/iam.go
@ -22,6 +22,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/minio/minio-go/v6/pkg/set"
|
"github.com/minio/minio-go/v6/pkg/set"
|
||||||
"github.com/minio/minio/cmd/config"
|
"github.com/minio/minio/cmd/config"
|
||||||
@ -166,6 +167,10 @@ type MappedPolicy struct {
|
|||||||
Policy string `json:"policy"`
|
Policy string `json:"policy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mp MappedPolicy) policySet() set.StringSet {
|
||||||
|
return set.CreateStringSet(strings.Split(mp.Policy, ",")...)
|
||||||
|
}
|
||||||
|
|
||||||
func newMappedPolicy(policy string) MappedPolicy {
|
func newMappedPolicy(policy string) MappedPolicy {
|
||||||
return MappedPolicy{Version: 1, Policy: policy}
|
return MappedPolicy{Version: 1, Policy: policy}
|
||||||
}
|
}
|
||||||
@ -591,11 +596,26 @@ func (sys *IAMSys) SetTempUser(accessKey string, cred auth.Credentials, policyNa
|
|||||||
// temporary user which match with pre-configured canned
|
// temporary user which match with pre-configured canned
|
||||||
// policies for this server.
|
// policies for this server.
|
||||||
if globalPolicyOPA == nil && policyName != "" {
|
if globalPolicyOPA == nil && policyName != "" {
|
||||||
p, ok := sys.iamPolicyDocsMap[policyName]
|
var availablePolicies []iampolicy.Policy
|
||||||
if !ok {
|
for _, pname := range strings.Split(policyName, ",") {
|
||||||
return errInvalidArgument
|
pname = strings.TrimSpace(pname)
|
||||||
|
if pname == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p, found := sys.iamPolicyDocsMap[pname]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("%w: (%s)", errNoSuchPolicy, pname)
|
||||||
|
}
|
||||||
|
availablePolicies = append(availablePolicies, p)
|
||||||
}
|
}
|
||||||
if p.IsEmpty() {
|
|
||||||
|
combinedPolicy := availablePolicies[0]
|
||||||
|
for i := 1; i < len(availablePolicies); i++ {
|
||||||
|
combinedPolicy.Statements = append(combinedPolicy.Statements,
|
||||||
|
availablePolicies[i].Statements...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if combinedPolicy.IsEmpty() {
|
||||||
delete(sys.iamUserPolicyMap, accessKey)
|
delete(sys.iamUserPolicyMap, accessKey)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1265,13 +1285,10 @@ func (sys *IAMSys) PolicyDBSet(name, policy string, isGroup bool) error {
|
|||||||
|
|
||||||
// policyDBSet - sets a policy for user in the policy db. Assumes that caller
|
// policyDBSet - sets a policy for user in the policy db. Assumes that caller
|
||||||
// has sys.Lock(). If policy == "", then policy mapping is removed.
|
// has sys.Lock(). If policy == "", then policy mapping is removed.
|
||||||
func (sys *IAMSys) policyDBSet(name, policy string, userType IAMUserType, isGroup bool) error {
|
func (sys *IAMSys) policyDBSet(name, policyName string, userType IAMUserType, isGroup bool) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return errInvalidArgument
|
return errInvalidArgument
|
||||||
}
|
}
|
||||||
if _, ok := sys.iamPolicyDocsMap[policy]; !ok && policy != "" {
|
|
||||||
return errNoSuchPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
if sys.usersSysType == MinIOUsersSysType {
|
if sys.usersSysType == MinIOUsersSysType {
|
||||||
if !isGroup {
|
if !isGroup {
|
||||||
@ -1286,7 +1303,7 @@ func (sys *IAMSys) policyDBSet(name, policy string, userType IAMUserType, isGrou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle policy mapping removal
|
// Handle policy mapping removal
|
||||||
if policy == "" {
|
if policyName == "" {
|
||||||
if err := sys.store.deleteMappedPolicy(name, userType, isGroup); err != nil && err != errNoSuchPolicy {
|
if err := sys.store.deleteMappedPolicy(name, userType, isGroup); err != nil && err != errNoSuchPolicy {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1298,8 +1315,19 @@ func (sys *IAMSys) policyDBSet(name, policy string, userType IAMUserType, isGrou
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, pname := range strings.Split(policyName, ",") {
|
||||||
|
pname = strings.TrimSpace(pname)
|
||||||
|
if pname == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, found := sys.iamPolicyDocsMap[pname]; !found {
|
||||||
|
logger.LogIf(GlobalContext, fmt.Errorf("%w: (%s)", errNoSuchPolicy, pname))
|
||||||
|
return errNoSuchPolicy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle policy mapping set/update
|
// Handle policy mapping set/update
|
||||||
mp := newMappedPolicy(policy)
|
mp := newMappedPolicy(policyName)
|
||||||
if err := sys.store.saveMappedPolicy(name, userType, isGroup, mp); err != nil {
|
if err := sys.store.saveMappedPolicy(name, userType, isGroup, mp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1644,14 +1672,15 @@ func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
|
|||||||
return combinedPolicy.IsAllowed(args)
|
return combinedPolicy.IsAllowed(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
pnameSlice, ok := args.GetPolicies(iamPolicyClaimNameOpenID())
|
policies, ok := args.GetPolicies(iamPolicyClaimNameOpenID())
|
||||||
if !ok {
|
if !ok {
|
||||||
// When claims are set, it should have a policy claim field.
|
// When claims are set, it should have a policy claim field.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// When claims are set, it should have a policy claim field.
|
// When claims are set, it should have policies as claim.
|
||||||
if len(pnameSlice) == 0 {
|
if policies.IsEmpty() {
|
||||||
|
// No policy, no access!
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1661,18 +1690,33 @@ func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
|
|||||||
// If policy is available for given user, check the policy.
|
// If policy is available for given user, check the policy.
|
||||||
mp, ok := sys.iamUserPolicyMap[args.AccountName]
|
mp, ok := sys.iamUserPolicyMap[args.AccountName]
|
||||||
if !ok {
|
if !ok {
|
||||||
// No policy available reject.
|
// No policy set for the user that we can find, no access!
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
name := mp.Policy
|
|
||||||
|
|
||||||
if pnameSlice[0] != name {
|
if !policies.Equals(mp.policySet()) {
|
||||||
// When claims has a policy, it should match the
|
// When claims has a policy, it should match the
|
||||||
// policy of args.AccountName which server remembers.
|
// policy of args.AccountName which server remembers.
|
||||||
// if not reject such requests.
|
// if not reject such requests.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var availablePolicies []iampolicy.Policy
|
||||||
|
for pname := range policies {
|
||||||
|
p, found := sys.iamPolicyDocsMap[pname]
|
||||||
|
if !found {
|
||||||
|
logger.LogIf(GlobalContext, fmt.Errorf("%w: (%s)", errNoSuchPolicy, pname))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
availablePolicies = append(availablePolicies, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
combinedPolicy := availablePolicies[0]
|
||||||
|
for i := 1; i < len(availablePolicies); i++ {
|
||||||
|
combinedPolicy.Statements = append(combinedPolicy.Statements,
|
||||||
|
availablePolicies[i].Statements...)
|
||||||
|
}
|
||||||
|
|
||||||
// Now check if we have a sessionPolicy.
|
// Now check if we have a sessionPolicy.
|
||||||
spolicy, ok := args.Claims[iampolicy.SessionPolicyName]
|
spolicy, ok := args.Claims[iampolicy.SessionPolicyName]
|
||||||
if ok {
|
if ok {
|
||||||
@ -1697,14 +1741,12 @@ func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sub policy is set and valid.
|
// Sub policy is set and valid.
|
||||||
p, ok := sys.iamPolicyDocsMap[pnameSlice[0]]
|
return combinedPolicy.IsAllowed(args) && subPolicy.IsAllowed(args)
|
||||||
return ok && p.IsAllowed(args) && subPolicy.IsAllowed(args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sub policy not set, this is most common since subPolicy
|
// Sub policy not set, this is most common since subPolicy
|
||||||
// is optional, use the top level policy only.
|
// is optional, use the inherited policies.
|
||||||
p, ok := sys.iamPolicyDocsMap[pnameSlice[0]]
|
return combinedPolicy.IsAllowed(args)
|
||||||
return ok && p.IsAllowed(args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAllowed - checks given policy args is allowed to continue the Rest API.
|
// IsAllowed - checks given policy args is allowed to continue the Rest API.
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/v6/pkg/set"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,17 +40,31 @@ type Args struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPolicies get policies
|
// GetPolicies get policies
|
||||||
func (a Args) GetPolicies(policyClaimName string) ([]string, bool) {
|
func (a Args) GetPolicies(policyClaimName string) (set.StringSet, bool) {
|
||||||
|
s := set.NewStringSet()
|
||||||
pname, ok := a.Claims[policyClaimName]
|
pname, ok := a.Claims[policyClaimName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return s, false
|
||||||
}
|
}
|
||||||
pnameStr, ok := pname.(string)
|
pnames, ok := pname.([]string)
|
||||||
if ok {
|
if !ok {
|
||||||
return strings.Split(pnameStr, ","), true
|
pnameStr, ok := pname.(string)
|
||||||
|
if ok {
|
||||||
|
pnames = strings.Split(pnameStr, ",")
|
||||||
|
} else {
|
||||||
|
return s, false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pnameSlice, ok := pname.([]string)
|
for _, pname := range pnames {
|
||||||
return pnameSlice, ok
|
pname = strings.TrimSpace(pname)
|
||||||
|
if pname == "" {
|
||||||
|
// ignore any empty strings, considerate
|
||||||
|
// towards some user errors.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.Add(pname)
|
||||||
|
}
|
||||||
|
return s, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Policy - iam bucket iamp.
|
// Policy - iam bucket iamp.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user