github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/jwt/parser_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 jwt
    19  
    20  // This file is a re-implementation of the original code here with some
    21  // additional allocation tweaks reproduced using GODEBUG=allocfreetrace=1
    22  // original file https://github.com/golang-jwt/jwt/blob/main/parser.go
    23  // borrowed under MIT License https://github.com/golang-jwt/jwt/blob/main/LICENSE
    24  
    25  import (
    26  	"fmt"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/golang-jwt/jwt/v4"
    31  )
    32  
    33  var (
    34  	defaultKeyFunc = func(claim *MapClaims) ([]byte, error) { return []byte("HelloSecret"), nil }
    35  	emptyKeyFunc   = func(claim *MapClaims) ([]byte, error) { return nil, nil }
    36  	errorKeyFunc   = func(claim *MapClaims) ([]byte, error) { return nil, fmt.Errorf("error loading key") }
    37  )
    38  
    39  var jwtTestData = []struct {
    40  	name        string
    41  	tokenString string
    42  	keyfunc     func(*MapClaims) ([]byte, error)
    43  	claims      jwt.Claims
    44  	valid       bool
    45  	errors      int32
    46  }{
    47  	{
    48  		"basic",
    49  		"",
    50  		defaultKeyFunc,
    51  		&MapClaims{
    52  			MapClaims: jwt.MapClaims{
    53  				"foo": "bar",
    54  			},
    55  		},
    56  		true,
    57  		0,
    58  	},
    59  	{
    60  		"basic expired",
    61  		"", // autogen
    62  		defaultKeyFunc,
    63  		&MapClaims{
    64  			MapClaims: jwt.MapClaims{
    65  				"foo": "bar",
    66  				"exp": float64(time.Now().Unix() - 100),
    67  			},
    68  		},
    69  		false,
    70  		-1,
    71  	},
    72  	{
    73  		"basic nbf",
    74  		"", // autogen
    75  		defaultKeyFunc,
    76  		&MapClaims{
    77  			MapClaims: jwt.MapClaims{
    78  				"foo": "bar",
    79  				"nbf": float64(time.Now().Unix() + 100),
    80  			},
    81  		},
    82  		false,
    83  		-1,
    84  	},
    85  	{
    86  		"expired and nbf",
    87  		"", // autogen
    88  		defaultKeyFunc,
    89  		&MapClaims{
    90  			MapClaims: jwt.MapClaims{
    91  				"foo": "bar",
    92  				"nbf": float64(time.Now().Unix() + 100),
    93  				"exp": float64(time.Now().Unix() - 100),
    94  			},
    95  		},
    96  		false,
    97  		-1,
    98  	},
    99  	{
   100  		"basic invalid",
   101  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
   102  		defaultKeyFunc,
   103  		&MapClaims{
   104  			MapClaims: jwt.MapClaims{
   105  				"foo": "bar",
   106  			},
   107  		},
   108  		false,
   109  		-1,
   110  	},
   111  	{
   112  		"basic nokeyfunc",
   113  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
   114  		nil,
   115  		&MapClaims{
   116  			MapClaims: jwt.MapClaims{
   117  				"foo": "bar",
   118  			},
   119  		},
   120  		false,
   121  		-1,
   122  	},
   123  	{
   124  		"basic nokey",
   125  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
   126  		emptyKeyFunc,
   127  		&MapClaims{
   128  			MapClaims: jwt.MapClaims{
   129  				"foo": "bar",
   130  			},
   131  		},
   132  		false,
   133  		-1,
   134  	},
   135  	{
   136  		"basic errorkey",
   137  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
   138  		errorKeyFunc,
   139  		&MapClaims{
   140  			MapClaims: jwt.MapClaims{
   141  				"foo": "bar",
   142  			},
   143  		},
   144  		false,
   145  		-1,
   146  	},
   147  	{
   148  		"Standard Claims",
   149  		"",
   150  		defaultKeyFunc,
   151  		&StandardClaims{
   152  			StandardClaims: jwt.StandardClaims{
   153  				ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
   154  			},
   155  		},
   156  		true,
   157  		0,
   158  	},
   159  }
   160  
   161  func mapClaimsToken(claims *MapClaims) string {
   162  	claims.SetAccessKey("test")
   163  	j := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
   164  	tk, _ := j.SignedString([]byte("HelloSecret"))
   165  	return tk
   166  }
   167  
   168  func standardClaimsToken(claims *StandardClaims) string {
   169  	claims.AccessKey = "test"
   170  	claims.Subject = "test"
   171  	j := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
   172  	tk, _ := j.SignedString([]byte("HelloSecret"))
   173  	return tk
   174  }
   175  
   176  func TestParserParse(t *testing.T) {
   177  	// Iterate over test data set and run tests
   178  	for _, data := range jwtTestData {
   179  		data := data
   180  		t.Run(data.name, func(t *testing.T) {
   181  			// Parse the token
   182  			var err error
   183  
   184  			// Figure out correct claims type
   185  			switch claims := data.claims.(type) {
   186  			case *MapClaims:
   187  				if data.tokenString == "" {
   188  					data.tokenString = mapClaimsToken(claims)
   189  				}
   190  				err = ParseWithClaims(data.tokenString, &MapClaims{}, data.keyfunc)
   191  			case *StandardClaims:
   192  				if data.tokenString == "" {
   193  					data.tokenString = standardClaimsToken(claims)
   194  				}
   195  				err = ParseWithStandardClaims(data.tokenString, &StandardClaims{}, []byte("HelloSecret"))
   196  			}
   197  
   198  			if data.valid && err != nil {
   199  				t.Errorf("Error while verifying token: %T:%v", err, err)
   200  			}
   201  
   202  			if !data.valid && err == nil {
   203  				t.Errorf("Invalid token passed validation")
   204  			}
   205  
   206  			if data.errors != 0 {
   207  				_, ok := err.(*jwt.ValidationError)
   208  				if !ok {
   209  					t.Errorf("Expected *jwt.ValidationError, but got %#v instead", err)
   210  				}
   211  			}
   212  		})
   213  	}
   214  }