| 
									
										
										
										
											2021-04-19 03:41:13 +08: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-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-13 10:25:43 +08:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-04-30 10:01:43 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2017-08-13 10:25:43 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2021-11-24 01:51:53 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-06 03:20:08 +08:00
										 |  |  | 	jwtgo "github.com/golang-jwt/jwt/v4" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/auth" | 
					
						
							|  |  |  | 	xjwt "github.com/minio/minio/internal/jwt" | 
					
						
							| 
									
										
										
										
											2017-08-13 10:25:43 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func testAuthenticate(authType string, t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-07-22 04:58:51 +08:00
										 |  |  | 	obj, fsDir, err := prepareFS() | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		t.Fatal(err) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	defer os.RemoveAll(fsDir) | 
					
						
							|  |  |  | 	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 08:24:43 +08:00
										 |  |  | 	cred, err := auth.GetNewCredentials() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Error getting new credentials: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	globalActiveCred = cred | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Define test cases.
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		accessKey   string | 
					
						
							|  |  |  | 		secretKey   string | 
					
						
							|  |  |  | 		expectedErr error | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2018-02-02 11:43:30 +08:00
										 |  |  | 		// Access key (less than 3 chrs) too small.
 | 
					
						
							|  |  |  | 		{"u1", cred.SecretKey, auth.ErrInvalidAccessKeyLength}, | 
					
						
							| 
									
										
										
										
											2017-08-04 11:03:37 +08:00
										 |  |  | 		// Secret key (less than 8 chrs) too small.
 | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 		{cred.AccessKey, "pass", auth.ErrInvalidSecretKeyLength}, | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 		// Authentication error.
 | 
					
						
							|  |  |  | 		{"myuser", "mypassword", errInvalidAccessKeyID}, | 
					
						
							|  |  |  | 		// Authentication error.
 | 
					
						
							| 
									
										
										
										
											2017-08-04 11:03:37 +08:00
										 |  |  | 		{cred.AccessKey, "mypassword", errAuthentication}, | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 		// Success.
 | 
					
						
							| 
									
										
										
										
											2017-08-04 11:03:37 +08:00
										 |  |  | 		{cred.AccessKey, cred.SecretKey, nil}, | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Run tests.
 | 
					
						
							|  |  |  | 	for _, testCase := range testCases { | 
					
						
							|  |  |  | 		var err error | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 		if authType == "web" { | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 			_, err = authenticateWeb(testCase.accessKey, testCase.secretKey) | 
					
						
							| 
									
										
										
										
											2017-07-25 03:46:37 +08:00
										 |  |  | 		} else if authType == "url" { | 
					
						
							|  |  |  | 			_, err = authenticateURL(testCase.accessKey, testCase.secretKey) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if testCase.expectedErr != nil { | 
					
						
							|  |  |  | 			if err == nil { | 
					
						
							|  |  |  | 				t.Fatalf("%+v: expected: %s, got: <nil>", testCase, testCase.expectedErr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if testCase.expectedErr.Error() != err.Error() { | 
					
						
							|  |  |  | 				t.Fatalf("%+v: expected: %s, got: %s", testCase, testCase.expectedErr, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("%+v: expected: <nil>, got: %s", testCase, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | func TestAuthenticateWeb(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	testAuthenticate("web", t) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-25 03:46:37 +08:00
										 |  |  | func TestAuthenticateURL(t *testing.T) { | 
					
						
							|  |  |  | 	testAuthenticate("url", t) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-18 11:27:04 +08:00
										 |  |  | func getTokenString(accessKey, secretKey string) (string, error) { | 
					
						
							|  |  |  | 	claims := xjwt.NewMapClaims() | 
					
						
							|  |  |  | 	claims.SetExpiry(UTCNow().Add(defaultJWTExpiry)) | 
					
						
							|  |  |  | 	claims.SetAccessKey(accessKey) | 
					
						
							|  |  |  | 	token := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims) | 
					
						
							|  |  |  | 	return token.SignedString([]byte(secretKey)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 10:01:43 +08:00
										 |  |  | // Tests web request authenticator.
 | 
					
						
							|  |  |  | func TestWebRequestAuthenticate(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-07-22 04:58:51 +08:00
										 |  |  | 	obj, fsDir, err := prepareFS() | 
					
						
							| 
									
										
										
										
											2021-04-30 10:01:43 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(fsDir) | 
					
						
							|  |  |  | 	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	creds := globalActiveCred | 
					
						
							|  |  |  | 	token, err := getTokenString(creds.AccessKey, creds.SecretKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unable get token %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		req         *http.Request | 
					
						
							|  |  |  | 		expectedErr error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// Set valid authorization header.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			req: &http.Request{ | 
					
						
							|  |  |  | 				Header: http.Header{ | 
					
						
							|  |  |  | 					"Authorization": []string{token}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedErr: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// No authorization header.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			req: &http.Request{ | 
					
						
							|  |  |  | 				Header: http.Header{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedErr: errNoAuthToken, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// Invalid authorization token.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			req: &http.Request{ | 
					
						
							|  |  |  | 				Header: http.Header{ | 
					
						
							|  |  |  | 					"Authorization": []string{"invalid-token"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedErr: errAuthentication, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, testCase := range testCases { | 
					
						
							| 
									
										
										
										
											2022-03-15 00:09:22 +08:00
										 |  |  | 		_, _, _, gotErr := metricsRequestAuthenticate(testCase.req) | 
					
						
							| 
									
										
										
										
											2021-04-30 10:01:43 +08:00
										 |  |  | 		if testCase.expectedErr != gotErr { | 
					
						
							|  |  |  | 			t.Errorf("Test %d, expected err %s, got %s", i+1, testCase.expectedErr, gotErr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | func BenchmarkParseJWTStandardClaims(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2022-07-22 04:58:51 +08:00
										 |  |  | 	obj, fsDir, err := prepareFS() | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(fsDir) | 
					
						
							|  |  |  | 	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	creds := globalActiveCred | 
					
						
							|  |  |  | 	token, err := authenticateNode(creds.AccessKey, creds.SecretKey, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	b.ReportAllocs() | 
					
						
							|  |  |  | 	b.RunParallel(func(pb *testing.PB) { | 
					
						
							|  |  |  | 		for pb.Next() { | 
					
						
							|  |  |  | 			err = xjwt.ParseWithStandardClaims(token, xjwt.NewStandardClaims(), []byte(creds.SecretKey)) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				b.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkParseJWTMapClaims(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2022-07-22 04:58:51 +08:00
										 |  |  | 	obj, fsDir, err := prepareFS() | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(fsDir) | 
					
						
							|  |  |  | 	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	creds := globalActiveCred | 
					
						
							|  |  |  | 	token, err := authenticateNode(creds.AccessKey, creds.SecretKey, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	b.ReportAllocs() | 
					
						
							|  |  |  | 	b.RunParallel(func(pb *testing.PB) { | 
					
						
							|  |  |  | 		for pb.Next() { | 
					
						
							|  |  |  | 			err = xjwt.ParseWithClaims(token, xjwt.NewMapClaims(), func(*xjwt.MapClaims) ([]byte, error) { | 
					
						
							|  |  |  | 				return []byte(creds.SecretKey), nil | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				b.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | func BenchmarkAuthenticateNode(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2022-07-22 04:58:51 +08:00
										 |  |  | 	obj, fsDir, err := prepareFS() | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(fsDir) | 
					
						
							|  |  |  | 	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	creds := globalActiveCred | 
					
						
							| 
									
										
										
										
											2021-11-24 01:51:53 +08:00
										 |  |  | 	b.Run("uncached", func(b *testing.B) { | 
					
						
							|  |  |  | 		fn := authenticateNode | 
					
						
							|  |  |  | 		b.ResetTimer() | 
					
						
							|  |  |  | 		b.ReportAllocs() | 
					
						
							|  |  |  | 		for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 			fn(creds.AccessKey, creds.SecretKey, "aud") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	b.Run("cached", func(b *testing.B) { | 
					
						
							|  |  |  | 		fn := cachedAuthenticateNode(time.Second) | 
					
						
							|  |  |  | 		b.ResetTimer() | 
					
						
							|  |  |  | 		b.ReportAllocs() | 
					
						
							|  |  |  | 		for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 			fn(creds.AccessKey, creds.SecretKey, "aud") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkAuthenticateWeb(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2022-07-22 04:58:51 +08:00
										 |  |  | 	obj, fsDir, err := prepareFS() | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		b.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(fsDir) | 
					
						
							|  |  |  | 	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { | 
					
						
							|  |  |  | 		b.Fatal(err) | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	creds := globalActiveCred | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	b.ReportAllocs() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		authenticateWeb(creds.AccessKey, creds.SecretKey) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |