github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/policy_test.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"reflect"
    22  	"testing"
    23  
    24  	miniogopolicy "github.com/minio/minio-go/v7/pkg/policy"
    25  	"github.com/minio/minio-go/v7/pkg/set"
    26  	"github.com/minio/pkg/v2/policy"
    27  	"github.com/minio/pkg/v2/policy/condition"
    28  )
    29  
    30  func TestPolicySysIsAllowed(t *testing.T) {
    31  	p := &policy.BucketPolicy{
    32  		Version: policy.DefaultVersion,
    33  		Statements: []policy.BPStatement{
    34  			policy.NewBPStatement("",
    35  				policy.Allow,
    36  				policy.NewPrincipal("*"),
    37  				policy.NewActionSet(policy.GetBucketLocationAction),
    38  				policy.NewResourceSet(policy.NewResource("mybucket")),
    39  				condition.NewFunctions(),
    40  			),
    41  			policy.NewBPStatement("",
    42  				policy.Allow,
    43  				policy.NewPrincipal("*"),
    44  				policy.NewActionSet(policy.PutObjectAction),
    45  				policy.NewResourceSet(policy.NewResource("mybucket/myobject*")),
    46  				condition.NewFunctions(),
    47  			),
    48  		},
    49  	}
    50  
    51  	anonGetBucketLocationArgs := policy.BucketPolicyArgs{
    52  		AccountName:     "Q3AM3UQ867SPQQA43P2F",
    53  		Action:          policy.GetBucketLocationAction,
    54  		BucketName:      "mybucket",
    55  		ConditionValues: map[string][]string{},
    56  	}
    57  
    58  	anonPutObjectActionArgs := policy.BucketPolicyArgs{
    59  		AccountName: "Q3AM3UQ867SPQQA43P2F",
    60  		Action:      policy.PutObjectAction,
    61  		BucketName:  "mybucket",
    62  		ConditionValues: map[string][]string{
    63  			"x-amz-copy-source": {"mybucket/myobject"},
    64  			"SourceIp":          {"192.168.1.10"},
    65  		},
    66  		ObjectName: "myobject",
    67  	}
    68  
    69  	anonGetObjectActionArgs := policy.BucketPolicyArgs{
    70  		AccountName:     "Q3AM3UQ867SPQQA43P2F",
    71  		Action:          policy.GetObjectAction,
    72  		BucketName:      "mybucket",
    73  		ConditionValues: map[string][]string{},
    74  		ObjectName:      "myobject",
    75  	}
    76  
    77  	getBucketLocationArgs := policy.BucketPolicyArgs{
    78  		AccountName:     "Q3AM3UQ867SPQQA43P2F",
    79  		Action:          policy.GetBucketLocationAction,
    80  		BucketName:      "mybucket",
    81  		ConditionValues: map[string][]string{},
    82  		IsOwner:         true,
    83  	}
    84  
    85  	putObjectActionArgs := policy.BucketPolicyArgs{
    86  		AccountName: "Q3AM3UQ867SPQQA43P2F",
    87  		Action:      policy.PutObjectAction,
    88  		BucketName:  "mybucket",
    89  		ConditionValues: map[string][]string{
    90  			"x-amz-copy-source": {"mybucket/myobject"},
    91  			"SourceIp":          {"192.168.1.10"},
    92  		},
    93  		IsOwner:    true,
    94  		ObjectName: "myobject",
    95  	}
    96  
    97  	getObjectActionArgs := policy.BucketPolicyArgs{
    98  		AccountName:     "Q3AM3UQ867SPQQA43P2F",
    99  		Action:          policy.GetObjectAction,
   100  		BucketName:      "mybucket",
   101  		ConditionValues: map[string][]string{},
   102  		IsOwner:         true,
   103  		ObjectName:      "myobject",
   104  	}
   105  
   106  	yourbucketAnonGetObjectActionArgs := policy.BucketPolicyArgs{
   107  		AccountName:     "Q3AM3UQ867SPQQA43P2F",
   108  		Action:          policy.GetObjectAction,
   109  		BucketName:      "yourbucket",
   110  		ConditionValues: map[string][]string{},
   111  		ObjectName:      "yourobject",
   112  	}
   113  
   114  	yourbucketGetObjectActionArgs := policy.BucketPolicyArgs{
   115  		AccountName:     "Q3AM3UQ867SPQQA43P2F",
   116  		Action:          policy.GetObjectAction,
   117  		BucketName:      "yourbucket",
   118  		ConditionValues: map[string][]string{},
   119  		IsOwner:         true,
   120  		ObjectName:      "yourobject",
   121  	}
   122  
   123  	testCases := []struct {
   124  		args           policy.BucketPolicyArgs
   125  		expectedResult bool
   126  	}{
   127  		{anonGetBucketLocationArgs, true},
   128  		{anonPutObjectActionArgs, true},
   129  		{anonGetObjectActionArgs, false},
   130  		{getBucketLocationArgs, true},
   131  		{putObjectActionArgs, true},
   132  		{getObjectActionArgs, true},
   133  		{yourbucketAnonGetObjectActionArgs, false},
   134  		{yourbucketGetObjectActionArgs, true},
   135  	}
   136  
   137  	for i, testCase := range testCases {
   138  		result := p.IsAllowed(testCase.args)
   139  
   140  		if result != testCase.expectedResult {
   141  			t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
   142  		}
   143  	}
   144  }
   145  
   146  func getReadOnlyStatement(bucketName, prefix string) []miniogopolicy.Statement {
   147  	return []miniogopolicy.Statement{
   148  		{
   149  			Effect:    string(policy.Allow),
   150  			Principal: miniogopolicy.User{AWS: set.CreateStringSet("*")},
   151  			Resources: set.CreateStringSet(policy.NewResource(bucketName).String()),
   152  			Actions:   set.CreateStringSet("s3:GetBucketLocation", "s3:ListBucket"),
   153  		},
   154  		{
   155  			Effect:    string(policy.Allow),
   156  			Principal: miniogopolicy.User{AWS: set.CreateStringSet("*")},
   157  			Resources: set.CreateStringSet(policy.NewResource(bucketName + "/" + prefix).String()),
   158  			Actions:   set.CreateStringSet("s3:GetObject"),
   159  		},
   160  	}
   161  }
   162  
   163  func TestPolicyToBucketAccessPolicy(t *testing.T) {
   164  	case1Policy := &policy.BucketPolicy{
   165  		Version: policy.DefaultVersion,
   166  		Statements: []policy.BPStatement{
   167  			policy.NewBPStatement("",
   168  				policy.Allow,
   169  				policy.NewPrincipal("*"),
   170  				policy.NewActionSet(policy.GetBucketLocationAction, policy.ListBucketAction),
   171  				policy.NewResourceSet(policy.NewResource("mybucket")),
   172  				condition.NewFunctions(),
   173  			),
   174  			policy.NewBPStatement("",
   175  				policy.Allow,
   176  				policy.NewPrincipal("*"),
   177  				policy.NewActionSet(policy.GetObjectAction),
   178  				policy.NewResourceSet(policy.NewResource("mybucket/myobject*")),
   179  				condition.NewFunctions(),
   180  			),
   181  		},
   182  	}
   183  
   184  	case1Result := &miniogopolicy.BucketAccessPolicy{
   185  		Version:    policy.DefaultVersion,
   186  		Statements: getReadOnlyStatement("mybucket", "myobject*"),
   187  	}
   188  
   189  	case2Policy := &policy.BucketPolicy{
   190  		Version:    policy.DefaultVersion,
   191  		Statements: []policy.BPStatement{},
   192  	}
   193  
   194  	case2Result := &miniogopolicy.BucketAccessPolicy{
   195  		Version:    policy.DefaultVersion,
   196  		Statements: []miniogopolicy.Statement{},
   197  	}
   198  
   199  	case3Policy := &policy.BucketPolicy{
   200  		Version: "12-10-2012",
   201  		Statements: []policy.BPStatement{
   202  			policy.NewBPStatement("",
   203  				policy.Allow,
   204  				policy.NewPrincipal("*"),
   205  				policy.NewActionSet(policy.PutObjectAction),
   206  				policy.NewResourceSet(policy.NewResource("mybucket/myobject*")),
   207  				condition.NewFunctions(),
   208  			),
   209  		},
   210  	}
   211  
   212  	testCases := []struct {
   213  		bucketPolicy   *policy.BucketPolicy
   214  		expectedResult *miniogopolicy.BucketAccessPolicy
   215  		expectErr      bool
   216  	}{
   217  		{case1Policy, case1Result, false},
   218  		{case2Policy, case2Result, false},
   219  		{case3Policy, nil, true},
   220  	}
   221  
   222  	for i, testCase := range testCases {
   223  		result, err := PolicyToBucketAccessPolicy(testCase.bucketPolicy)
   224  		expectErr := (err != nil)
   225  
   226  		if expectErr != testCase.expectErr {
   227  			t.Fatalf("case %v: error: expected: %v, got: %v\n", i+1, testCase.expectErr, expectErr)
   228  		}
   229  
   230  		if !testCase.expectErr {
   231  			if !reflect.DeepEqual(result, testCase.expectedResult) {
   232  				t.Fatalf("case %v: result: expected: %+v, got: %+v\n", i+1, testCase.expectedResult, result)
   233  			}
   234  		}
   235  	}
   236  }
   237  
   238  func TestBucketAccessPolicyToPolicy(t *testing.T) {
   239  	case1PolicyInfo := &miniogopolicy.BucketAccessPolicy{
   240  		Version:    policy.DefaultVersion,
   241  		Statements: getReadOnlyStatement("mybucket", "myobject*"),
   242  	}
   243  
   244  	case1Result := &policy.BucketPolicy{
   245  		Version: policy.DefaultVersion,
   246  		Statements: []policy.BPStatement{
   247  			policy.NewBPStatement("",
   248  				policy.Allow,
   249  				policy.NewPrincipal("*"),
   250  				policy.NewActionSet(policy.GetBucketLocationAction, policy.ListBucketAction),
   251  				policy.NewResourceSet(policy.NewResource("mybucket")),
   252  				condition.NewFunctions(),
   253  			),
   254  			policy.NewBPStatement("",
   255  				policy.Allow,
   256  				policy.NewPrincipal("*"),
   257  				policy.NewActionSet(policy.GetObjectAction),
   258  				policy.NewResourceSet(policy.NewResource("mybucket/myobject*")),
   259  				condition.NewFunctions(),
   260  			),
   261  		},
   262  	}
   263  
   264  	case2PolicyInfo := &miniogopolicy.BucketAccessPolicy{
   265  		Version:    policy.DefaultVersion,
   266  		Statements: []miniogopolicy.Statement{},
   267  	}
   268  
   269  	case2Result := &policy.BucketPolicy{
   270  		Version:    policy.DefaultVersion,
   271  		Statements: []policy.BPStatement{},
   272  	}
   273  
   274  	case3PolicyInfo := &miniogopolicy.BucketAccessPolicy{
   275  		Version:    "12-10-2012",
   276  		Statements: getReadOnlyStatement("mybucket", "/myobject*"),
   277  	}
   278  
   279  	testCases := []struct {
   280  		policyInfo     *miniogopolicy.BucketAccessPolicy
   281  		expectedResult *policy.BucketPolicy
   282  		expectErr      bool
   283  	}{
   284  		{case1PolicyInfo, case1Result, false},
   285  		{case2PolicyInfo, case2Result, false},
   286  		{case3PolicyInfo, nil, true},
   287  	}
   288  
   289  	for i, testCase := range testCases {
   290  		result, err := BucketAccessPolicyToPolicy(testCase.policyInfo)
   291  		expectErr := (err != nil)
   292  
   293  		if expectErr != testCase.expectErr {
   294  			t.Fatalf("case %v: error: expected: %v, got: %v\n", i+1, testCase.expectErr, expectErr)
   295  		}
   296  
   297  		if !testCase.expectErr {
   298  			if !reflect.DeepEqual(result, testCase.expectedResult) {
   299  				t.Fatalf("case %v: result: expected: %+v, got: %+v\n", i+1, testCase.expectedResult, result)
   300  			}
   301  		}
   302  	}
   303  }