mirror of
				https://github.com/minio/minio.git
				synced 2025-10-29 15:55:00 -04:00 
			
		
		
		
	Support policy variable replacement (#7085)
This PR supports iam and bucket policies to have
policy variable replacements in resource and
condition key values.
For example
- ${aws:username}
- ${aws:userid}
			
			
This commit is contained in:
		
							parent
							
								
									3265112d04
								
							
						
					
					
						commit
						5353edcc38
					
				| @ -283,7 +283,7 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac | ||||
| 			AccountName:     cred.AccessKey, | ||||
| 			Action:          action, | ||||
| 			BucketName:      bucketName, | ||||
| 			ConditionValues: getConditionValues(r, locationConstraint), | ||||
| 			ConditionValues: getConditionValues(r, locationConstraint, ""), | ||||
| 			IsOwner:         false, | ||||
| 			ObjectName:      objectName, | ||||
| 		}) { | ||||
| @ -296,7 +296,7 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac | ||||
| 		AccountName:     cred.AccessKey, | ||||
| 		Action:          iampolicy.Action(action), | ||||
| 		BucketName:      bucketName, | ||||
| 		ConditionValues: getConditionValues(r, ""), | ||||
| 		ConditionValues: getConditionValues(r, "", cred.AccessKey), | ||||
| 		ObjectName:      objectName, | ||||
| 		IsOwner:         owner, | ||||
| 		Claims:          claims, | ||||
| @ -448,7 +448,7 @@ func isPutAllowed(atype authType, bucketName, objectName string, r *http.Request | ||||
| 			AccountName:     cred.AccessKey, | ||||
| 			Action:          policy.PutObjectAction, | ||||
| 			BucketName:      bucketName, | ||||
| 			ConditionValues: getConditionValues(r, ""), | ||||
| 			ConditionValues: getConditionValues(r, "", ""), | ||||
| 			IsOwner:         false, | ||||
| 			ObjectName:      objectName, | ||||
| 		}) { | ||||
| @ -461,7 +461,7 @@ func isPutAllowed(atype authType, bucketName, objectName string, r *http.Request | ||||
| 		AccountName:     cred.AccessKey, | ||||
| 		Action:          policy.PutObjectAction, | ||||
| 		BucketName:      bucketName, | ||||
| 		ConditionValues: getConditionValues(r, ""), | ||||
| 		ConditionValues: getConditionValues(r, "", cred.AccessKey), | ||||
| 		ObjectName:      objectName, | ||||
| 		IsOwner:         owner, | ||||
| 		Claims:          claims, | ||||
|  | ||||
| @ -131,7 +131,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r | ||||
| 			if globalPolicySys.IsAllowed(policy.Args{ | ||||
| 				Action:          policy.ListBucketAction, | ||||
| 				BucketName:      bucket, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", ""), | ||||
| 				IsOwner:         false, | ||||
| 			}) { | ||||
| 				_, err = getObjectInfo(ctx, bucket, object, opts) | ||||
| @ -281,7 +281,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req | ||||
| 			if globalPolicySys.IsAllowed(policy.Args{ | ||||
| 				Action:          policy.ListBucketAction, | ||||
| 				BucketName:      bucket, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", ""), | ||||
| 				IsOwner:         false, | ||||
| 			}) { | ||||
| 				getObjectInfo := objectAPI.GetObjectInfo | ||||
| @ -463,7 +463,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re | ||||
| 			if globalPolicySys.IsAllowed(policy.Args{ | ||||
| 				Action:          policy.ListBucketAction, | ||||
| 				BucketName:      bucket, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", ""), | ||||
| 				IsOwner:         false, | ||||
| 			}) { | ||||
| 				_, err = getObjectInfo(ctx, bucket, object, opts) | ||||
|  | ||||
| @ -30,6 +30,7 @@ import ( | ||||
| 	miniogopolicy "github.com/minio/minio-go/pkg/policy" | ||||
| 	"github.com/minio/minio-go/pkg/set" | ||||
| 	"github.com/minio/minio/cmd/logger" | ||||
| 	"github.com/minio/minio/pkg/event" | ||||
| 	"github.com/minio/minio/pkg/handlers" | ||||
| 	"github.com/minio/minio/pkg/policy" | ||||
| ) | ||||
| @ -183,12 +184,24 @@ func NewPolicySys() *PolicySys { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getConditionValues(request *http.Request, locationConstraint string) map[string][]string { | ||||
| func getConditionValues(request *http.Request, locationConstraint string, username string) map[string][]string { | ||||
| 	currTime := UTCNow() | ||||
| 	principalType := func() string { | ||||
| 		if username != "" { | ||||
| 			return "User" | ||||
| 		} | ||||
| 		return "Anonymous" | ||||
| 	}() | ||||
| 	args := map[string][]string{ | ||||
| 		"SourceIp":        {handlers.GetSourceIP(request)}, | ||||
| 		"CurrenTime":      {currTime.Format(event.AMZTimeFormat)}, | ||||
| 		"EpochTime":       {fmt.Sprintf("%d", currTime.Unix())}, | ||||
| 		"principaltype":   {principalType}, | ||||
| 		"SecureTransport": {fmt.Sprintf("%t", request.TLS != nil)}, | ||||
| 		"SourceIp":        {handlers.GetSourceIP(request)}, | ||||
| 		"UserAgent":       {request.UserAgent()}, | ||||
| 		"Referer":         {request.Referer()}, | ||||
| 		"userid":          {username}, | ||||
| 		"username":        {username}, | ||||
| 	} | ||||
| 
 | ||||
| 	for key, values := range request.Header { | ||||
|  | ||||
| @ -306,7 +306,7 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re | ||||
| 				AccountName:     claims.Subject, | ||||
| 				Action:          iampolicy.ListBucketAction, | ||||
| 				BucketName:      bucketName, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", claims.Subject), | ||||
| 				IsOwner:         owner, | ||||
| 				ObjectName:      "", | ||||
| 			}) { | ||||
| @ -326,7 +326,7 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re | ||||
| 				AccountName:     claims.Subject, | ||||
| 				Action:          iampolicy.ListBucketAction, | ||||
| 				BucketName:      bucket.Name, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", claims.Subject), | ||||
| 				IsOwner:         owner, | ||||
| 				ObjectName:      "", | ||||
| 			}) { | ||||
| @ -432,7 +432,7 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r | ||||
| 			readable := globalPolicySys.IsAllowed(policy.Args{ | ||||
| 				Action:          policy.ListBucketAction, | ||||
| 				BucketName:      args.BucketName, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", ""), | ||||
| 				IsOwner:         false, | ||||
| 			}) | ||||
| 
 | ||||
| @ -440,7 +440,7 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r | ||||
| 			writable := globalPolicySys.IsAllowed(policy.Args{ | ||||
| 				Action:          policy.PutObjectAction, | ||||
| 				BucketName:      args.BucketName, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", ""), | ||||
| 				IsOwner:         false, | ||||
| 				ObjectName:      args.Prefix + "/", | ||||
| 			}) | ||||
| @ -471,7 +471,7 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r | ||||
| 			AccountName:     claims.Subject, | ||||
| 			Action:          iampolicy.ListBucketAction, | ||||
| 			BucketName:      args.BucketName, | ||||
| 			ConditionValues: getConditionValues(r, ""), | ||||
| 			ConditionValues: getConditionValues(r, "", ""), | ||||
| 			IsOwner:         owner, | ||||
| 		}) | ||||
| 
 | ||||
| @ -479,7 +479,7 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r | ||||
| 			AccountName:     claims.Subject, | ||||
| 			Action:          iampolicy.PutObjectAction, | ||||
| 			BucketName:      args.BucketName, | ||||
| 			ConditionValues: getConditionValues(r, ""), | ||||
| 			ConditionValues: getConditionValues(r, "", ""), | ||||
| 			IsOwner:         owner, | ||||
| 			ObjectName:      args.Prefix + "/", | ||||
| 		}) | ||||
| @ -611,7 +611,7 @@ next: | ||||
| 				AccountName:     claims.Subject, | ||||
| 				Action:          iampolicy.DeleteObjectAction, | ||||
| 				BucketName:      args.BucketName, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", claims.Subject), | ||||
| 				IsOwner:         owner, | ||||
| 				ObjectName:      objectName, | ||||
| 			}) { | ||||
| @ -628,7 +628,7 @@ next: | ||||
| 			AccountName:     claims.Subject, | ||||
| 			Action:          iampolicy.DeleteObjectAction, | ||||
| 			BucketName:      args.BucketName, | ||||
| 			ConditionValues: getConditionValues(r, ""), | ||||
| 			ConditionValues: getConditionValues(r, "", claims.Subject), | ||||
| 			IsOwner:         owner, | ||||
| 			ObjectName:      objectName, | ||||
| 		}) { | ||||
| @ -853,7 +853,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { | ||||
| 			if !globalPolicySys.IsAllowed(policy.Args{ | ||||
| 				Action:          policy.PutObjectAction, | ||||
| 				BucketName:      bucket, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", ""), | ||||
| 				IsOwner:         false, | ||||
| 				ObjectName:      object, | ||||
| 			}) { | ||||
| @ -872,7 +872,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { | ||||
| 			AccountName:     claims.Subject, | ||||
| 			Action:          iampolicy.PutObjectAction, | ||||
| 			BucketName:      bucket, | ||||
| 			ConditionValues: getConditionValues(r, ""), | ||||
| 			ConditionValues: getConditionValues(r, "", claims.Subject), | ||||
| 			IsOwner:         owner, | ||||
| 			ObjectName:      object, | ||||
| 		}) { | ||||
| @ -1040,7 +1040,7 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) { | ||||
| 			if !globalPolicySys.IsAllowed(policy.Args{ | ||||
| 				Action:          policy.GetObjectAction, | ||||
| 				BucketName:      bucket, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", ""), | ||||
| 				IsOwner:         false, | ||||
| 				ObjectName:      object, | ||||
| 			}) { | ||||
| @ -1059,7 +1059,7 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) { | ||||
| 			AccountName:     claims.Subject, | ||||
| 			Action:          iampolicy.GetObjectAction, | ||||
| 			BucketName:      bucket, | ||||
| 			ConditionValues: getConditionValues(r, ""), | ||||
| 			ConditionValues: getConditionValues(r, "", claims.Subject), | ||||
| 			IsOwner:         owner, | ||||
| 			ObjectName:      object, | ||||
| 		}) { | ||||
| @ -1195,7 +1195,7 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) { | ||||
| 				if !globalPolicySys.IsAllowed(policy.Args{ | ||||
| 					Action:          policy.GetObjectAction, | ||||
| 					BucketName:      args.BucketName, | ||||
| 					ConditionValues: getConditionValues(r, ""), | ||||
| 					ConditionValues: getConditionValues(r, "", ""), | ||||
| 					IsOwner:         false, | ||||
| 					ObjectName:      pathJoin(args.Prefix, object), | ||||
| 				}) { | ||||
| @ -1216,7 +1216,7 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) { | ||||
| 				AccountName:     claims.Subject, | ||||
| 				Action:          iampolicy.GetObjectAction, | ||||
| 				BucketName:      args.BucketName, | ||||
| 				ConditionValues: getConditionValues(r, ""), | ||||
| 				ConditionValues: getConditionValues(r, "", claims.Subject), | ||||
| 				IsOwner:         owner, | ||||
| 				ObjectName:      pathJoin(args.Prefix, object), | ||||
| 			}) { | ||||
|  | ||||
| @ -21,6 +21,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/minio/minio/pkg/policy/condition" | ||||
| 	"github.com/minio/minio/pkg/wildcard" | ||||
| ) | ||||
| 
 | ||||
| @ -47,11 +48,18 @@ func (r Resource) IsValid() bool { | ||||
| } | ||||
| 
 | ||||
| // Match - matches object name with resource pattern. | ||||
| func (r Resource) Match(resource string) bool { | ||||
| 	if strings.HasPrefix(resource, r.Pattern) { | ||||
| func (r Resource) Match(resource string, conditionValues map[string][]string) bool { | ||||
| 	pattern := r.Pattern | ||||
| 	for _, key := range condition.CommonKeys { | ||||
| 		// Empty values are not supported for policy variables. | ||||
| 		if rvalues, ok := conditionValues[key.Name()]; ok && rvalues[0] != "" { | ||||
| 			pattern = strings.Replace(pattern, key.VarName(), rvalues[0], -1) | ||||
| 		} | ||||
| 	} | ||||
| 	if strings.HasPrefix(resource, pattern) { | ||||
| 		return true | ||||
| 	} | ||||
| 	return wildcard.Match(r.Pattern, resource) | ||||
| 	return wildcard.Match(pattern, resource) | ||||
| } | ||||
| 
 | ||||
| // MarshalJSON - encodes Resource to JSON data. | ||||
|  | ||||
| @ -124,7 +124,7 @@ func TestResourceMatch(t *testing.T) { | ||||
| 	} | ||||
| 
 | ||||
| 	for i, testCase := range testCases { | ||||
| 		result := testCase.resource.Match(testCase.objectName) | ||||
| 		result := testCase.resource.Match(testCase.objectName, nil) | ||||
| 
 | ||||
| 		if result != testCase.expectedResult { | ||||
| 			t.Fatalf("case %v: expected: %v, got: %v", i+1, testCase.expectedResult, result) | ||||
|  | ||||
| @ -81,9 +81,9 @@ func (resourceSet ResourceSet) MarshalJSON() ([]byte, error) { | ||||
| } | ||||
| 
 | ||||
| // Match - matches object name with anyone of resource pattern in resource set. | ||||
| func (resourceSet ResourceSet) Match(resource string) bool { | ||||
| func (resourceSet ResourceSet) Match(resource string, conditionValues map[string][]string) bool { | ||||
| 	for r := range resourceSet { | ||||
| 		if r.Match(resource) { | ||||
| 		if r.Match(resource, conditionValues) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -179,7 +179,7 @@ func TestResourceSetMatch(t *testing.T) { | ||||
| 	} | ||||
| 
 | ||||
| 	for i, testCase := range testCases { | ||||
| 		result := testCase.resourceSet.Match(testCase.resource) | ||||
| 		result := testCase.resourceSet.Match(testCase.resource, nil) | ||||
| 
 | ||||
| 		if result != testCase.expectedResult { | ||||
| 			t.Fatalf("case %v: expected: %v, got: %v", i+1, testCase.expectedResult, result) | ||||
|  | ||||
| @ -52,7 +52,7 @@ func (statement Statement) IsAllowed(args Args) bool { | ||||
| 			resource += "/" | ||||
| 		} | ||||
| 
 | ||||
| 		if !statement.Resources.Match(resource) { | ||||
| 		if !statement.Resources.Match(resource, args.ConditionValues) { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
| @ -51,7 +51,8 @@ func (f binaryEqualsFunc) evaluate(values map[string][]string) bool { | ||||
| 		requestValue = values[f.k.Name()] | ||||
| 	} | ||||
| 
 | ||||
| 	return !f.values.Intersection(set.CreateStringSet(requestValue...)).IsEmpty() | ||||
| 	fvalues := f.values.ApplyFunc(substFuncFromValues(values)) | ||||
| 	return !fvalues.Intersection(set.CreateStringSet(requestValue...)).IsEmpty() | ||||
| } | ||||
| 
 | ||||
| // key() - returns condition key which is used by this condition function. | ||||
|  | ||||
| @ -33,49 +33,58 @@ const ( | ||||
| 
 | ||||
| 	// S3XAmzServerSideEncryption - key representing x-amz-server-side-encryption HTTP header applicable | ||||
| 	// to PutObject API only. | ||||
| 	S3XAmzServerSideEncryption = "s3:x-amz-server-side-encryption" | ||||
| 	S3XAmzServerSideEncryption Key = "s3:x-amz-server-side-encryption" | ||||
| 
 | ||||
| 	// S3XAmzServerSideEncryptionCustomerAlgorithm - key representing | ||||
| 	// x-amz-server-side-encryption-customer-algorithm HTTP header applicable to PutObject API only. | ||||
| 	S3XAmzServerSideEncryptionCustomerAlgorithm = "s3:x-amz-server-side-encryption-customer-algorithm" | ||||
| 	S3XAmzServerSideEncryptionCustomerAlgorithm Key = "s3:x-amz-server-side-encryption-customer-algorithm" | ||||
| 
 | ||||
| 	// S3XAmzMetadataDirective - key representing x-amz-metadata-directive HTTP header applicable to | ||||
| 	// PutObject API only. | ||||
| 	S3XAmzMetadataDirective = "s3:x-amz-metadata-directive" | ||||
| 	S3XAmzMetadataDirective Key = "s3:x-amz-metadata-directive" | ||||
| 
 | ||||
| 	// S3XAmzStorageClass - key representing x-amz-storage-class HTTP header applicable to PutObject API | ||||
| 	// only. | ||||
| 	S3XAmzStorageClass = "s3:x-amz-storage-class" | ||||
| 	S3XAmzStorageClass Key = "s3:x-amz-storage-class" | ||||
| 
 | ||||
| 	// S3LocationConstraint - key representing LocationConstraint XML tag of CreateBucket API only. | ||||
| 	S3LocationConstraint = "s3:LocationConstraint" | ||||
| 	S3LocationConstraint Key = "s3:LocationConstraint" | ||||
| 
 | ||||
| 	// S3Prefix - key representing prefix query parameter of ListBucket API only. | ||||
| 	S3Prefix = "s3:prefix" | ||||
| 	S3Prefix Key = "s3:prefix" | ||||
| 
 | ||||
| 	// S3Delimiter - key representing delimiter query parameter of ListBucket API only. | ||||
| 	S3Delimiter = "s3:delimiter" | ||||
| 	S3Delimiter Key = "s3:delimiter" | ||||
| 
 | ||||
| 	// S3MaxKeys - key representing max-keys query parameter of ListBucket API only. | ||||
| 	S3MaxKeys = "s3:max-keys" | ||||
| 	S3MaxKeys Key = "s3:max-keys" | ||||
| 
 | ||||
| 	// AWSReferer - key representing Referer header of any API. | ||||
| 	AWSReferer = "aws:Referer" | ||||
| 	AWSReferer Key = "aws:Referer" | ||||
| 
 | ||||
| 	// AWSSourceIP - key representing client's IP address (not intermittent proxies) of any API. | ||||
| 	AWSSourceIP = "aws:SourceIp" | ||||
| 	AWSSourceIP Key = "aws:SourceIp" | ||||
| 
 | ||||
| 	// AWSUserAgent - key representing UserAgent header for any API. | ||||
| 	AWSUserAgent = "aws:UserAgent" | ||||
| 	AWSUserAgent Key = "aws:UserAgent" | ||||
| 
 | ||||
| 	// AWSSecureTransport - key representing if the clients request is authenticated or not. | ||||
| 	AWSSecureTransport = "aws:SecureTransport" | ||||
| 	AWSSecureTransport Key = "aws:SecureTransport" | ||||
| 
 | ||||
| 	// AWSCurrentTime - key representing the current time. | ||||
| 	AWSCurrentTime = "aws:CurrentTime" | ||||
| 	AWSCurrentTime Key = "aws:CurrentTime" | ||||
| 
 | ||||
| 	// AWSEpochTime - key representing the current epoch time. | ||||
| 	AWSEpochTime = "aws:EpochTime" | ||||
| 	AWSEpochTime Key = "aws:EpochTime" | ||||
| 
 | ||||
| 	// AWSPrincipalType - user principal type currently supported values are "User" and "Anonymous". | ||||
| 	AWSPrincipalType Key = "aws:principaltype" | ||||
| 
 | ||||
| 	// AWSUserID - user unique ID, in Minio this value is same as your user Access Key. | ||||
| 	AWSUserID Key = "aws:userid" | ||||
| 
 | ||||
| 	// AWSUsername - user friendly name, in Minio this value is same as your user Access Key. | ||||
| 	AWSUsername Key = "aws:username" | ||||
| ) | ||||
| 
 | ||||
| // AllSupportedKeys - is list of all all supported keys. | ||||
| @ -95,6 +104,9 @@ var AllSupportedKeys = []Key{ | ||||
| 	AWSSecureTransport, | ||||
| 	AWSCurrentTime, | ||||
| 	AWSEpochTime, | ||||
| 	AWSPrincipalType, | ||||
| 	AWSUserID, | ||||
| 	AWSUsername, | ||||
| 	// Add new supported condition keys. | ||||
| } | ||||
| 
 | ||||
| @ -106,6 +118,21 @@ var CommonKeys = []Key{ | ||||
| 	AWSSecureTransport, | ||||
| 	AWSCurrentTime, | ||||
| 	AWSEpochTime, | ||||
| 	AWSPrincipalType, | ||||
| 	AWSUserID, | ||||
| 	AWSUsername, | ||||
| } | ||||
| 
 | ||||
| func substFuncFromValues(values map[string][]string) func(string) string { | ||||
| 	return func(v string) string { | ||||
| 		for _, key := range CommonKeys { | ||||
| 			// Empty values are not supported for policy variables. | ||||
| 			if rvalues, ok := values[key.Name()]; ok && rvalues[0] != "" { | ||||
| 				v = strings.Replace(v, key.VarName(), rvalues[0], -1) | ||||
| 			} | ||||
| 		} | ||||
| 		return v | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // IsValid - checks if key is valid or not. | ||||
| @ -128,6 +155,11 @@ func (key Key) MarshalJSON() ([]byte, error) { | ||||
| 	return json.Marshal(string(key)) | ||||
| } | ||||
| 
 | ||||
| // VarName - returns variable key name, such as "${aws:username}" | ||||
| func (key Key) VarName() string { | ||||
| 	return fmt.Sprintf("${%s}", key) | ||||
| } | ||||
| 
 | ||||
| // Name - returns key name which is stripped value of prefixes "aws:" and "s3:" | ||||
| func (key Key) Name() string { | ||||
| 	keyString := string(key) | ||||
|  | ||||
| @ -50,7 +50,8 @@ func (f stringEqualsFunc) evaluate(values map[string][]string) bool { | ||||
| 		requestValue = values[f.k.Name()] | ||||
| 	} | ||||
| 
 | ||||
| 	return !f.values.Intersection(set.CreateStringSet(requestValue...)).IsEmpty() | ||||
| 	fvalues := f.values.ApplyFunc(substFuncFromValues(values)) | ||||
| 	return !fvalues.Intersection(set.CreateStringSet(requestValue...)).IsEmpty() | ||||
| } | ||||
| 
 | ||||
| // key() - returns condition key which is used by this condition function. | ||||
|  | ||||
| @ -50,11 +50,14 @@ func (f stringEqualsIgnoreCaseFunc) evaluate(values map[string][]string) bool { | ||||
| 		requestValue = values[f.k.Name()] | ||||
| 	} | ||||
| 
 | ||||
| 	fvalues := f.values.ApplyFunc(substFuncFromValues(values)) | ||||
| 
 | ||||
| 	for _, v := range requestValue { | ||||
| 		if !f.values.FuncMatch(strings.EqualFold, v).IsEmpty() { | ||||
| 		if !fvalues.FuncMatch(strings.EqualFold, v).IsEmpty() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -51,8 +51,10 @@ func (f stringLikeFunc) evaluate(values map[string][]string) bool { | ||||
| 		requestValue = values[f.k.Name()] | ||||
| 	} | ||||
| 
 | ||||
| 	fvalues := f.values.ApplyFunc(substFuncFromValues(values)) | ||||
| 
 | ||||
| 	for _, v := range requestValue { | ||||
| 		if !f.values.FuncMatch(wildcard.Match, v).IsEmpty() { | ||||
| 		if !fvalues.FuncMatch(wildcard.Match, v).IsEmpty() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -21,6 +21,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/minio/minio/pkg/policy/condition" | ||||
| 	"github.com/minio/minio/pkg/wildcard" | ||||
| ) | ||||
| 
 | ||||
| @ -47,8 +48,16 @@ func (r Resource) IsValid() bool { | ||||
| } | ||||
| 
 | ||||
| // Match - matches object name with resource pattern. | ||||
| func (r Resource) Match(resource string) bool { | ||||
| 	return wildcard.Match(r.Pattern, resource) | ||||
| func (r Resource) Match(resource string, conditionValues map[string][]string) bool { | ||||
| 	pattern := r.Pattern | ||||
| 	for _, key := range condition.CommonKeys { | ||||
| 		// Empty values are not supported for policy variables. | ||||
| 		if rvalues, ok := conditionValues[key.Name()]; ok && rvalues[0] != "" { | ||||
| 			pattern = strings.Replace(pattern, key.VarName(), rvalues[0], -1) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return wildcard.Match(pattern, resource) | ||||
| } | ||||
| 
 | ||||
| // MarshalJSON - encodes Resource to JSON data. | ||||
|  | ||||
| @ -124,7 +124,7 @@ func TestResourceMatch(t *testing.T) { | ||||
| 	} | ||||
| 
 | ||||
| 	for i, testCase := range testCases { | ||||
| 		result := testCase.resource.Match(testCase.objectName) | ||||
| 		result := testCase.resource.Match(testCase.objectName, nil) | ||||
| 
 | ||||
| 		if result != testCase.expectedResult { | ||||
| 			t.Fatalf("case %v: expected: %v, got: %v", i+1, testCase.expectedResult, result) | ||||
|  | ||||
| @ -81,9 +81,9 @@ func (resourceSet ResourceSet) MarshalJSON() ([]byte, error) { | ||||
| } | ||||
| 
 | ||||
| // Match - matches object name with anyone of resource pattern in resource set. | ||||
| func (resourceSet ResourceSet) Match(resource string) bool { | ||||
| func (resourceSet ResourceSet) Match(resource string, conditionValues map[string][]string) bool { | ||||
| 	for r := range resourceSet { | ||||
| 		if r.Match(resource) { | ||||
| 		if r.Match(resource, conditionValues) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -179,7 +179,7 @@ func TestResourceSetMatch(t *testing.T) { | ||||
| 	} | ||||
| 
 | ||||
| 	for i, testCase := range testCases { | ||||
| 		result := testCase.resourceSet.Match(testCase.resource) | ||||
| 		result := testCase.resourceSet.Match(testCase.resource, nil) | ||||
| 
 | ||||
| 		if result != testCase.expectedResult { | ||||
| 			t.Fatalf("case %v: expected: %v, got: %v", i+1, testCase.expectedResult, result) | ||||
|  | ||||
| @ -54,7 +54,7 @@ func (statement Statement) IsAllowed(args Args) bool { | ||||
| 			resource += args.ObjectName | ||||
| 		} | ||||
| 
 | ||||
| 		if !statement.Resources.Match(resource) { | ||||
| 		if !statement.Resources.Match(resource, args.ConditionValues) { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user