github.com/minio/console@v1.4.1/api/admin_policies_test.go (about) 1 // This file is part of MinIO Console Server 2 // Copyright (c) 2021 MinIO, Inc. 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Affero General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 package api 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "reflect" 26 "testing" 27 28 "github.com/minio/console/models" 29 iampolicy "github.com/minio/pkg/v3/policy" 30 "github.com/stretchr/testify/assert" 31 ) 32 33 func TestListPolicies(t *testing.T) { 34 ctx, cancel := context.WithCancel(context.Background()) 35 defer cancel() 36 funcAssert := assert.New(t) 37 adminClient := AdminClientMock{} 38 // mock function response from listPolicies() 39 minioListPoliciesMock = func() (map[string]*iampolicy.Policy, error) { 40 var readonly iampolicy.Policy 41 var readwrite iampolicy.Policy 42 var diagnostis iampolicy.Policy 43 44 for _, p := range iampolicy.DefaultPolicies { 45 switch p.Name { 46 case "readonly": 47 readonly = p.Definition 48 case "readwrite": 49 readwrite = p.Definition 50 case "diagnostics": 51 diagnostis = p.Definition 52 } 53 } 54 55 return map[string]*iampolicy.Policy{ 56 "readonly": &readonly, 57 "readwrite": &readwrite, 58 "diagnostics": &diagnostis, 59 }, nil 60 } 61 // Test-1 : listPolicies() Get response from minio client with three Canned Policies and return the same number on listPolicies() 62 function := "listPolicies()" 63 policiesList, err := listPolicies(ctx, adminClient) 64 if err != nil { 65 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 66 } 67 // verify length of Policies is correct 68 funcAssert.Equal(3, len(policiesList), fmt.Sprintf("Failed on %s: length of Policies's lists is not the same", function)) 69 // Test-2 : listPolicies() Return error and see that the error is handled correctly and returned 70 minioListPoliciesMock = func() (map[string]*iampolicy.Policy, error) { 71 return nil, errors.New("error") 72 } 73 _, err = listPolicies(ctx, adminClient) 74 if funcAssert.Error(err) { 75 funcAssert.Equal("error", err.Error()) 76 } 77 } 78 79 func TestRemovePolicy(t *testing.T) { 80 ctx, cancel := context.WithCancel(context.Background()) 81 defer cancel() 82 funcAssert := assert.New(t) 83 adminClient := AdminClientMock{} 84 // Test-1 : removePolicy() remove an existing policy 85 policyToRemove := "console-policy" 86 minioRemovePolicyMock = func(_ string) error { 87 return nil 88 } 89 function := "removePolicy()" 90 if err := removePolicy(ctx, adminClient, policyToRemove); err != nil { 91 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 92 } 93 // Test-2 : removePolicy() Return error and see that the error is handled correctly and returned 94 minioRemovePolicyMock = func(_ string) error { 95 return errors.New("error") 96 } 97 if err := removePolicy(ctx, adminClient, policyToRemove); funcAssert.Error(err) { 98 funcAssert.Equal("error", err.Error()) 99 } 100 } 101 102 func TestAddPolicy(t *testing.T) { 103 ctx, cancel := context.WithCancel(context.Background()) 104 defer cancel() 105 funcAssert := assert.New(t) 106 adminClient := AdminClientMock{} 107 policyName := "new-policy" 108 policyDefinition := "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetBucketLocation\",\"s3:GetObject\",\"s3:ListAllMyBuckets\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}" 109 minioAddPolicyMock = func(_ string, _ *iampolicy.Policy) error { 110 return nil 111 } 112 minioGetPolicyMock = func(_ string) (*iampolicy.Policy, error) { 113 policy := "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetBucketLocation\",\"s3:GetObject\",\"s3:ListAllMyBuckets\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}" 114 iamp, err := iampolicy.ParseConfig(bytes.NewReader([]byte(policy))) 115 if err != nil { 116 return nil, err 117 } 118 return iamp, nil 119 } 120 assertPolicy := models.Policy{ 121 Name: "new-policy", 122 Policy: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetBucketLocation\",\"s3:GetObject\",\"s3:ListAllMyBuckets\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}", 123 } 124 // Test-1 : addPolicy() adds a new policy 125 function := "addPolicy()" 126 policy, err := addPolicy(ctx, adminClient, policyName, policyDefinition) 127 if err != nil { 128 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 129 } else { 130 funcAssert.Equal(policy.Name, assertPolicy.Name) 131 132 var expectedPolicy iampolicy.Policy 133 var actualPolicy iampolicy.Policy 134 err1 := json.Unmarshal([]byte(policy.Policy), &expectedPolicy) 135 funcAssert.NoError(err1) 136 err2 := json.Unmarshal([]byte(assertPolicy.Policy), &actualPolicy) 137 funcAssert.NoError(err2) 138 funcAssert.Equal(expectedPolicy, actualPolicy) 139 } 140 // Test-2 : addPolicy() got an error while adding policy 141 minioAddPolicyMock = func(_ string, _ *iampolicy.Policy) error { 142 return errors.New("error") 143 } 144 if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); funcAssert.Error(err) { 145 funcAssert.Equal("error", err.Error()) 146 } 147 // Test-3 : addPolicy() got an error while retrieving policy 148 minioAddPolicyMock = func(_ string, _ *iampolicy.Policy) error { 149 return nil 150 } 151 minioGetPolicyMock = func(_ string) (*iampolicy.Policy, error) { 152 return nil, errors.New("error") 153 } 154 if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); funcAssert.Error(err) { 155 funcAssert.Equal("error", err.Error()) 156 } 157 } 158 159 func TestSetPolicy(t *testing.T) { 160 ctx, cancel := context.WithCancel(context.Background()) 161 defer cancel() 162 funcAssert := assert.New(t) 163 adminClient := AdminClientMock{} 164 policyName := "readOnly" 165 entityName := "alevsk" 166 entityObject := models.PolicyEntityUser 167 minioSetPolicyMock = func(_, _ string, _ bool) error { 168 return nil 169 } 170 // Test-1 : SetPolicy() set policy to user 171 function := "SetPolicy()" 172 err := SetPolicy(ctx, adminClient, policyName, entityName, entityObject) 173 if err != nil { 174 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 175 } 176 // Test-2 : SetPolicy() set policy to group 177 entityObject = models.PolicyEntityGroup 178 err = SetPolicy(ctx, adminClient, policyName, entityName, entityObject) 179 if err != nil { 180 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 181 } 182 // Test-3 : SetPolicy() set policy to user and get error 183 entityObject = models.PolicyEntityUser 184 minioSetPolicyMock = func(_, _ string, _ bool) error { 185 return errors.New("error") 186 } 187 if err := SetPolicy(ctx, adminClient, policyName, entityName, entityObject); funcAssert.Error(err) { 188 funcAssert.Equal("error", err.Error()) 189 } 190 // Test-4 : SetPolicy() set policy to group and get error 191 entityObject = models.PolicyEntityGroup 192 minioSetPolicyMock = func(_, _ string, _ bool) error { 193 return errors.New("error") 194 } 195 if err := SetPolicy(ctx, adminClient, policyName, entityName, entityObject); funcAssert.Error(err) { 196 funcAssert.Equal("error", err.Error()) 197 } 198 } 199 200 func Test_SetPolicyMultiple(t *testing.T) { 201 ctx, cancel := context.WithCancel(context.Background()) 202 defer cancel() 203 adminClient := AdminClientMock{} 204 205 type args struct { 206 policyName string 207 users []models.IamEntity 208 groups []models.IamEntity 209 setPolicyFunc func(policyName, entityName string, isGroup bool) error 210 } 211 tests := []struct { 212 name string 213 args args 214 errorExpected error 215 }{ 216 { 217 name: "Set policy to multiple users and groups", 218 args: args{ 219 policyName: "readonly", 220 users: []models.IamEntity{"user1", "user2"}, 221 groups: []models.IamEntity{"group1", "group2"}, 222 setPolicyFunc: func(_, _ string, _ bool) error { 223 return nil 224 }, 225 }, 226 errorExpected: nil, 227 }, 228 { 229 name: "Return error on set policy function", 230 args: args{ 231 policyName: "readonly", 232 users: []models.IamEntity{"user1", "user2"}, 233 groups: []models.IamEntity{"group1", "group2"}, 234 setPolicyFunc: func(_, _ string, _ bool) error { 235 return errors.New("error set") 236 }, 237 }, 238 errorExpected: errors.New("error set"), 239 }, 240 { 241 // Description: Empty lists of users and groups are acceptable 242 name: "Empty lists of users and groups", 243 args: args{ 244 policyName: "readonly", 245 users: []models.IamEntity{}, 246 groups: []models.IamEntity{}, 247 setPolicyFunc: func(_, _ string, _ bool) error { 248 return nil 249 }, 250 }, 251 errorExpected: nil, 252 }, 253 } 254 for _, tt := range tests { 255 t.Run(tt.name, func(_ *testing.T) { 256 minioSetPolicyMock = tt.args.setPolicyFunc 257 got := setPolicyMultipleEntities(ctx, adminClient, tt.args.policyName, tt.args.users, tt.args.groups) 258 if !reflect.DeepEqual(got, tt.errorExpected) { 259 ji, _ := json.Marshal(got) 260 vi, _ := json.Marshal(tt.errorExpected) 261 t.Errorf("got %s want %s", ji, vi) 262 } 263 }) 264 } 265 } 266 267 func Test_policyMatchesBucket(t *testing.T) { 268 type args struct { 269 ctx context.Context 270 policy *models.Policy 271 bucket string 272 } 273 tests := []struct { 274 name string 275 args args 276 want bool 277 }{ 278 { 279 name: "Test1", 280 args: args{ctx: context.Background(), policy: &models.Policy{Name: "consoleAdmin", Policy: `{ 281 "Version": "2012-10-17", 282 "Statement": [ 283 { 284 "Effect": "Allow", 285 "Action": [ 286 "admin:*" 287 ] 288 }, 289 { 290 "Effect": "Allow", 291 "Action": [ 292 "s3:*" 293 ], 294 "Resource": [ 295 "arn:aws:s3:::*" 296 ] 297 } 298 ] 299 }`}, bucket: "test1"}, 300 want: true, 301 }, 302 { 303 name: "Test2", 304 args: args{ctx: context.Background(), policy: &models.Policy{Name: "consoleAdmin", Policy: `{ 305 "Version": "2012-10-17", 306 "Statement": [ 307 { 308 "Effect": "Allow", 309 "Action": [ 310 "s3:*" 311 ], 312 "Resource": [ 313 "arn:aws:s3:::bucket1" 314 ] 315 } 316 ] 317 }`}, bucket: "test1"}, 318 want: false, 319 }, 320 { 321 name: "Test3", 322 args: args{ctx: context.Background(), policy: &models.Policy{Name: "consoleAdmin", Policy: `{ 323 "Version": "2012-10-17", 324 "Statement": [ 325 { 326 "Sid": "VisualEditor0", 327 "Effect": "Allow", 328 "Action": [ 329 "s3:ListStorageLensConfigurations", 330 "s3:GetAccessPoint", 331 "s3:PutAccountPublicAccessBlock", 332 "s3:GetAccountPublicAccessBlock", 333 "s3:ListAllMyBuckets", 334 "s3:ListAccessPoints", 335 "s3:ListJobs", 336 "s3:PutStorageLensConfiguration", 337 "s3:CreateJob" 338 ], 339 "Resource": "*" 340 }, 341 { 342 "Sid": "VisualEditor1", 343 "Effect": "Allow", 344 "Action": "s3:*", 345 "Resource": [ 346 "arn:aws:s3:::test", 347 "arn:aws:s3:::test/*", 348 "arn:aws:s3:::lkasdkljasd090901", 349 "arn:aws:s3:::lkasdkljasd090901/*" 350 ] 351 } 352 ] 353 }`}, bucket: "test1"}, 354 want: false, 355 }, 356 { 357 name: "Test4", 358 args: args{ctx: context.Background(), policy: &models.Policy{Name: "consoleAdmin", Policy: `{ 359 "Version": "2012-10-17", 360 "Statement": [ 361 { 362 "Effect": "Allow", 363 "Action": [ 364 "s3:*" 365 ], 366 "Resource": [ 367 "arn:aws:s3:::bucket1" 368 ] 369 } 370 ] 371 }`}, bucket: "bucket1"}, 372 want: true, 373 }, 374 } 375 for _, tt := range tests { 376 t.Run(tt.name, func(_ *testing.T) { 377 if got := policyMatchesBucket(tt.args.ctx, tt.args.policy, tt.args.bucket); got != tt.want { 378 t.Errorf("policyMatchesBucket() = %v, want %v", got, tt.want) 379 } 380 }) 381 } 382 }