mirror of https://github.com/minio/minio.git
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 {
|
||||
return ErrNone
|
||||
}
|
||||
// Verify if the underlying error is signature mismatch.
|
||||
|
||||
switch err {
|
||||
case errInvalidArgument:
|
||||
apiErr = ErrAdminInvalidArgument
|
||||
|
|
84
cmd/iam.go
84
cmd/iam.go
|
@ -22,6 +22,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/minio-go/v6/pkg/set"
|
||||
"github.com/minio/minio/cmd/config"
|
||||
|
@ -166,6 +167,10 @@ type MappedPolicy struct {
|
|||
Policy string `json:"policy"`
|
||||
}
|
||||
|
||||
func (mp MappedPolicy) policySet() set.StringSet {
|
||||
return set.CreateStringSet(strings.Split(mp.Policy, ",")...)
|
||||
}
|
||||
|
||||
func newMappedPolicy(policy string) MappedPolicy {
|
||||
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
|
||||
// policies for this server.
|
||||
if globalPolicyOPA == nil && policyName != "" {
|
||||
p, ok := sys.iamPolicyDocsMap[policyName]
|
||||
if !ok {
|
||||
return errInvalidArgument
|
||||
var availablePolicies []iampolicy.Policy
|
||||
for _, pname := range strings.Split(policyName, ",") {
|
||||
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)
|
||||
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
|
||||
// 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 == "" {
|
||||
return errInvalidArgument
|
||||
}
|
||||
if _, ok := sys.iamPolicyDocsMap[policy]; !ok && policy != "" {
|
||||
return errNoSuchPolicy
|
||||
}
|
||||
|
||||
if sys.usersSysType == MinIOUsersSysType {
|
||||
if !isGroup {
|
||||
|
@ -1286,7 +1303,7 @@ func (sys *IAMSys) policyDBSet(name, policy string, userType IAMUserType, isGrou
|
|||
}
|
||||
|
||||
// Handle policy mapping removal
|
||||
if policy == "" {
|
||||
if policyName == "" {
|
||||
if err := sys.store.deleteMappedPolicy(name, userType, isGroup); err != nil && err != errNoSuchPolicy {
|
||||
return err
|
||||
}
|
||||
|
@ -1298,8 +1315,19 @@ func (sys *IAMSys) policyDBSet(name, policy string, userType IAMUserType, isGrou
|
|||
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
|
||||
mp := newMappedPolicy(policy)
|
||||
mp := newMappedPolicy(policyName)
|
||||
if err := sys.store.saveMappedPolicy(name, userType, isGroup, mp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1644,14 +1672,15 @@ func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
|
|||
return combinedPolicy.IsAllowed(args)
|
||||
}
|
||||
|
||||
pnameSlice, ok := args.GetPolicies(iamPolicyClaimNameOpenID())
|
||||
policies, ok := args.GetPolicies(iamPolicyClaimNameOpenID())
|
||||
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 {
|
||||
// When claims are set, it should have policies as claim.
|
||||
if policies.IsEmpty() {
|
||||
// No policy, no access!
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -1661,18 +1690,33 @@ func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
|
|||
// If policy is available for given user, check the policy.
|
||||
mp, ok := sys.iamUserPolicyMap[args.AccountName]
|
||||
if !ok {
|
||||
// No policy available reject.
|
||||
// No policy set for the user that we can find, no access!
|
||||
return false
|
||||
}
|
||||
name := mp.Policy
|
||||
|
||||
if pnameSlice[0] != name {
|
||||
if !policies.Equals(mp.policySet()) {
|
||||
// When claims has a policy, it should match the
|
||||
// policy of args.AccountName which server remembers.
|
||||
// if not reject such requests.
|
||||
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.
|
||||
spolicy, ok := args.Claims[iampolicy.SessionPolicyName]
|
||||
if ok {
|
||||
|
@ -1697,14 +1741,12 @@ func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
|
|||
}
|
||||
|
||||
// Sub policy is set and valid.
|
||||
p, ok := sys.iamPolicyDocsMap[pnameSlice[0]]
|
||||
return ok && p.IsAllowed(args) && subPolicy.IsAllowed(args)
|
||||
return combinedPolicy.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)
|
||||
// is optional, use the inherited policies.
|
||||
return combinedPolicy.IsAllowed(args)
|
||||
}
|
||||
|
||||
// IsAllowed - checks given policy args is allowed to continue the Rest API.
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/minio-go/v6/pkg/set"
|
||||
"github.com/minio/minio/pkg/bucket/policy"
|
||||
)
|
||||
|
||||
|
@ -39,17 +40,31 @@ type Args struct {
|
|||
}
|
||||
|
||||
// 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]
|
||||
if !ok {
|
||||
return nil, false
|
||||
return s, false
|
||||
}
|
||||
pnameStr, ok := pname.(string)
|
||||
if ok {
|
||||
return strings.Split(pnameStr, ","), true
|
||||
pnames, ok := pname.([]string)
|
||||
if !ok {
|
||||
pnameStr, ok := pname.(string)
|
||||
if ok {
|
||||
pnames = strings.Split(pnameStr, ",")
|
||||
} else {
|
||||
return s, false
|
||||
}
|
||||
}
|
||||
pnameSlice, ok := pname.([]string)
|
||||
return pnameSlice, ok
|
||||
for _, pname := range pnames {
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue