github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/jwt_test.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"context"
    22  	"net/http"
    23  	"os"
    24  	"testing"
    25  	"time"
    26  
    27  	jwtgo "github.com/golang-jwt/jwt/v4"
    28  	xjwt "github.com/minio/minio/internal/jwt"
    29  )
    30  
    31  func getTokenString(accessKey, secretKey string) (string, error) {
    32  	claims := xjwt.NewMapClaims()
    33  	claims.SetExpiry(UTCNow().Add(defaultJWTExpiry))
    34  	claims.SetAccessKey(accessKey)
    35  	token := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims)
    36  	return token.SignedString([]byte(secretKey))
    37  }
    38  
    39  // Tests web request authenticator.
    40  func TestWebRequestAuthenticate(t *testing.T) {
    41  	ctx, cancel := context.WithCancel(context.Background())
    42  	defer cancel()
    43  
    44  	obj, fsDir, err := prepareFS(ctx)
    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  	creds := globalActiveCred
    54  	token, err := getTokenString(creds.AccessKey, creds.SecretKey)
    55  	if err != nil {
    56  		t.Fatalf("unable get token %s", err)
    57  	}
    58  	testCases := []struct {
    59  		req         *http.Request
    60  		expectedErr error
    61  	}{
    62  		// Set valid authorization header.
    63  		{
    64  			req: &http.Request{
    65  				Header: http.Header{
    66  					"Authorization": []string{token},
    67  				},
    68  			},
    69  			expectedErr: nil,
    70  		},
    71  		// No authorization header.
    72  		{
    73  			req: &http.Request{
    74  				Header: http.Header{},
    75  			},
    76  			expectedErr: errNoAuthToken,
    77  		},
    78  		// Invalid authorization token.
    79  		{
    80  			req: &http.Request{
    81  				Header: http.Header{
    82  					"Authorization": []string{"invalid-token"},
    83  				},
    84  			},
    85  			expectedErr: errAuthentication,
    86  		},
    87  	}
    88  
    89  	for i, testCase := range testCases {
    90  		_, _, _, gotErr := metricsRequestAuthenticate(testCase.req)
    91  		if testCase.expectedErr != gotErr {
    92  			t.Errorf("Test %d, expected err %s, got %s", i+1, testCase.expectedErr, gotErr)
    93  		}
    94  	}
    95  }
    96  
    97  func BenchmarkParseJWTStandardClaims(b *testing.B) {
    98  	ctx, cancel := context.WithCancel(context.Background())
    99  	defer cancel()
   100  
   101  	obj, fsDir, err := prepareFS(ctx)
   102  	if err != nil {
   103  		b.Fatal(err)
   104  	}
   105  	defer os.RemoveAll(fsDir)
   106  	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil {
   107  		b.Fatal(err)
   108  	}
   109  
   110  	creds := globalActiveCred
   111  	token, err := authenticateNode(creds.AccessKey, creds.SecretKey, "")
   112  	if err != nil {
   113  		b.Fatal(err)
   114  	}
   115  
   116  	b.ResetTimer()
   117  	b.ReportAllocs()
   118  	b.RunParallel(func(pb *testing.PB) {
   119  		for pb.Next() {
   120  			err = xjwt.ParseWithStandardClaims(token, xjwt.NewStandardClaims(), []byte(creds.SecretKey))
   121  			if err != nil {
   122  				b.Fatal(err)
   123  			}
   124  		}
   125  	})
   126  }
   127  
   128  func BenchmarkParseJWTMapClaims(b *testing.B) {
   129  	ctx, cancel := context.WithCancel(context.Background())
   130  	defer cancel()
   131  
   132  	obj, fsDir, err := prepareFS(ctx)
   133  	if err != nil {
   134  		b.Fatal(err)
   135  	}
   136  	defer os.RemoveAll(fsDir)
   137  	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil {
   138  		b.Fatal(err)
   139  	}
   140  
   141  	creds := globalActiveCred
   142  	token, err := authenticateNode(creds.AccessKey, creds.SecretKey, "")
   143  	if err != nil {
   144  		b.Fatal(err)
   145  	}
   146  
   147  	b.ResetTimer()
   148  	b.ReportAllocs()
   149  	b.RunParallel(func(pb *testing.PB) {
   150  		for pb.Next() {
   151  			err = xjwt.ParseWithClaims(token, xjwt.NewMapClaims(), func(*xjwt.MapClaims) ([]byte, error) {
   152  				return []byte(creds.SecretKey), nil
   153  			})
   154  			if err != nil {
   155  				b.Fatal(err)
   156  			}
   157  		}
   158  	})
   159  }
   160  
   161  func BenchmarkAuthenticateNode(b *testing.B) {
   162  	ctx, cancel := context.WithCancel(context.Background())
   163  	defer cancel()
   164  
   165  	obj, fsDir, err := prepareFS(ctx)
   166  	if err != nil {
   167  		b.Fatal(err)
   168  	}
   169  	defer os.RemoveAll(fsDir)
   170  	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil {
   171  		b.Fatal(err)
   172  	}
   173  
   174  	creds := globalActiveCred
   175  	b.Run("uncached", func(b *testing.B) {
   176  		fn := authenticateNode
   177  		b.ResetTimer()
   178  		b.ReportAllocs()
   179  		for i := 0; i < b.N; i++ {
   180  			fn(creds.AccessKey, creds.SecretKey, "aud")
   181  		}
   182  	})
   183  	b.Run("cached", func(b *testing.B) {
   184  		fn := cachedAuthenticateNode(time.Second)
   185  		b.ResetTimer()
   186  		b.ReportAllocs()
   187  		for i := 0; i < b.N; i++ {
   188  			fn(creds.AccessKey, creds.SecretKey, "aud")
   189  		}
   190  	})
   191  }