mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
fix: support IAM policy handling for wildcard actions (#11530)
This PR fixes - allow 's3:versionid` as a valid conditional for Get,Put,Tags,Object locking APIs - allow additional headers missing for object APIs - allow wildcard based action matching
This commit is contained in:
parent
79b6a43467
commit
a94a9c37fa
@ -110,10 +110,9 @@ func registerAdminRouter(router *mux.Router, enableConfigOps, enableIAMOps bool)
|
|||||||
// -- IAM APIs --
|
// -- IAM APIs --
|
||||||
|
|
||||||
// Add policy IAM
|
// Add policy IAM
|
||||||
adminRouter.Methods(http.MethodPut).Path(adminVersion+"/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name", "{name:.*}")
|
adminRouter.Methods(http.MethodPut).Path(adminVersion+"/add-canned-policy").HandlerFunc(httpTraceAll(adminAPI.AddCannedPolicy)).Queries("name", "{name:.*}")
|
||||||
|
|
||||||
// Add user IAM
|
// Add user IAM
|
||||||
|
|
||||||
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/accountinfo").HandlerFunc(httpTraceAll(adminAPI.AccountInfoHandler))
|
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/accountinfo").HandlerFunc(httpTraceAll(adminAPI.AccountInfoHandler))
|
||||||
|
|
||||||
adminRouter.Methods(http.MethodPut).Path(adminVersion+"/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}")
|
adminRouter.Methods(http.MethodPut).Path(adminVersion+"/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}")
|
||||||
|
@ -124,6 +124,7 @@ var AllSupportedKeys = append([]Key{
|
|||||||
S3Prefix,
|
S3Prefix,
|
||||||
S3Delimiter,
|
S3Delimiter,
|
||||||
S3MaxKeys,
|
S3MaxKeys,
|
||||||
|
S3VersionID,
|
||||||
S3ObjectLockRemainingRetentionDays,
|
S3ObjectLockRemainingRetentionDays,
|
||||||
S3ObjectLockMode,
|
S3ObjectLockMode,
|
||||||
S3ObjectLockLegalHold,
|
S3ObjectLockLegalHold,
|
||||||
@ -143,6 +144,8 @@ var AllSupportedKeys = append([]Key{
|
|||||||
|
|
||||||
// CommonKeys - is list of all common condition keys.
|
// CommonKeys - is list of all common condition keys.
|
||||||
var CommonKeys = append([]Key{
|
var CommonKeys = append([]Key{
|
||||||
|
S3XAmzContentSha256,
|
||||||
|
S3LocationConstraint,
|
||||||
AWSReferer,
|
AWSReferer,
|
||||||
AWSSourceIP,
|
AWSSourceIP,
|
||||||
AWSUserAgent,
|
AWSUserAgent,
|
||||||
@ -152,7 +155,6 @@ var CommonKeys = append([]Key{
|
|||||||
AWSPrincipalType,
|
AWSPrincipalType,
|
||||||
AWSUserID,
|
AWSUserID,
|
||||||
AWSUsername,
|
AWSUsername,
|
||||||
S3XAmzContentSha256,
|
|
||||||
LDAPUser,
|
LDAPUser,
|
||||||
}, JWTKeys...)
|
}, JWTKeys...)
|
||||||
|
|
||||||
@ -241,6 +243,13 @@ func (set KeySet) Add(key Key) {
|
|||||||
set[key] = struct{}{}
|
set[key] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge merges two key sets, duplicates are overwritten
|
||||||
|
func (set KeySet) Merge(mset KeySet) {
|
||||||
|
for k, v := range mset {
|
||||||
|
set[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Difference - returns a key set contains difference of two keys.
|
// Difference - returns a key set contains difference of two keys.
|
||||||
// Example:
|
// Example:
|
||||||
// keySet1 := ["one", "two", "three"]
|
// keySet1 := ["one", "two", "three"]
|
||||||
|
@ -266,23 +266,45 @@ var supportedObjectActions = map[Action]struct{}{
|
|||||||
|
|
||||||
// isObjectAction - returns whether action is object type or not.
|
// isObjectAction - returns whether action is object type or not.
|
||||||
func (action Action) isObjectAction() bool {
|
func (action Action) isObjectAction() bool {
|
||||||
_, ok := supportedObjectActions[action]
|
for supAction := range supportedObjectActions {
|
||||||
return ok
|
if action.Match(supAction) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match - matches object name with resource pattern.
|
// Match - matches action name with action patter.
|
||||||
func (action Action) Match(a Action) bool {
|
func (action Action) Match(a Action) bool {
|
||||||
return wildcard.Match(string(action), string(a))
|
return wildcard.Match(string(action), string(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValid - checks if action is valid or not.
|
// IsValid - checks if action is valid or not.
|
||||||
func (action Action) IsValid() bool {
|
func (action Action) IsValid() bool {
|
||||||
_, ok := supportedActions[action]
|
for supAction := range supportedActions {
|
||||||
return ok
|
if action.Match(supAction) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// actionConditionKeyMap - holds mapping of supported condition key for an action.
|
type actionConditionKeyMap map[Action]condition.KeySet
|
||||||
var actionConditionKeyMap = map[Action]condition.KeySet{
|
|
||||||
|
func (a actionConditionKeyMap) Lookup(action Action) (condition.KeySet, bool) {
|
||||||
|
var ckeysMerged = condition.KeySet{}
|
||||||
|
var found bool
|
||||||
|
for act, ckey := range a {
|
||||||
|
if action.Match(act) {
|
||||||
|
ckeysMerged.Merge(ckey)
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ckeysMerged, found
|
||||||
|
}
|
||||||
|
|
||||||
|
// iamActionConditionKeyMap - holds mapping of supported condition key for an action.
|
||||||
|
var iamActionConditionKeyMap = actionConditionKeyMap{
|
||||||
AllActions: condition.NewKeySet(condition.AllSupportedKeys...),
|
AllActions: condition.NewKeySet(condition.AllSupportedKeys...),
|
||||||
|
|
||||||
AbortMultipartUploadAction: condition.NewKeySet(condition.CommonKeys...),
|
AbortMultipartUploadAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
@ -291,8 +313,6 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
|
|
||||||
DeleteBucketPolicyAction: condition.NewKeySet(condition.CommonKeys...),
|
DeleteBucketPolicyAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
|
|
||||||
DeleteObjectAction: condition.NewKeySet(condition.CommonKeys...),
|
|
||||||
|
|
||||||
GetBucketLocationAction: condition.NewKeySet(condition.CommonKeys...),
|
GetBucketLocationAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
|
|
||||||
GetBucketNotificationAction: condition.NewKeySet(condition.CommonKeys...),
|
GetBucketNotificationAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
@ -303,6 +323,7 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
append([]condition.Key{
|
append([]condition.Key{
|
||||||
condition.S3XAmzServerSideEncryption,
|
condition.S3XAmzServerSideEncryption,
|
||||||
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
||||||
|
condition.S3VersionID,
|
||||||
}, condition.CommonKeys...)...),
|
}, condition.CommonKeys...)...),
|
||||||
|
|
||||||
HeadBucketAction: condition.NewKeySet(condition.CommonKeys...),
|
HeadBucketAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
@ -335,6 +356,11 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
|
|
||||||
PutBucketPolicyAction: condition.NewKeySet(condition.CommonKeys...),
|
PutBucketPolicyAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
|
|
||||||
|
DeleteObjectAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
|
|
||||||
PutObjectAction: condition.NewKeySet(
|
PutObjectAction: condition.NewKeySet(
|
||||||
append([]condition.Key{
|
append([]condition.Key{
|
||||||
condition.S3XAmzCopySource,
|
condition.S3XAmzCopySource,
|
||||||
@ -342,6 +368,7 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
||||||
condition.S3XAmzMetadataDirective,
|
condition.S3XAmzMetadataDirective,
|
||||||
condition.S3XAmzStorageClass,
|
condition.S3XAmzStorageClass,
|
||||||
|
condition.S3VersionID,
|
||||||
condition.S3ObjectLockRetainUntilDate,
|
condition.S3ObjectLockRetainUntilDate,
|
||||||
condition.S3ObjectLockMode,
|
condition.S3ObjectLockMode,
|
||||||
condition.S3ObjectLockLegalHold,
|
condition.S3ObjectLockLegalHold,
|
||||||
@ -351,21 +378,32 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
// LockLegalHold is not supported with PutObjectRetentionAction
|
// LockLegalHold is not supported with PutObjectRetentionAction
|
||||||
PutObjectRetentionAction: condition.NewKeySet(
|
PutObjectRetentionAction: condition.NewKeySet(
|
||||||
append([]condition.Key{
|
append([]condition.Key{
|
||||||
|
condition.S3XAmzServerSideEncryption,
|
||||||
|
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
||||||
condition.S3ObjectLockRemainingRetentionDays,
|
condition.S3ObjectLockRemainingRetentionDays,
|
||||||
condition.S3ObjectLockRetainUntilDate,
|
condition.S3ObjectLockRetainUntilDate,
|
||||||
condition.S3ObjectLockMode,
|
condition.S3ObjectLockMode,
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
|
GetObjectRetentionAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3XAmzServerSideEncryption,
|
||||||
|
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
||||||
|
condition.S3VersionID,
|
||||||
}, condition.CommonKeys...)...),
|
}, condition.CommonKeys...)...),
|
||||||
|
|
||||||
GetObjectRetentionAction: condition.NewKeySet(condition.CommonKeys...),
|
|
||||||
PutObjectLegalHoldAction: condition.NewKeySet(
|
PutObjectLegalHoldAction: condition.NewKeySet(
|
||||||
append([]condition.Key{
|
append([]condition.Key{
|
||||||
|
condition.S3XAmzServerSideEncryption,
|
||||||
|
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
||||||
condition.S3ObjectLockLegalHold,
|
condition.S3ObjectLockLegalHold,
|
||||||
|
condition.S3VersionID,
|
||||||
}, condition.CommonKeys...)...),
|
}, condition.CommonKeys...)...),
|
||||||
GetObjectLegalHoldAction: condition.NewKeySet(condition.CommonKeys...),
|
GetObjectLegalHoldAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
|
|
||||||
// https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html
|
// https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html
|
||||||
BypassGovernanceRetentionAction: condition.NewKeySet(
|
BypassGovernanceRetentionAction: condition.NewKeySet(
|
||||||
append([]condition.Key{
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
condition.S3ObjectLockRemainingRetentionDays,
|
condition.S3ObjectLockRemainingRetentionDays,
|
||||||
condition.S3ObjectLockRetainUntilDate,
|
condition.S3ObjectLockRetainUntilDate,
|
||||||
condition.S3ObjectLockMode,
|
condition.S3ObjectLockMode,
|
||||||
@ -376,11 +414,24 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
PutBucketObjectLockConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
PutBucketObjectLockConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
GetBucketTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
GetBucketTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
PutBucketTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
PutBucketTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
PutObjectTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
|
||||||
GetObjectTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
|
||||||
DeleteObjectTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
|
||||||
|
|
||||||
PutObjectVersionTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
PutObjectTaggingAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
|
GetObjectTaggingAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
|
DeleteObjectTaggingAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
|
|
||||||
|
PutObjectVersionTaggingAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
GetObjectVersionAction: condition.NewKeySet(
|
GetObjectVersionAction: condition.NewKeySet(
|
||||||
append([]condition.Key{
|
append([]condition.Key{
|
||||||
condition.S3VersionID,
|
condition.S3VersionID,
|
||||||
@ -397,10 +448,22 @@ var actionConditionKeyMap = map[Action]condition.KeySet{
|
|||||||
append([]condition.Key{
|
append([]condition.Key{
|
||||||
condition.S3VersionID,
|
condition.S3VersionID,
|
||||||
}, condition.CommonKeys...)...),
|
}, condition.CommonKeys...)...),
|
||||||
GetReplicationConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
GetReplicationConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
PutReplicationConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
PutReplicationConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
||||||
ReplicateObjectAction: condition.NewKeySet(condition.CommonKeys...),
|
ReplicateObjectAction: condition.NewKeySet(
|
||||||
ReplicateDeleteAction: condition.NewKeySet(condition.CommonKeys...),
|
append([]condition.Key{
|
||||||
ReplicateTagsAction: condition.NewKeySet(condition.CommonKeys...),
|
condition.S3VersionID,
|
||||||
GetObjectVersionForReplicationAction: condition.NewKeySet(condition.CommonKeys...),
|
}, condition.CommonKeys...)...),
|
||||||
|
ReplicateDeleteAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
|
ReplicateTagsAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
|
GetObjectVersionForReplicationAction: condition.NewKeySet(
|
||||||
|
append([]condition.Key{
|
||||||
|
condition.S3VersionID,
|
||||||
|
}, condition.CommonKeys...)...),
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,15 @@ func (actionSet ActionSet) Match(action Action) bool {
|
|||||||
if r.Match(action) {
|
if r.Match(action) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a special case where GetObjectVersion
|
||||||
|
// means GetObject is enabled implicitly.
|
||||||
|
switch r {
|
||||||
|
case GetObjectVersionAction:
|
||||||
|
if action == GetObjectAction {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -20,7 +20,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/minio/minio-go/v7/pkg/set"
|
"github.com/minio/minio-go/v7/pkg/set"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
@ -432,6 +434,259 @@ func TestPolicyIsValid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse config with location constraints
|
||||||
|
func TestPolicyParseConfig(t *testing.T) {
|
||||||
|
policy1LocationConstraint := `{
|
||||||
|
"Version":"2012-10-17",
|
||||||
|
"Statement":[
|
||||||
|
{
|
||||||
|
"Sid":"statement1",
|
||||||
|
"Effect":"Allow",
|
||||||
|
"Action": "s3:CreateBucket",
|
||||||
|
"Resource": "arn:aws:s3:::*",
|
||||||
|
"Condition": {
|
||||||
|
"StringLike": {
|
||||||
|
"s3:LocationConstraint": "us-east-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Sid":"statement2",
|
||||||
|
"Effect":"Deny",
|
||||||
|
"Action": "s3:CreateBucket",
|
||||||
|
"Resource": "arn:aws:s3:::*",
|
||||||
|
"Condition": {
|
||||||
|
"StringNotLike": {
|
||||||
|
"s3:LocationConstraint": "us-east-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
policy2Condition := `{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Sid": "statement1",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": "s3:GetObjectVersion",
|
||||||
|
"Resource": "arn:aws:s3:::test/HappyFace.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Sid": "statement2",
|
||||||
|
"Effect": "Deny",
|
||||||
|
"Action": "s3:GetObjectVersion",
|
||||||
|
"Resource": "arn:aws:s3:::test/HappyFace.jpg",
|
||||||
|
"Condition": {
|
||||||
|
"StringNotEquals": {
|
||||||
|
"s3:versionid": "AaaHbAQitwiL_h47_44lRO2DDfLlBO5e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
policy3ConditionActionRegex := `{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Sid": "statement2",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": "s3:Get*",
|
||||||
|
"Resource": "arn:aws:s3:::test/HappyFace.jpg",
|
||||||
|
"Condition": {
|
||||||
|
"StringEquals": {
|
||||||
|
"s3:versionid": "AaaHbAQitwiL_h47_44lRO2DDfLlBO5e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
policy4ConditionAction := `{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Sid": "statement2",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": "s3:GetObject",
|
||||||
|
"Resource": "arn:aws:s3:::test/HappyFace.jpg",
|
||||||
|
"Condition": {
|
||||||
|
"StringEquals": {
|
||||||
|
"s3:versionid": "AaaHbAQitwiL_h47_44lRO2DDfLlBO5e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
policy5ConditionCurrenTime := `{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"s3:Get*",
|
||||||
|
"s3:Put*"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::test/*"
|
||||||
|
],
|
||||||
|
"Condition": {
|
||||||
|
"DateGreaterThan": {
|
||||||
|
"aws:CurrentTime": [
|
||||||
|
"2017-02-28T00:00:00Z"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
policy5ConditionCurrenTimeLesser := `{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"s3:Get*",
|
||||||
|
"s3:Put*"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::test/*"
|
||||||
|
],
|
||||||
|
"Condition": {
|
||||||
|
"DateLessThan": {
|
||||||
|
"aws:CurrentTime": [
|
||||||
|
"2017-02-28T00:00:00Z"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
p string
|
||||||
|
args Args
|
||||||
|
allowed bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
p: policy1LocationConstraint,
|
||||||
|
allowed: true,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "allowed",
|
||||||
|
Action: CreateBucketAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ConditionValues: map[string][]string{"LocationConstraint": {"us-east-1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy1LocationConstraint,
|
||||||
|
allowed: false,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "disallowed",
|
||||||
|
Action: CreateBucketAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ConditionValues: map[string][]string{"LocationConstraint": {"us-east-2"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy2Condition,
|
||||||
|
allowed: true,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "allowed",
|
||||||
|
Action: GetObjectAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ObjectName: "HappyFace.jpg",
|
||||||
|
ConditionValues: map[string][]string{"versionid": {"AaaHbAQitwiL_h47_44lRO2DDfLlBO5e"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy2Condition,
|
||||||
|
allowed: false,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "disallowed",
|
||||||
|
Action: GetObjectAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ObjectName: "HappyFace.jpg",
|
||||||
|
ConditionValues: map[string][]string{"versionid": {"AaaHbAQitwiL_h47_44lRO2DDfLlBO5f"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy3ConditionActionRegex,
|
||||||
|
allowed: true,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "allowed",
|
||||||
|
Action: GetObjectAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ObjectName: "HappyFace.jpg",
|
||||||
|
ConditionValues: map[string][]string{"versionid": {"AaaHbAQitwiL_h47_44lRO2DDfLlBO5e"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy3ConditionActionRegex,
|
||||||
|
allowed: false,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "disallowed",
|
||||||
|
Action: GetObjectAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ObjectName: "HappyFace.jpg",
|
||||||
|
ConditionValues: map[string][]string{"versionid": {"AaaHbAQitwiL_h47_44lRO2DDfLlBO5f"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy4ConditionAction,
|
||||||
|
allowed: true,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "allowed",
|
||||||
|
Action: GetObjectAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ObjectName: "HappyFace.jpg",
|
||||||
|
ConditionValues: map[string][]string{"versionid": {"AaaHbAQitwiL_h47_44lRO2DDfLlBO5e"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy5ConditionCurrenTime,
|
||||||
|
allowed: true,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "allowed",
|
||||||
|
Action: GetObjectAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ObjectName: "HappyFace.jpg",
|
||||||
|
ConditionValues: map[string][]string{
|
||||||
|
"CurrentTime": {time.Now().Format(time.RFC3339)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
p: policy5ConditionCurrenTimeLesser,
|
||||||
|
allowed: false,
|
||||||
|
args: Args{
|
||||||
|
AccountName: "disallowed",
|
||||||
|
Action: GetObjectAction,
|
||||||
|
BucketName: "test",
|
||||||
|
ObjectName: "HappyFace.jpg",
|
||||||
|
ConditionValues: map[string][]string{
|
||||||
|
"CurrentTime": {time.Now().Format(time.RFC3339)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.args.AccountName, func(t *testing.T) {
|
||||||
|
ip, err := ParseConfig(strings.NewReader(test.p))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if got := ip.IsAllowed(test.args); got != test.allowed {
|
||||||
|
t.Errorf("Expected %t, got %t", test.allowed, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPolicyUnmarshalJSONAndValidate(t *testing.T) {
|
func TestPolicyUnmarshalJSONAndValidate(t *testing.T) {
|
||||||
case1Data := []byte(`{
|
case1Data := []byte(`{
|
||||||
"ID": "MyPolicyForMyBucket1",
|
"ID": "MyPolicyForMyBucket1",
|
||||||
|
@ -114,8 +114,13 @@ func (statement Statement) isValid() error {
|
|||||||
return Errorf("unsupported Resource found %v for action %v", statement.Resources, action)
|
return Errorf("unsupported Resource found %v for action %v", statement.Resources, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condKeys, ok := iamActionConditionKeyMap.Lookup(action)
|
||||||
|
if !ok {
|
||||||
|
return Errorf("conditions are not supported for action %v", action)
|
||||||
|
}
|
||||||
|
|
||||||
keys := statement.Conditions.Keys()
|
keys := statement.Conditions.Keys()
|
||||||
keyDiff := keys.Difference(actionConditionKeyMap[action])
|
keyDiff := keys.Difference(condKeys)
|
||||||
if !keyDiff.IsEmpty() {
|
if !keyDiff.IsEmpty() {
|
||||||
return Errorf("unsupported condition keys '%v' used for action '%v'", keyDiff, action)
|
return Errorf("unsupported condition keys '%v' used for action '%v'", keyDiff, action)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user