2021-04-18 15:41:13 -04:00
|
|
|
// Copyright (c) 2015-2021 MinIO, Inc.
|
|
|
|
//
|
|
|
|
// This file is part of MinIO Object Storage stack
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2016-07-19 02:56:27 -04:00
|
|
|
|
2016-08-18 19:23:42 -04:00
|
|
|
package cmd
|
2016-07-19 02:56:27 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-11-12 14:07:43 -05:00
|
|
|
"context"
|
2016-07-19 02:56:27 -04:00
|
|
|
"io"
|
|
|
|
"net/http"
|
2016-09-16 18:17:49 -04:00
|
|
|
"net/url"
|
2017-08-12 22:25:43 -04:00
|
|
|
"os"
|
2016-07-19 02:56:27 -04:00
|
|
|
"testing"
|
2018-01-17 13:36:25 -05:00
|
|
|
"time"
|
2017-10-31 14:54:32 -04:00
|
|
|
|
2021-06-01 17:59:40 -04:00
|
|
|
"github.com/minio/minio/internal/auth"
|
2021-05-30 00:16:42 -04:00
|
|
|
iampolicy "github.com/minio/pkg/iam/policy"
|
2016-07-19 02:56:27 -04:00
|
|
|
)
|
|
|
|
|
2022-06-15 17:51:42 -04:00
|
|
|
type nullReader struct{}
|
|
|
|
|
|
|
|
func (r *nullReader) Read(b []byte) (int, error) {
|
|
|
|
return len(b), nil
|
|
|
|
}
|
|
|
|
|
2016-09-16 18:17:49 -04:00
|
|
|
// Test get request auth type.
|
|
|
|
func TestGetRequestAuthType(t *testing.T) {
|
|
|
|
type testCase struct {
|
|
|
|
req *http.Request
|
|
|
|
authT authType
|
|
|
|
}
|
2022-09-19 14:05:16 -04:00
|
|
|
nopCloser := io.NopCloser(io.LimitReader(&nullReader{}, 1024))
|
2016-09-16 18:17:49 -04:00
|
|
|
testCases := []testCase{
|
|
|
|
// Test case - 1
|
|
|
|
// Check for generic signature v4 header.
|
|
|
|
{
|
|
|
|
req: &http.Request{
|
|
|
|
URL: &url.URL{
|
2017-02-10 02:26:44 -05:00
|
|
|
Host: "127.0.0.1:9000",
|
2017-01-18 15:24:34 -05:00
|
|
|
Scheme: httpScheme,
|
2019-08-06 15:08:58 -04:00
|
|
|
Path: SlashSeparator,
|
2016-09-16 18:17:49 -04:00
|
|
|
},
|
|
|
|
Header: http.Header{
|
|
|
|
"Authorization": []string{"AWS4-HMAC-SHA256 <cred_string>"},
|
|
|
|
"X-Amz-Content-Sha256": []string{streamingContentSHA256},
|
2017-02-20 15:07:03 -05:00
|
|
|
"Content-Encoding": []string{streamingContentEncoding},
|
2016-09-16 18:17:49 -04:00
|
|
|
},
|
2020-07-20 15:52:49 -04:00
|
|
|
Method: http.MethodPut,
|
2021-08-08 01:43:01 -04:00
|
|
|
Body: nopCloser,
|
2016-09-16 18:17:49 -04:00
|
|
|
},
|
|
|
|
authT: authTypeStreamingSigned,
|
|
|
|
},
|
|
|
|
// Test case - 2
|
|
|
|
// Check for JWT header.
|
|
|
|
{
|
|
|
|
req: &http.Request{
|
|
|
|
URL: &url.URL{
|
2017-02-10 02:26:44 -05:00
|
|
|
Host: "127.0.0.1:9000",
|
2017-01-18 15:24:34 -05:00
|
|
|
Scheme: httpScheme,
|
2019-08-06 15:08:58 -04:00
|
|
|
Path: SlashSeparator,
|
2016-09-16 18:17:49 -04:00
|
|
|
},
|
|
|
|
Header: http.Header{
|
|
|
|
"Authorization": []string{"Bearer 12313123"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
authT: authTypeJWT,
|
|
|
|
},
|
|
|
|
// Test case - 3
|
|
|
|
// Empty authorization header.
|
|
|
|
{
|
|
|
|
req: &http.Request{
|
|
|
|
URL: &url.URL{
|
2017-02-10 02:26:44 -05:00
|
|
|
Host: "127.0.0.1:9000",
|
2017-01-18 15:24:34 -05:00
|
|
|
Scheme: httpScheme,
|
2019-08-06 15:08:58 -04:00
|
|
|
Path: SlashSeparator,
|
2016-09-16 18:17:49 -04:00
|
|
|
},
|
|
|
|
Header: http.Header{
|
|
|
|
"Authorization": []string{""},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
authT: authTypeUnknown,
|
|
|
|
},
|
|
|
|
// Test case - 4
|
|
|
|
// Check for presigned.
|
|
|
|
{
|
|
|
|
req: &http.Request{
|
|
|
|
URL: &url.URL{
|
2017-02-10 02:26:44 -05:00
|
|
|
Host: "127.0.0.1:9000",
|
2017-01-18 15:24:34 -05:00
|
|
|
Scheme: httpScheme,
|
2019-08-06 15:08:58 -04:00
|
|
|
Path: SlashSeparator,
|
2016-09-16 18:17:49 -04:00
|
|
|
RawQuery: "X-Amz-Credential=EXAMPLEINVALIDEXAMPL%2Fs3%2F20160314%2Fus-east-1",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
authT: authTypePresigned,
|
|
|
|
},
|
|
|
|
// Test case - 5
|
|
|
|
// Check for post policy.
|
|
|
|
{
|
|
|
|
req: &http.Request{
|
|
|
|
URL: &url.URL{
|
2017-02-10 02:26:44 -05:00
|
|
|
Host: "127.0.0.1:9000",
|
2017-01-18 15:24:34 -05:00
|
|
|
Scheme: httpScheme,
|
2019-08-06 15:08:58 -04:00
|
|
|
Path: SlashSeparator,
|
2016-09-16 18:17:49 -04:00
|
|
|
},
|
|
|
|
Header: http.Header{
|
|
|
|
"Content-Type": []string{"multipart/form-data"},
|
|
|
|
},
|
2020-07-20 15:52:49 -04:00
|
|
|
Method: http.MethodPost,
|
2021-08-08 01:43:01 -04:00
|
|
|
Body: nopCloser,
|
2016-09-16 18:17:49 -04:00
|
|
|
},
|
|
|
|
authT: authTypePostPolicy,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// .. Tests all request auth type.
|
|
|
|
for i, testc := range testCases {
|
|
|
|
authT := getRequestAuthType(testc.req)
|
|
|
|
if authT != testc.authT {
|
|
|
|
t.Errorf("Test %d: Expected %d, got %d", i+1, testc.authT, authT)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-08 23:56:29 -04:00
|
|
|
// Test all s3 supported auth types.
|
|
|
|
func TestS3SupportedAuthType(t *testing.T) {
|
|
|
|
type testCase struct {
|
|
|
|
authT authType
|
|
|
|
pass bool
|
|
|
|
}
|
|
|
|
// List of all valid and invalid test cases.
|
|
|
|
testCases := []testCase{
|
|
|
|
// Test 1 - supported s3 type anonymous.
|
|
|
|
{
|
|
|
|
authT: authTypeAnonymous,
|
|
|
|
pass: true,
|
|
|
|
},
|
|
|
|
// Test 2 - supported s3 type presigned.
|
|
|
|
{
|
|
|
|
authT: authTypePresigned,
|
|
|
|
pass: true,
|
|
|
|
},
|
|
|
|
// Test 3 - supported s3 type signed.
|
|
|
|
{
|
|
|
|
authT: authTypeSigned,
|
|
|
|
pass: true,
|
|
|
|
},
|
|
|
|
// Test 4 - supported s3 type with post policy.
|
|
|
|
{
|
|
|
|
authT: authTypePostPolicy,
|
|
|
|
pass: true,
|
|
|
|
},
|
|
|
|
// Test 5 - supported s3 type with streaming signed.
|
|
|
|
{
|
|
|
|
authT: authTypeStreamingSigned,
|
|
|
|
pass: true,
|
|
|
|
},
|
2016-09-30 17:32:13 -04:00
|
|
|
// Test 6 - supported s3 type with signature v2.
|
|
|
|
{
|
|
|
|
authT: authTypeSignedV2,
|
|
|
|
pass: true,
|
|
|
|
},
|
|
|
|
// Test 7 - supported s3 type with presign v2.
|
|
|
|
{
|
|
|
|
authT: authTypePresignedV2,
|
|
|
|
pass: true,
|
|
|
|
},
|
|
|
|
// Test 8 - JWT is not supported s3 type.
|
2016-08-08 23:56:29 -04:00
|
|
|
{
|
|
|
|
authT: authTypeJWT,
|
|
|
|
pass: false,
|
|
|
|
},
|
2016-09-30 17:32:13 -04:00
|
|
|
// Test 9 - unknown auth header is not supported s3 type.
|
2016-08-08 23:56:29 -04:00
|
|
|
{
|
|
|
|
authT: authTypeUnknown,
|
|
|
|
pass: false,
|
|
|
|
},
|
2016-09-30 17:32:13 -04:00
|
|
|
// Test 10 - some new auth type is not supported s3 type.
|
2016-08-08 23:56:29 -04:00
|
|
|
{
|
2016-09-30 17:32:13 -04:00
|
|
|
authT: authType(9),
|
2016-08-08 23:56:29 -04:00
|
|
|
pass: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
// Validate all the test cases.
|
|
|
|
for i, tt := range testCases {
|
|
|
|
ok := isSupportedS3AuthType(tt.authT)
|
|
|
|
if ok != tt.pass {
|
|
|
|
t.Errorf("Test %d:, Expected %t, got %t", i+1, tt.pass, ok)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 17:32:13 -04:00
|
|
|
func TestIsRequestPresignedSignatureV2(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
inputQueryKey string
|
|
|
|
inputQueryValue string
|
|
|
|
expectedResult bool
|
|
|
|
}{
|
|
|
|
// Test case - 1.
|
|
|
|
// Test case with query key "AWSAccessKeyId" set.
|
|
|
|
{"", "", false},
|
|
|
|
// Test case - 2.
|
|
|
|
{"AWSAccessKeyId", "", true},
|
|
|
|
// Test case - 3.
|
|
|
|
{"X-Amz-Content-Sha256", "", false},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, testCase := range testCases {
|
|
|
|
// creating an input HTTP request.
|
|
|
|
// Only the query parameters are relevant for this particular test.
|
2020-07-20 15:52:49 -04:00
|
|
|
inputReq, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
2016-09-30 17:32:13 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error initializing input HTTP request: %v", err)
|
|
|
|
}
|
|
|
|
q := inputReq.URL.Query()
|
|
|
|
q.Add(testCase.inputQueryKey, testCase.inputQueryValue)
|
|
|
|
inputReq.URL.RawQuery = q.Encode()
|
2021-08-08 01:43:01 -04:00
|
|
|
inputReq.ParseForm()
|
2016-09-30 17:32:13 -04:00
|
|
|
|
|
|
|
actualResult := isRequestPresignedSignatureV2(inputReq)
|
|
|
|
if testCase.expectedResult != actualResult {
|
|
|
|
t.Errorf("Test %d: Expected the result to `%v`, but instead got `%v`", i+1, testCase.expectedResult, actualResult)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-01 23:54:11 -04:00
|
|
|
// TestIsRequestPresignedSignatureV4 - Test validates the logic for presign signature verision v4 detection.
|
|
|
|
func TestIsRequestPresignedSignatureV4(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
inputQueryKey string
|
|
|
|
inputQueryValue string
|
|
|
|
expectedResult bool
|
|
|
|
}{
|
|
|
|
// Test case - 1.
|
|
|
|
// Test case with query key ""X-Amz-Credential" set.
|
|
|
|
{"", "", false},
|
|
|
|
// Test case - 2.
|
|
|
|
{"X-Amz-Credential", "", true},
|
|
|
|
// Test case - 3.
|
|
|
|
{"X-Amz-Content-Sha256", "", false},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, testCase := range testCases {
|
|
|
|
// creating an input HTTP request.
|
|
|
|
// Only the query parameters are relevant for this particular test.
|
2020-07-20 15:52:49 -04:00
|
|
|
inputReq, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
2016-08-01 23:54:11 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error initializing input HTTP request: %v", err)
|
|
|
|
}
|
|
|
|
q := inputReq.URL.Query()
|
|
|
|
q.Add(testCase.inputQueryKey, testCase.inputQueryValue)
|
|
|
|
inputReq.URL.RawQuery = q.Encode()
|
2021-08-08 01:43:01 -04:00
|
|
|
inputReq.ParseForm()
|
2016-08-01 23:54:11 -04:00
|
|
|
|
|
|
|
actualResult := isRequestPresignedSignatureV4(inputReq)
|
|
|
|
if testCase.expectedResult != actualResult {
|
|
|
|
t.Errorf("Test %d: Expected the result to `%v`, but instead got `%v`", i+1, testCase.expectedResult, actualResult)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-19 02:56:27 -04:00
|
|
|
// Provides a fully populated http request instance, fails otherwise.
|
|
|
|
func mustNewRequest(method string, urlStr string, contentLength int64, body io.ReadSeeker, t *testing.T) *http.Request {
|
|
|
|
req, err := newTestRequest(method, urlStr, contentLength, body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to initialize new http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is similar to mustNewRequest but additionally the request
|
|
|
|
// is signed with AWS Signature V4, fails if not able to do so.
|
|
|
|
func mustNewSignedRequest(method string, urlStr string, contentLength int64, body io.ReadSeeker, t *testing.T) *http.Request {
|
|
|
|
req := mustNewRequest(method, urlStr, contentLength, body, t)
|
2019-10-23 01:59:13 -04:00
|
|
|
cred := globalActiveCred
|
2016-12-26 13:21:23 -05:00
|
|
|
if err := signRequestV4(req, cred.AccessKey, cred.SecretKey); err != nil {
|
2016-07-19 02:56:27 -04:00
|
|
|
t.Fatalf("Unable to inititalized new signed http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
2018-01-17 13:36:25 -05:00
|
|
|
// This is similar to mustNewRequest but additionally the request
|
|
|
|
// is signed with AWS Signature V2, fails if not able to do so.
|
|
|
|
func mustNewSignedV2Request(method string, urlStr string, contentLength int64, body io.ReadSeeker, t *testing.T) *http.Request {
|
|
|
|
req := mustNewRequest(method, urlStr, contentLength, body, t)
|
2019-10-23 01:59:13 -04:00
|
|
|
cred := globalActiveCred
|
2018-01-17 13:36:25 -05:00
|
|
|
if err := signRequestV2(req, cred.AccessKey, cred.SecretKey); err != nil {
|
|
|
|
t.Fatalf("Unable to inititalized new signed http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is similar to mustNewRequest but additionally the request
|
|
|
|
// is presigned with AWS Signature V2, fails if not able to do so.
|
|
|
|
func mustNewPresignedV2Request(method string, urlStr string, contentLength int64, body io.ReadSeeker, t *testing.T) *http.Request {
|
|
|
|
req := mustNewRequest(method, urlStr, contentLength, body, t)
|
2019-10-23 01:59:13 -04:00
|
|
|
cred := globalActiveCred
|
2018-01-17 13:36:25 -05:00
|
|
|
if err := preSignV2(req, cred.AccessKey, cred.SecretKey, time.Now().Add(10*time.Minute).Unix()); err != nil {
|
|
|
|
t.Fatalf("Unable to inititalized new signed http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is similar to mustNewRequest but additionally the request
|
|
|
|
// is presigned with AWS Signature V4, fails if not able to do so.
|
|
|
|
func mustNewPresignedRequest(method string, urlStr string, contentLength int64, body io.ReadSeeker, t *testing.T) *http.Request {
|
|
|
|
req := mustNewRequest(method, urlStr, contentLength, body, t)
|
2019-10-23 01:59:13 -04:00
|
|
|
cred := globalActiveCred
|
2018-01-17 13:36:25 -05:00
|
|
|
if err := preSignV4(req, cred.AccessKey, cred.SecretKey, time.Now().Add(10*time.Minute).Unix()); err != nil {
|
|
|
|
t.Fatalf("Unable to inititalized new signed http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
2018-03-16 14:22:34 -04:00
|
|
|
func mustNewSignedShortMD5Request(method string, urlStr string, contentLength int64, body io.ReadSeeker, t *testing.T) *http.Request {
|
|
|
|
req := mustNewRequest(method, urlStr, contentLength, body, t)
|
|
|
|
req.Header.Set("Content-Md5", "invalid-digest")
|
2019-10-23 01:59:13 -04:00
|
|
|
cred := globalActiveCred
|
2018-03-16 14:22:34 -04:00
|
|
|
if err := signRequestV4(req, cred.AccessKey, cred.SecretKey); err != nil {
|
|
|
|
t.Fatalf("Unable to initialized new signed http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
|
|
|
func mustNewSignedEmptyMD5Request(method string, urlStr string, contentLength int64, body io.ReadSeeker, t *testing.T) *http.Request {
|
|
|
|
req := mustNewRequest(method, urlStr, contentLength, body, t)
|
|
|
|
req.Header.Set("Content-Md5", "")
|
2019-10-23 01:59:13 -04:00
|
|
|
cred := globalActiveCred
|
2018-03-16 14:22:34 -04:00
|
|
|
if err := signRequestV4(req, cred.AccessKey, cred.SecretKey); err != nil {
|
|
|
|
t.Fatalf("Unable to initialized new signed http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
2019-10-23 01:59:13 -04:00
|
|
|
func mustNewSignedBadMD5Request(method string, urlStr string, contentLength int64,
|
2022-04-13 15:00:11 -04:00
|
|
|
body io.ReadSeeker, t *testing.T,
|
|
|
|
) *http.Request {
|
2017-04-10 12:58:08 -04:00
|
|
|
req := mustNewRequest(method, urlStr, contentLength, body, t)
|
|
|
|
req.Header.Set("Content-Md5", "YWFhYWFhYWFhYWFhYWFhCg==")
|
2019-10-23 01:59:13 -04:00
|
|
|
cred := globalActiveCred
|
2017-04-10 12:58:08 -04:00
|
|
|
if err := signRequestV4(req, cred.AccessKey, cred.SecretKey); err != nil {
|
|
|
|
t.Fatalf("Unable to initialized new signed http request %s", err)
|
|
|
|
}
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
2016-07-19 02:56:27 -04:00
|
|
|
// Tests is requested authenticated function, tests replies for s3 errors.
|
|
|
|
func TestIsReqAuthenticated(t *testing.T) {
|
2022-10-14 06:08:40 -04:00
|
|
|
ctx, cancel := context.WithCancel(GlobalContext)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
objLayer, fsDir, err := prepareFS(ctx)
|
2016-07-19 02:56:27 -04:00
|
|
|
if err != nil {
|
2018-08-15 00:41:47 -04:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(fsDir)
|
|
|
|
if err = newTestConfig(globalMinioDefaultRegion, objLayer); err != nil {
|
2016-07-26 03:01:35 -04:00
|
|
|
t.Fatalf("unable initialize config file, %s", err)
|
2016-07-19 02:56:27 -04:00
|
|
|
}
|
|
|
|
|
2022-10-14 06:08:40 -04:00
|
|
|
initAllSubsystems(ctx)
|
2021-05-09 11:14:19 -04:00
|
|
|
|
2021-11-17 16:42:08 -05:00
|
|
|
initConfigSubsystem(ctx, objLayer)
|
2021-11-12 00:03:02 -05:00
|
|
|
|
2017-10-31 14:54:32 -04:00
|
|
|
creds, err := auth.CreateCredentials("myuser", "mypassword")
|
2017-03-16 03:16:06 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable create credential, %s", err)
|
|
|
|
}
|
|
|
|
|
2019-10-23 01:59:13 -04:00
|
|
|
globalActiveCred = creds
|
2016-07-19 02:56:27 -04:00
|
|
|
|
2023-04-28 15:24:14 -04:00
|
|
|
globalIAMSys.Init(ctx, objLayer, globalEtcdClient, 2*time.Second)
|
|
|
|
|
2016-07-19 02:56:27 -04:00
|
|
|
// List of test cases for validating http request authentication.
|
|
|
|
testCases := []struct {
|
|
|
|
req *http.Request
|
|
|
|
s3Error APIErrorCode
|
|
|
|
}{
|
|
|
|
// When request is unsigned, access denied is returned.
|
2020-07-20 15:52:49 -04:00
|
|
|
{mustNewRequest(http.MethodGet, "http://127.0.0.1:9000", 0, nil, t), ErrAccessDenied},
|
2018-03-16 14:22:34 -04:00
|
|
|
// Empty Content-Md5 header.
|
2020-07-20 15:52:49 -04:00
|
|
|
{mustNewSignedEmptyMD5Request(http.MethodPut, "http://127.0.0.1:9000/", 5, bytes.NewReader([]byte("hello")), t), ErrInvalidDigest},
|
2018-03-16 14:22:34 -04:00
|
|
|
// Short Content-Md5 header.
|
2020-07-20 15:52:49 -04:00
|
|
|
{mustNewSignedShortMD5Request(http.MethodPut, "http://127.0.0.1:9000/", 5, bytes.NewReader([]byte("hello")), t), ErrInvalidDigest},
|
2016-07-19 02:56:27 -04:00
|
|
|
// When request is properly signed, but has bad Content-MD5 header.
|
2020-07-20 15:52:49 -04:00
|
|
|
{mustNewSignedBadMD5Request(http.MethodPut, "http://127.0.0.1:9000/", 5, bytes.NewReader([]byte("hello")), t), ErrBadDigest},
|
2016-07-19 02:56:27 -04:00
|
|
|
// When request is properly signed, error is none.
|
2020-07-20 15:52:49 -04:00
|
|
|
{mustNewSignedRequest(http.MethodGet, "http://127.0.0.1:9000", 0, nil, t), ErrNone},
|
2016-07-19 02:56:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Validates all testcases.
|
2018-05-18 14:27:25 -04:00
|
|
|
for i, testCase := range testCases {
|
2021-11-25 16:06:25 -05:00
|
|
|
s3Error := isReqAuthenticated(ctx, testCase.req, globalSite.Region, serviceS3)
|
2019-02-27 20:46:55 -05:00
|
|
|
if s3Error != testCase.s3Error {
|
2022-09-19 14:05:16 -04:00
|
|
|
if _, err := io.ReadAll(testCase.req.Body); toAPIErrorCode(ctx, err) != testCase.s3Error {
|
2019-02-12 04:25:52 -05:00
|
|
|
t.Fatalf("Test %d: Unexpected S3 error: want %d - got %d (got after reading request %s)", i, testCase.s3Error, s3Error, toAPIError(ctx, err).Code)
|
2018-05-18 14:27:25 -04:00
|
|
|
}
|
2016-07-19 02:56:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-22 16:42:01 -04:00
|
|
|
|
2018-01-17 13:36:25 -05:00
|
|
|
func TestCheckAdminRequestAuthType(t *testing.T) {
|
2022-10-14 06:08:40 -04:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
objLayer, fsDir, err := prepareFS(ctx)
|
2018-01-17 13:36:25 -05:00
|
|
|
if err != nil {
|
2018-08-15 00:41:47 -04:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(fsDir)
|
|
|
|
|
|
|
|
if err = newTestConfig(globalMinioDefaultRegion, objLayer); err != nil {
|
2018-01-17 13:36:25 -05:00
|
|
|
t.Fatalf("unable initialize config file, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
creds, err := auth.CreateCredentials("myuser", "mypassword")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable create credential, %s", err)
|
|
|
|
}
|
|
|
|
|
2019-10-23 01:59:13 -04:00
|
|
|
globalActiveCred = creds
|
2018-01-17 13:36:25 -05:00
|
|
|
testCases := []struct {
|
|
|
|
Request *http.Request
|
|
|
|
ErrCode APIErrorCode
|
|
|
|
}{
|
2020-07-20 15:52:49 -04:00
|
|
|
{Request: mustNewRequest(http.MethodGet, "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrAccessDenied},
|
|
|
|
{Request: mustNewSignedRequest(http.MethodGet, "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrNone},
|
|
|
|
{Request: mustNewSignedV2Request(http.MethodGet, "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrAccessDenied},
|
|
|
|
{Request: mustNewPresignedV2Request(http.MethodGet, "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrAccessDenied},
|
|
|
|
{Request: mustNewPresignedRequest(http.MethodGet, "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrAccessDenied},
|
2018-01-17 13:36:25 -05:00
|
|
|
}
|
|
|
|
for i, testCase := range testCases {
|
2021-11-25 16:06:25 -05:00
|
|
|
if _, s3Error := checkAdminRequestAuth(ctx, testCase.Request, iampolicy.AllAdminActions, globalSite.Region); s3Error != testCase.ErrCode {
|
2018-01-17 13:36:25 -05:00
|
|
|
t.Errorf("Test %d: Unexpected s3error returned wanted %d, got %d", i, testCase.ErrCode, s3Error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-22 16:42:01 -04:00
|
|
|
|
|
|
|
func TestValidateAdminSignature(t *testing.T) {
|
2021-11-12 00:03:02 -05:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
2020-04-22 16:42:01 -04:00
|
|
|
|
2022-10-14 06:08:40 -04:00
|
|
|
objLayer, fsDir, err := prepareFS(ctx)
|
2020-04-22 16:42:01 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(fsDir)
|
|
|
|
|
|
|
|
if err = newTestConfig(globalMinioDefaultRegion, objLayer); err != nil {
|
|
|
|
t.Fatalf("unable initialize config file, %s", err)
|
|
|
|
}
|
2021-05-09 11:14:19 -04:00
|
|
|
|
2022-10-14 06:08:40 -04:00
|
|
|
initAllSubsystems(ctx)
|
2021-05-09 11:14:19 -04:00
|
|
|
|
2023-04-28 15:24:14 -04:00
|
|
|
initConfigSubsystem(ctx, objLayer)
|
2020-04-22 16:42:01 -04:00
|
|
|
|
|
|
|
creds, err := auth.CreateCredentials("admin", "mypassword")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable create credential, %s", err)
|
|
|
|
}
|
|
|
|
globalActiveCred = creds
|
|
|
|
|
2023-04-28 15:24:14 -04:00
|
|
|
globalIAMSys.Init(ctx, objLayer, globalEtcdClient, 2*time.Second)
|
|
|
|
|
2020-04-22 16:42:01 -04:00
|
|
|
testCases := []struct {
|
|
|
|
AccessKey string
|
|
|
|
SecretKey string
|
|
|
|
ErrCode APIErrorCode
|
|
|
|
}{
|
|
|
|
{"", "", ErrInvalidAccessKeyID},
|
|
|
|
{"admin", "", ErrSignatureDoesNotMatch},
|
|
|
|
{"admin", "wrongpassword", ErrSignatureDoesNotMatch},
|
|
|
|
{"wronguser", "mypassword", ErrInvalidAccessKeyID},
|
|
|
|
{"", "mypassword", ErrInvalidAccessKeyID},
|
|
|
|
{"admin", "mypassword", ErrNone},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, testCase := range testCases {
|
2020-07-20 15:52:49 -04:00
|
|
|
req := mustNewRequest(http.MethodGet, "http://localhost:9000/", 0, nil, t)
|
2020-04-22 16:42:01 -04:00
|
|
|
if err := signRequestV4(req, testCase.AccessKey, testCase.SecretKey); err != nil {
|
|
|
|
t.Fatalf("Unable to inititalized new signed http request %s", err)
|
|
|
|
}
|
2023-02-06 12:27:29 -05:00
|
|
|
_, _, s3Error := validateAdminSignature(ctx, req, globalMinioDefaultRegion)
|
2020-04-22 16:42:01 -04:00
|
|
|
if s3Error != testCase.ErrCode {
|
|
|
|
t.Errorf("Test %d: Unexpected s3error returned wanted %d, got %d", i+1, testCase.ErrCode, s3Error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|