diff --git a/iam/converter.go b/iam/converter.go index bd3483e..61124ed 100644 --- a/iam/converter.go +++ b/iam/converter.go @@ -9,6 +9,7 @@ import ( "unicode/utf8" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" + "git.frostfs.info/TrueCloudLab/policy-engine/schema/common" ) const ( @@ -62,7 +63,11 @@ const ( s3ActionPutObjectVersionTagging = "s3:PutObjectVersionTagging" ) -const condKeyAWSPrincipalARN = "aws:PrincipalArn" +const ( + condKeyAWSPrincipalARN = "aws:PrincipalArn" + condKeyAWSPrincipalTagPrefix = "aws:PrincipalTag/" + userClaimTagPrefix = "tag-" +) const ( // String condition operators. @@ -175,7 +180,7 @@ func convertToChainCondition(c Conditions) ([]GroupedConditions, error) { group.Conditions[i] = chain.Condition{ Op: condType, Object: chain.ObjectRequest, - Key: key, + Key: transformKey(key), Value: converted, } } @@ -186,6 +191,15 @@ func convertToChainCondition(c Conditions) ([]GroupedConditions, error) { return grouped, nil } +func transformKey(key string) string { + tagName, isTag := strings.CutPrefix(key, condKeyAWSPrincipalTagPrefix) + if isTag { + return fmt.Sprintf(common.PropertyKeyFormatFrostFSIDUserClaim, userClaimTagPrefix+tagName) + } + + return key +} + func getConditionTypeAndConverter(op string) (chain.ConditionType, convertFunction, error) { switch { case strings.HasPrefix(op, "String"): diff --git a/iam/converter_test.go b/iam/converter_test.go index 97e1cd7..3e8a86e 100644 --- a/iam/converter_test.go +++ b/iam/converter_test.go @@ -1500,6 +1500,64 @@ func TestResourceParsing(t *testing.T) { } } +func TestTagsConditions(t *testing.T) { + policy := ` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "s3:PutObjectTagging", + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:PrincipalTag/department": "hr", + "aws:ResourceTag/owner": "hr-admin", + "aws:Request/scope": "*" + } + } + } + ] +} +` + + expectedConditions := []chain.Condition{ + { + Op: chain.CondStringEquals, + Object: chain.ObjectRequest, + Key: "frostfsid:userClaim/tag-department", + Value: "hr", + }, + { + Op: chain.CondStringEquals, + Object: chain.ObjectRequest, + Key: "aws:ResourceTag/owner", + Value: "hr-admin", + }, + { + Op: chain.CondStringEquals, + Object: chain.ObjectRequest, + Key: "aws:Request/scope", + Value: "*", + }, + } + + var p Policy + err := json.Unmarshal([]byte(policy), &p) + require.NoError(t, err) + + s3Chain, err := ConvertToS3Chain(p, newMockUserResolver(nil, nil, "")) + require.NoError(t, err) + require.Len(t, s3Chain.Rules, 1) + require.ElementsMatch(t, expectedConditions, s3Chain.Rules[0].Condition) + + nativeChain, err := ConvertToNativeChain(p, newMockUserResolver(nil, nil, "")) + require.NoError(t, err) + require.Len(t, nativeChain.Rules, 1) + require.ElementsMatch(t, expectedConditions, nativeChain.Rules[0].Condition) +} + func requireChainRulesMatch(t *testing.T, expected, actual []chain.Rule) { require.Equal(t, len(expected), len(actual), "length of chain rules differ") diff --git a/schema/common/consts.go b/schema/common/consts.go index 03ed340..592df91 100644 --- a/schema/common/consts.go +++ b/schema/common/consts.go @@ -2,4 +2,6 @@ package common const ( PropertyKeyFrostFSIDGroupID = "frostfsid:groupID" + + PropertyKeyFormatFrostFSIDUserClaim = "frostfsid:userClaim/%s" )