cubefs/objectnode/policy_statement_test.go
slasher 5c7898354f style(all): format all codes with golangci tools
closes #3371

@formatter:off

Signed-off-by: slasher <shenjie1@oppo.com>
2024-05-14 09:54:13 +08:00

323 lines
9.1 KiB
Go

// Copyright 2023 The CubeFS Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
package objectnode
import (
"encoding/json"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestPolicyExample(t *testing.T) {
policyJson := `{
"Version": "2012-10-17",
"Id": "ExamplePolicy01",
"Statement": [
{
"Sid": "ExampleStatement01",
"Effect": "Allow",
"Principal": {
"AWS": ["11","22"]
},
"Action": [
"s3:GetObject",
"s3:GetBucketLocation",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::examplebucket/*",
"arn:aws:s3:::examplebucket"
],
"Condition": {
"StringLike": {
"aws:Referer": [
"*.cubefs.com"
]
}
}
}
]
}`
var policy Policy
err := json.Unmarshal([]byte(policyJson), &policy)
require.NoError(t, err)
out, _ := json.Marshal(policy)
err = json.Unmarshal(out, &policy)
require.NoError(t, err)
}
func TestMissingRequiredField(t *testing.T) {
policyJson := `{
"Version": "2008-10-17",
"Statement": [
{
"Principal": {
"AWS": "099454345549"
},
"action": [
"s3:ListBucket",
"s3:getobject"
],
"Resource": [
"arn:aws:s3:::examplebucket/*",
"arn:aws:s3:::examplebucket"
]
}
]
}`
var out1 Policy
dec := json.NewDecoder(strings.NewReader(policyJson))
dec.DisallowUnknownFields()
err := dec.Decode(&out1)
require.NoError(t, err)
_, err = out1.Validate("examplebucket")
require.EqualError(t, err, "missing Effect in policy")
policyJson = `{
"Version": "",
"Statement": [
{
"Principal": {
"AWS": "099454345549"
},
"Effect": "Allow",
"action": [
"s3:ListBucket",
"s3:getobject"
],
"Resource": [
"arn:aws:s3:::examplebucket/*",
"arn:aws:s3:::examplebucket"
]
}
]
}`
var out2 Policy
dec = json.NewDecoder(strings.NewReader(policyJson))
dec.DisallowUnknownFields()
err = dec.Decode(&out2)
require.NoError(t, err)
_, err = out2.Validate("examplebucket")
require.EqualError(t, err, "missing Version in policy")
policyJson = `{
"Version": "2008-10-17"
}`
var out3 Policy
dec = json.NewDecoder(strings.NewReader(policyJson))
dec.DisallowUnknownFields()
err = dec.Decode(&out3)
require.NoError(t, err)
_, err = out3.Validate("examplebucket")
require.EqualError(t, err, "missing Statement in policy")
}
func TestEffectFormat(t *testing.T) {
var s Statement
json.Unmarshal([]byte(`"dummy"`), &s.Effect)
b := s.isEffectValid()
require.False(t, b)
json.Unmarshal([]byte(`"alloW"`), &s.Effect)
b = s.isEffectValid()
require.True(t, b)
json.Unmarshal([]byte(`"Deny"`), &s.Effect)
b = s.isEffectValid()
require.True(t, b)
}
func TestResourceFormat(t *testing.T) {
// bad: "arn:aws:s3:::bucket/" , or "arn:aws:s3:::/keyname" or "arn:aws:s3:::/" or "arn:aws:s3:::wrongbucket/key" or [ ] empty
bucketId := "examplebucket"
var s Statement
validResources := []string{
`["arn:aws:s3:::examplebucket"]`,
`["arn:aws:s3:::examplebucket/*"]`,
`["arn:aws:s3:::examplebucket/abc"]`,
`["arn:aws:s3:::examplebucket/abc/*"]`,
`"arn:aws:s3:::examplebucket/abc?d/*"`,
`"arn:aws:s3:::examplebucket"`,
`"arn:aws:s3:::examplebucket/*"`,
}
for _, r := range validResources {
err := json.Unmarshal([]byte(r), &s.Resource)
require.NoError(t, err)
b := s.isResourceValid(bucketId)
require.True(t, b)
}
invalidResources := []string{
`["arn:aws:s3:::examplebucket/","arn:aws:s3:::examplebucket/key"]`, // first one is invaid
`["arn:aws:s3:::*/keyname"]`,
`["arn:aws:s3:::/keyname"]`,
`["arn:aws:s3:::/"]`,
`["arn:aws:s3:::/*"]`,
`["arn:aws:s3:::wrongbucket/key"]`,
`["arn:aws:s3:::wrongbucket"]`,
`["Arn:aws:s3:::examplebucket"]`, // Arn is invalid, should be arn
`[]`,
`""`,
`"arn:aws:s3:::exampl*bucket"`,
`"arn:aws:s3:::*"`,
`["arn:aws:s3:::*"]`,
}
for _, r := range invalidResources {
err := json.Unmarshal([]byte(r), &s.Resource)
require.NoError(t, err)
b := s.isResourceValid(bucketId)
require.False(t, b)
}
}
func TestPrincipalFormat(t *testing.T) {
var s Statement
b := s.isPrincipalValid()
require.False(t, b)
validPrincipal := []string{
`{"AWS":["11","22"]}`,
`{"AWS":"11"}`,
`{"AWS":"*"}`,
`"*"`,
`"11"`,
}
for _, p := range validPrincipal {
err := json.Unmarshal([]byte(p), &s.Principal)
require.NoError(t, err)
b := s.isPrincipalValid()
require.True(t, b)
}
invalidPrincipal := []string{
`{}`,
`{"aws":"11"}`, // must be "AWS", not "aws"
`{"AWS":11}`, // must be string, not number, 11 should be "11"
`{"AWS":[]}`,
`{"AWS":["11",22]}`,
`["11"]`, // currently, aws not support [] for principal
}
for _, p := range invalidPrincipal {
err := json.Unmarshal([]byte(p), &s.Principal)
require.NoError(t, err)
b := s.isPrincipalValid()
require.False(t, b)
}
}
func TestActionFormat(t *testing.T) {
var s Statement
validAction := []string{
`["s3:PutObject","s3:getobject","s3:deleteObject","s3:AbortMultipartUpload","s3:ListMultipartUploadParts"]`,
`["S3:ListBucket","S3:deletebucket","s3:listbucketMultipartUploads"]`,
`["s3:*"]`,
}
for _, a := range validAction {
err := json.Unmarshal([]byte(a), &s.Action)
require.NoError(t, err)
b := s.isActionValid()
require.True(t, b)
}
invalidAction := []string{
`["s3:CreateBucket"]`,
`["s3:ListAllMyBuckets"]`,
`["s3:DeleteBucketPolicy"]`,
`["s3:GetBucketPolicy"]`,
`["s3:PutBucketPolicy"]`,
`[]`,
`["s3:PutObject","s3:invalid"]`, // second is invalid
}
for _, a := range invalidAction {
err := json.Unmarshal([]byte(a), &s.Action)
require.NoError(t, err)
b := s.isActionValid()
require.False(t, b)
}
}
func TestConditionFormat(t *testing.T) {
validCondition := []string{
`{"IpAddress":{"aws:SourceIp":["1.1.1.1/24","1.1.1.1","fe80::45e:9d4c:20ca:20f7/64"]}}`,
`{"NotIpAddress":{"aws:SourceIp":"1.1.1.3"}}`,
`{"StringLike":{"aws:Referer":"http://*.example.com/*"}}`,
`{"StringLike":{"aws:Referer":["http://*.example.com/*","http://example.com/*"]}}`,
`{"StringLike":{"aws:Host":"http://*.example.com/*"}}`,
`{"StringLike":{"aws:Host":["http://*.example.com/*","http://example.com/*"]}}`,
`{"StringNotLike":{"aws:Referer":"http://*.example.com/*"}}`,
`{"StringNotLike":{"aws:Referer":["http://*.example.com/*","http://example.com/*"]}}`,
`{"StringNotLike":{"aws:Host":"http://*.example.com/*"}}`,
`{"StringNotLike":{"aws:Host":["http://*.example.com/*","http://example.com/*"]}}`,
}
for _, c := range validCondition {
var cond Condition
err := json.Unmarshal([]byte(c), &cond)
require.NoError(t, err)
}
invalidCondition := []string{
`{"ipAddress":{"aws:SourceIp":["1.1.1.1/24"]}}`, // should be "IpAddress"
`{"notIpAddress":{"aws:SourceIp":["1.1.1.3"]}}`, // should be "NotIpAddress"
`{"IpAddress":{"SourceIp":["1.1.1.3"]}}`, // should be "aws:SourceIp"
`{"StringLik":{"aws:Referer":"http://*.example.com/*"}}`, // should be "aws:StringLike"
`{"StringLike":{"aws:SourceIP":"http://*.example.com/*"}}`,
`{"StringLike":{"aws:referer":"http://*.example.com/*"}}`,
`{"StringLike":{"aws:host":"http://*.example.com/*"}}`,
`{"StringNotLik":{"aws:Referer":"http://*.example.com/*"}}`, // should be "aws:StringLike"
`{"StringNotLike":{"aws:SourceIP":"http://*.example.com/*"}}`,
`{"StringNotLike":{"aws:referer":"http://*.example.com/*"}}`,
`{"StringNotLike":{"aws:host":"http://*.example.com/*"}}`,
}
for _, c := range invalidCondition {
var cond Condition
err := json.Unmarshal([]byte(c), &cond)
require.Error(t, err)
}
}
func TestActionResourceCombination(t *testing.T) {
var s Statement
resource_action := []struct {
action string
resource string
matchResult bool
}{
{`["s3:*"]`, `["arn:aws:s3:::examplebucket"]`, true},
{`["s3:*"]`, `["arn:aws:s3:::examplebucket/*"]`, true},
{`["s3:ListBucket"]`, `["arn:aws:s3:::examplebucket"]`, true},
{`["s3:GetObject"]`, `["arn:aws:s3:::examplebucket/*"]`, true},
{`["s3:ListBucket"]`, `["arn:aws:s3:::examplebucket","arn:aws:s3:::examplebucket/*"]`, true},
{`["s3:GetObject"]`, `["arn:aws:s3:::examplebucket","arn:aws:s3:::examplebucket/*"]`, true},
{`["s3:GetObject","s3:ListBucket"]`, `["arn:aws:s3:::examplebucket","arn:aws:s3:::examplebucket/*"]`, true},
{`["s3:GetObject"]`, `["arn:aws:s3:::examplebucket"]`, false},
{`["s3:ListBucket"]`, `["arn:aws:s3:::examplebucket/*"]`, false},
{`["s3:GetObject","s3:ListBucket"]`, `["arn:aws:s3:::examplebucket"]`, false},
{`["s3:GetObject","s3:ListBucket"]`, `["arn:aws:s3:::examplebucket/*"]`, false},
}
for _, ra := range resource_action {
json.Unmarshal([]byte(ra.resource), &s.Resource)
json.Unmarshal([]byte(ra.action), &s.Action)
b := s.isValidCombination()
require.Equal(t, ra.matchResult, b)
}
}