support multiple policies for temporary users (#9550)

master
Harshavardhana 5 years ago committed by GitHub
parent 337c2a7cb4
commit f8edc233ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      cmd/api-errors.go
  2. 84
      cmd/iam.go
  3. 25
      pkg/iam/policy/policy.go

@ -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

@ -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
} }
pnames, ok := pname.([]string)
if !ok {
pnameStr, ok := pname.(string) pnameStr, ok := pname.(string)
if ok { if ok {
return strings.Split(pnameStr, ","), true pnames = strings.Split(pnameStr, ",")
} else {
return s, false
}
}
for _, pname := range pnames {
pname = strings.TrimSpace(pname)
if pname == "" {
// ignore any empty strings, considerate
// towards some user errors.
continue
}
s.Add(pname)
} }
pnameSlice, ok := pname.([]string) return s, true
return pnameSlice, ok
} }
// Policy - iam bucket iamp. // Policy - iam bucket iamp.

Loading…
Cancel
Save