storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/signature-v2_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2016, 2017 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 cmd 18 19 import ( 20 "context" 21 "fmt" 22 "net/http" 23 "net/url" 24 "os" 25 "sort" 26 "testing" 27 ) 28 29 // Tests for 'func TestResourceListSorting(t *testing.T)'. 30 func TestResourceListSorting(t *testing.T) { 31 sortedResourceList := make([]string, len(resourceList)) 32 copy(sortedResourceList, resourceList) 33 sort.Strings(sortedResourceList) 34 for i := 0; i < len(resourceList); i++ { 35 if resourceList[i] != sortedResourceList[i] { 36 t.Errorf("Expected resourceList[%d] = \"%s\", resourceList is not correctly sorted.", i, sortedResourceList[i]) 37 break 38 } 39 } 40 } 41 42 // Tests presigned v2 signature. 43 func TestDoesPresignedV2SignatureMatch(t *testing.T) { 44 obj, fsDir, err := prepareFS() 45 if err != nil { 46 t.Fatal(err) 47 } 48 defer os.RemoveAll(fsDir) 49 if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { 50 t.Fatal(err) 51 } 52 53 now := UTCNow() 54 55 var ( 56 accessKey = globalActiveCred.AccessKey 57 secretKey = globalActiveCred.SecretKey 58 ) 59 testCases := []struct { 60 queryParams map[string]string 61 expected APIErrorCode 62 }{ 63 // (0) Should error without a set URL query. 64 { 65 expected: ErrInvalidQueryParams, 66 }, 67 // (1) Should error on an invalid access key. 68 { 69 queryParams: map[string]string{ 70 "Expires": "60", 71 "Signature": "badsignature", 72 "AWSAccessKeyId": "Z7IXGOO6BZ0REAN1Q26I", 73 }, 74 expected: ErrInvalidAccessKeyID, 75 }, 76 // (2) Should error with malformed expires. 77 { 78 queryParams: map[string]string{ 79 "Expires": "60s", 80 "Signature": "badsignature", 81 "AWSAccessKeyId": accessKey, 82 }, 83 expected: ErrMalformedExpires, 84 }, 85 // (3) Should give an expired request if it has expired. 86 { 87 queryParams: map[string]string{ 88 "Expires": "60", 89 "Signature": "badsignature", 90 "AWSAccessKeyId": accessKey, 91 }, 92 expected: ErrExpiredPresignRequest, 93 }, 94 // (4) Should error when the signature does not match. 95 { 96 queryParams: map[string]string{ 97 "Expires": fmt.Sprintf("%d", now.Unix()+60), 98 "Signature": "badsignature", 99 "AWSAccessKeyId": accessKey, 100 }, 101 expected: ErrSignatureDoesNotMatch, 102 }, 103 // (5) Should error when the signature does not match. 104 { 105 queryParams: map[string]string{ 106 "Expires": fmt.Sprintf("%d", now.Unix()+60), 107 "Signature": "zOM2YrY/yAQe15VWmT78OlBrK6g=", 108 "AWSAccessKeyId": accessKey, 109 }, 110 expected: ErrSignatureDoesNotMatch, 111 }, 112 // (6) Should not error signature matches with extra query params. 113 { 114 queryParams: map[string]string{ 115 "response-content-disposition": "attachment; filename=\"4K%2d4M.txt\"", 116 }, 117 expected: ErrNone, 118 }, 119 // (7) Should not error signature matches with no special query params. 120 { 121 queryParams: map[string]string{}, 122 expected: ErrNone, 123 }, 124 } 125 126 // Run each test case individually. 127 for i, testCase := range testCases { 128 // Turn the map[string]string into map[string][]string, because Go. 129 query := url.Values{} 130 for key, value := range testCase.queryParams { 131 query.Set(key, value) 132 } 133 // Create a request to use. 134 req, err := http.NewRequest(http.MethodGet, "http://host/a/b?"+query.Encode(), nil) 135 if err != nil { 136 t.Errorf("(%d) failed to create http.Request, got %v", i, err) 137 } 138 if testCase.expected != ErrNone { 139 // Should be set since we are simulating a http server. 140 req.RequestURI = req.URL.RequestURI() 141 // Check if it matches! 142 errCode := doesPresignV2SignatureMatch(req) 143 if errCode != testCase.expected { 144 t.Errorf("(%d) expected to get %s, instead got %s", i, niceError(testCase.expected), niceError(errCode)) 145 } 146 } else { 147 err = preSignV2(req, accessKey, secretKey, now.Unix()+60) 148 if err != nil { 149 t.Fatalf("(%d) failed to preSignV2 http request, got %v", i, err) 150 } 151 // Should be set since we are simulating a http server. 152 req.RequestURI = req.URL.RequestURI() 153 errCode := doesPresignV2SignatureMatch(req) 154 if errCode != testCase.expected { 155 t.Errorf("(%d) expected to get success, instead got %s", i, niceError(errCode)) 156 } 157 } 158 159 } 160 } 161 162 // TestValidateV2AuthHeader - Tests validate the logic of V2 Authorization header validator. 163 func TestValidateV2AuthHeader(t *testing.T) { 164 obj, fsDir, err := prepareFS() 165 if err != nil { 166 t.Fatal(err) 167 } 168 defer os.RemoveAll(fsDir) 169 if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { 170 t.Fatal(err) 171 } 172 173 accessID := globalActiveCred.AccessKey 174 testCases := []struct { 175 authString string 176 expectedError APIErrorCode 177 }{ 178 // Test case - 1. 179 // Case with empty V2AuthString. 180 { 181 182 authString: "", 183 expectedError: ErrAuthHeaderEmpty, 184 }, 185 // Test case - 2. 186 // Test case with `signV2Algorithm` ("AWS") not being the prefix. 187 { 188 189 authString: "NoV2Prefix", 190 expectedError: ErrSignatureVersionNotSupported, 191 }, 192 // Test case - 3. 193 // Test case with missing parts in the Auth string. 194 // below is the correct format of V2 Authorization header. 195 // Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature 196 { 197 198 authString: signV2Algorithm, 199 expectedError: ErrAuthHeaderEmpty, 200 }, 201 // Test case - 4. 202 // Test case with signature part missing. 203 { 204 205 authString: fmt.Sprintf("%s %s", signV2Algorithm, accessID), 206 expectedError: ErrMissingFieldsV2, 207 }, 208 // Test case - 5. 209 // Test case with wrong accessID. 210 { 211 212 authString: fmt.Sprintf("%s %s:%s", signV2Algorithm, "InvalidAccessID", "signature"), 213 expectedError: ErrInvalidAccessKeyID, 214 }, 215 // Test case - 6. 216 // Case with right accessID and format. 217 { 218 219 authString: fmt.Sprintf("%s %s:%s", signV2Algorithm, accessID, "signature"), 220 expectedError: ErrNone, 221 }, 222 } 223 224 for i, testCase := range testCases { 225 t.Run(fmt.Sprintf("Case %d AuthStr \"%s\".", i+1, testCase.authString), func(t *testing.T) { 226 227 req := &http.Request{ 228 Header: make(http.Header), 229 URL: &url.URL{}, 230 } 231 req.Header.Set("Authorization", testCase.authString) 232 _, actualErrCode := validateV2AuthHeader(req) 233 234 if testCase.expectedError != actualErrCode { 235 t.Errorf("Expected the error code to be %v, got %v.", testCase.expectedError, actualErrCode) 236 } 237 }) 238 } 239 240 } 241 242 func TestDoesPolicySignatureV2Match(t *testing.T) { 243 obj, fsDir, err := prepareFS() 244 if err != nil { 245 t.Fatal(err) 246 } 247 defer os.RemoveAll(fsDir) 248 if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { 249 t.Fatal(err) 250 } 251 252 creds := globalActiveCred 253 policy := "policy" 254 testCases := []struct { 255 accessKey string 256 policy string 257 signature string 258 errCode APIErrorCode 259 }{ 260 {"invalidAccessKey", policy, calculateSignatureV2(policy, creds.SecretKey), ErrInvalidAccessKeyID}, 261 {creds.AccessKey, policy, calculateSignatureV2("random", creds.SecretKey), ErrSignatureDoesNotMatch}, 262 {creds.AccessKey, policy, calculateSignatureV2(policy, creds.SecretKey), ErrNone}, 263 } 264 for i, test := range testCases { 265 formValues := make(http.Header) 266 formValues.Set("Awsaccesskeyid", test.accessKey) 267 formValues.Set("Signature", test.signature) 268 formValues.Set("Policy", test.policy) 269 _, errCode := doesPolicySignatureV2Match(context.TODO(), formValues) 270 if errCode != test.errCode { 271 t.Fatalf("(%d) expected to get %s, instead got %s", i+1, niceError(test.errCode), niceError(errCode)) 272 } 273 } 274 }