storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/policy/condition/func_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2018 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package condition 18 19 import ( 20 "encoding/json" 21 "reflect" 22 "testing" 23 ) 24 25 func TestFunctionsEvaluate(t *testing.T) { 26 func1, err := newNullFunc(S3XAmzCopySource, NewValueSet(NewBoolValue(true))) 27 if err != nil { 28 t.Fatalf("unexpected error. %v\n", err) 29 } 30 31 func2, err := newIPAddressFunc(AWSSourceIP, NewValueSet(NewStringValue("192.168.1.0/24"))) 32 if err != nil { 33 t.Fatalf("unexpected error. %v\n", err) 34 } 35 36 func3, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"))) 37 if err != nil { 38 t.Fatalf("unexpected error. %v\n", err) 39 } 40 41 func4, err := newStringLikeFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject*"))) 42 if err != nil { 43 t.Fatalf("unexpected error. %v\n", err) 44 } 45 46 case1Function := NewFunctions(func1, func2, func3, func4) 47 48 testCases := []struct { 49 functions Functions 50 values map[string][]string 51 expectedResult bool 52 }{ 53 {case1Function, map[string][]string{ 54 "x-amz-copy-source": {"mybucket/myobject"}, 55 "SourceIp": {"192.168.1.10"}, 56 }, false}, 57 {case1Function, map[string][]string{ 58 "x-amz-copy-source": {"mybucket/myobject"}, 59 "SourceIp": {"192.168.1.10"}, 60 "Refer": {"http://example.org/"}, 61 }, false}, 62 {case1Function, map[string][]string{"x-amz-copy-source": {"mybucket/myobject"}}, false}, 63 {case1Function, map[string][]string{"SourceIp": {"192.168.1.10"}}, false}, 64 {case1Function, map[string][]string{ 65 "x-amz-copy-source": {"mybucket/yourobject"}, 66 "SourceIp": {"192.168.1.10"}, 67 }, false}, 68 {case1Function, map[string][]string{ 69 "x-amz-copy-source": {"mybucket/myobject"}, 70 "SourceIp": {"192.168.2.10"}, 71 }, false}, 72 {case1Function, map[string][]string{ 73 "x-amz-copy-source": {"mybucket/myobject"}, 74 "Refer": {"http://example.org/"}, 75 }, false}, 76 } 77 78 for i, testCase := range testCases { 79 result := testCase.functions.Evaluate(testCase.values) 80 81 if result != testCase.expectedResult { 82 t.Errorf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result) 83 } 84 } 85 } 86 87 func TestFunctionsKeys(t *testing.T) { 88 func1, err := newNullFunc(S3XAmzCopySource, NewValueSet(NewBoolValue(true))) 89 if err != nil { 90 t.Fatalf("unexpected error. %v\n", err) 91 } 92 93 func2, err := newIPAddressFunc(AWSSourceIP, NewValueSet(NewStringValue("192.168.1.0/24"))) 94 if err != nil { 95 t.Fatalf("unexpected error. %v\n", err) 96 } 97 98 func3, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"))) 99 if err != nil { 100 t.Fatalf("unexpected error. %v\n", err) 101 } 102 103 func4, err := newStringLikeFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject*"))) 104 if err != nil { 105 t.Fatalf("unexpected error. %v\n", err) 106 } 107 108 testCases := []struct { 109 functions Functions 110 expectedResult KeySet 111 }{ 112 {NewFunctions(func1, func2, func3, func4), NewKeySet(S3XAmzCopySource, AWSSourceIP)}, 113 } 114 115 for i, testCase := range testCases { 116 result := testCase.functions.Keys() 117 118 if !reflect.DeepEqual(result, testCase.expectedResult) { 119 t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result) 120 } 121 } 122 } 123 124 func TestFunctionsMarshalJSON(t *testing.T) { 125 func1, err := newStringLikeFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPL*"))) 126 if err != nil { 127 t.Fatalf("unexpected error. %v\n", err) 128 } 129 130 func2, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"))) 131 if err != nil { 132 t.Fatalf("unexpected error. %v\n", err) 133 } 134 135 func3, err := newStringNotEqualsFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256"))) 136 if err != nil { 137 t.Fatalf("unexpected error. %v\n", err) 138 } 139 140 func4, err := newNotIPAddressFunc(AWSSourceIP, 141 NewValueSet(NewStringValue("10.1.10.0/24"))) 142 if err != nil { 143 t.Fatalf("unexpected error. %v\n", err) 144 } 145 146 func5, err := newStringNotLikeFunc(S3XAmzStorageClass, NewValueSet(NewStringValue("STANDARD"))) 147 if err != nil { 148 t.Fatalf("unexpected error. %v\n", err) 149 } 150 151 func6, err := newNullFunc(S3XAmzServerSideEncryptionCustomerAlgorithm, NewValueSet(NewBoolValue(true))) 152 if err != nil { 153 t.Fatalf("unexpected error. %v\n", err) 154 } 155 156 func7, err := newIPAddressFunc(AWSSourceIP, 157 NewValueSet(NewStringValue("192.168.1.0/24"))) 158 if err != nil { 159 t.Fatalf("unexpected error. %v\n", err) 160 } 161 162 case1Result := []byte(`{"IpAddress":{"aws:SourceIp":["192.168.1.0/24"]},"NotIpAddress":{"aws:SourceIp":["10.1.10.0/24"]},"Null":{"s3:x-amz-server-side-encryption-customer-algorithm":[true]},"StringEquals":{"s3:x-amz-copy-source":["mybucket/myobject"]},"StringLike":{"s3:x-amz-metadata-directive":["REPL*"]},"StringNotEquals":{"s3:x-amz-server-side-encryption":["AES256"]},"StringNotLike":{"s3:x-amz-storage-class":["STANDARD"]}}`) 163 164 case2Result := []byte(`{"Null":{"s3:x-amz-server-side-encryption-customer-algorithm":[true]}}`) 165 166 testCases := []struct { 167 functions Functions 168 expectedResult []byte 169 expectErr bool 170 }{ 171 {NewFunctions(func1, func2, func3, func4, func5, func6, func7), case1Result, false}, 172 {NewFunctions(func6), case2Result, false}, 173 {NewFunctions(), []byte(`{}`), false}, 174 {nil, []byte(`{}`), false}, 175 } 176 177 for i, testCase := range testCases { 178 result, err := json.Marshal(testCase.functions) 179 expectErr := (err != nil) 180 181 if testCase.expectErr != expectErr { 182 t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 183 } 184 185 if !testCase.expectErr { 186 if !reflect.DeepEqual(result, testCase.expectedResult) { 187 t.Fatalf("case %v: result: expected: %v, got: %v", i+1, string(testCase.expectedResult), string(result)) 188 } 189 } 190 } 191 } 192 193 func TestFunctionsUnmarshalJSON(t *testing.T) { 194 case1Data := []byte(`{ 195 "StringLike": { 196 "s3:x-amz-metadata-directive": "REPL*" 197 }, 198 "StringEquals": { 199 "s3:x-amz-copy-source": "mybucket/myobject" 200 }, 201 "StringNotEquals": { 202 "s3:x-amz-server-side-encryption": "AES256" 203 }, 204 "NotIpAddress": { 205 "aws:SourceIp": [ 206 "10.1.10.0/24", 207 "10.10.1.0/24" 208 ] 209 }, 210 "StringNotLike": { 211 "s3:x-amz-storage-class": "STANDARD" 212 }, 213 "Null": { 214 "s3:x-amz-server-side-encryption-customer-algorithm": true 215 }, 216 "IpAddress": { 217 "aws:SourceIp": [ 218 "192.168.1.0/24", 219 "192.168.2.0/24" 220 ] 221 } 222 }`) 223 func1, err := newStringLikeFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPL*"))) 224 if err != nil { 225 t.Fatalf("unexpected error. %v\n", err) 226 } 227 228 func2, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"))) 229 if err != nil { 230 t.Fatalf("unexpected error. %v\n", err) 231 } 232 233 func3, err := newStringNotEqualsFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256"))) 234 if err != nil { 235 t.Fatalf("unexpected error. %v\n", err) 236 } 237 238 func4, err := newNotIPAddressFunc(AWSSourceIP, 239 NewValueSet(NewStringValue("10.1.10.0/24"), NewStringValue("10.10.1.0/24"))) 240 if err != nil { 241 t.Fatalf("unexpected error. %v\n", err) 242 } 243 244 func5, err := newStringNotLikeFunc(S3XAmzStorageClass, NewValueSet(NewStringValue("STANDARD"))) 245 if err != nil { 246 t.Fatalf("unexpected error. %v\n", err) 247 } 248 249 func6, err := newNullFunc(S3XAmzServerSideEncryptionCustomerAlgorithm, NewValueSet(NewBoolValue(true))) 250 if err != nil { 251 t.Fatalf("unexpected error. %v\n", err) 252 } 253 254 func7, err := newIPAddressFunc(AWSSourceIP, 255 NewValueSet(NewStringValue("192.168.1.0/24"), NewStringValue("192.168.2.0/24"))) 256 if err != nil { 257 t.Fatalf("unexpected error. %v\n", err) 258 } 259 260 case2Data := []byte(`{ 261 "Null": { 262 "s3:x-amz-server-side-encryption-customer-algorithm": true 263 }, 264 "Null": { 265 "s3:x-amz-server-side-encryption-customer-algorithm": "true" 266 } 267 }`) 268 269 case3Data := []byte(`{}`) 270 271 case4Data := []byte(`{ 272 "StringLike": { 273 "s3:x-amz-metadata-directive": "REPL*" 274 }, 275 "StringEquals": { 276 "s3:x-amz-copy-source": "mybucket/myobject", 277 "s3:prefix": [ 278 "", 279 "home/" 280 ], 281 "s3:delimiter": [ 282 "/" 283 ] 284 }, 285 "StringNotEquals": { 286 "s3:x-amz-server-side-encryption": "AES256" 287 }, 288 "NotIpAddress": { 289 "aws:SourceIp": [ 290 "10.1.10.0/24", 291 "10.10.1.0/24" 292 ] 293 }, 294 "StringNotLike": { 295 "s3:x-amz-storage-class": "STANDARD" 296 }, 297 "Null": { 298 "s3:x-amz-server-side-encryption-customer-algorithm": true 299 }, 300 "IpAddress": { 301 "aws:SourceIp": [ 302 "192.168.1.0/24", 303 "192.168.2.0/24" 304 ] 305 } 306 }`) 307 308 func2_1, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"))) 309 if err != nil { 310 t.Fatalf("unexpected error. %v\n", err) 311 } 312 313 func2_2, err := newStringEqualsFunc(S3Prefix, NewValueSet(NewStringValue(""), NewStringValue("home/"))) 314 if err != nil { 315 t.Fatalf("unexpected error. %v\n", err) 316 } 317 318 func2_3, err := newStringEqualsFunc(S3Delimiter, NewValueSet(NewStringValue("/"))) 319 if err != nil { 320 t.Fatalf("unexpected error. %v\n", err) 321 } 322 323 testCases := []struct { 324 data []byte 325 expectedResult Functions 326 expectErr bool 327 }{ 328 // Success case, basic conditions. 329 {case1Data, NewFunctions(func1, func2, func3, func4, func5, func6, func7), false}, 330 // Duplicate conditions, success case only one value is preserved. 331 {case2Data, NewFunctions(func6), false}, 332 // empty condition error. 333 {case3Data, nil, true}, 334 // Success case multiple keys, same condition. 335 {case4Data, NewFunctions(func1, func2_1, func2_2, func2_3, func3, func4, func5, func6, func7), false}, 336 } 337 338 for i, testCase := range testCases { 339 result := new(Functions) 340 err := json.Unmarshal(testCase.data, result) 341 expectErr := (err != nil) 342 343 if testCase.expectErr != expectErr { 344 t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) 345 } 346 347 if !testCase.expectErr { 348 if (*result).String() != testCase.expectedResult.String() { 349 t.Fatalf("case %v: result: expected: %v, got: %v", i+1, testCase.expectedResult, *result) 350 } 351 } 352 } 353 }