...

Source file src/github.com/golang-jwt/jwt/parser_test.go

Documentation: github.com/golang-jwt/jwt

     1  package jwt_test
     2  
     3  import (
     4  	"crypto/rsa"
     5  	"encoding/json"
     6  	"fmt"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/golang-jwt/jwt"
    12  	"github.com/golang-jwt/jwt/test"
    13  )
    14  
    15  var keyFuncError error = fmt.Errorf("error loading key")
    16  
    17  var (
    18  	jwtTestDefaultKey *rsa.PublicKey
    19  	defaultKeyFunc    jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil }
    20  	emptyKeyFunc      jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, nil }
    21  	errorKeyFunc      jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, keyFuncError }
    22  	nilKeyFunc        jwt.Keyfunc = nil
    23  )
    24  
    25  func init() {
    26  	jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub")
    27  }
    28  
    29  var jwtTestData = []struct {
    30  	name        string
    31  	tokenString string
    32  	keyfunc     jwt.Keyfunc
    33  	claims      jwt.Claims
    34  	valid       bool
    35  	errors      uint32
    36  	parser      *jwt.Parser
    37  }{
    38  	{
    39  		"basic",
    40  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
    41  		defaultKeyFunc,
    42  		jwt.MapClaims{"foo": "bar"},
    43  		true,
    44  		0,
    45  		nil,
    46  	},
    47  	{
    48  		"basic expired",
    49  		"", // autogen
    50  		defaultKeyFunc,
    51  		jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)},
    52  		false,
    53  		jwt.ValidationErrorExpired,
    54  		nil,
    55  	},
    56  	{
    57  		"basic nbf",
    58  		"", // autogen
    59  		defaultKeyFunc,
    60  		jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)},
    61  		false,
    62  		jwt.ValidationErrorNotValidYet,
    63  		nil,
    64  	},
    65  	{
    66  		"expired and nbf",
    67  		"", // autogen
    68  		defaultKeyFunc,
    69  		jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)},
    70  		false,
    71  		jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired,
    72  		nil,
    73  	},
    74  	{
    75  		"basic invalid",
    76  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
    77  		defaultKeyFunc,
    78  		jwt.MapClaims{"foo": "bar"},
    79  		false,
    80  		jwt.ValidationErrorSignatureInvalid,
    81  		nil,
    82  	},
    83  	{
    84  		"basic nokeyfunc",
    85  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
    86  		nilKeyFunc,
    87  		jwt.MapClaims{"foo": "bar"},
    88  		false,
    89  		jwt.ValidationErrorUnverifiable,
    90  		nil,
    91  	},
    92  	{
    93  		"basic nokey",
    94  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
    95  		emptyKeyFunc,
    96  		jwt.MapClaims{"foo": "bar"},
    97  		false,
    98  		jwt.ValidationErrorSignatureInvalid,
    99  		nil,
   100  	},
   101  	{
   102  		"basic errorkey",
   103  		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
   104  		errorKeyFunc,
   105  		jwt.MapClaims{"foo": "bar"},
   106  		false,
   107  		jwt.ValidationErrorUnverifiable,
   108  		nil,
   109  	},
   110  	{
   111  		"invalid signing method",
   112  		"",
   113  		defaultKeyFunc,
   114  		jwt.MapClaims{"foo": "bar"},
   115  		false,
   116  		jwt.ValidationErrorSignatureInvalid,
   117  		&jwt.Parser{ValidMethods: []string{"HS256"}},
   118  	},
   119  	{
   120  		"valid signing method",
   121  		"",
   122  		defaultKeyFunc,
   123  		jwt.MapClaims{"foo": "bar"},
   124  		true,
   125  		0,
   126  		&jwt.Parser{ValidMethods: []string{"RS256", "HS256"}},
   127  	},
   128  	{
   129  		"JSON Number",
   130  		"",
   131  		defaultKeyFunc,
   132  		jwt.MapClaims{"foo": json.Number("123.4")},
   133  		true,
   134  		0,
   135  		&jwt.Parser{UseJSONNumber: true},
   136  	},
   137  	{
   138  		"Standard Claims",
   139  		"",
   140  		defaultKeyFunc,
   141  		&jwt.StandardClaims{
   142  			ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
   143  		},
   144  		true,
   145  		0,
   146  		&jwt.Parser{UseJSONNumber: true},
   147  	},
   148  	{
   149  		"JSON Number - basic expired",
   150  		"", // autogen
   151  		defaultKeyFunc,
   152  		jwt.MapClaims{"foo": "bar", "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
   153  		false,
   154  		jwt.ValidationErrorExpired,
   155  		&jwt.Parser{UseJSONNumber: true},
   156  	},
   157  	{
   158  		"JSON Number - basic nbf",
   159  		"", // autogen
   160  		defaultKeyFunc,
   161  		jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
   162  		false,
   163  		jwt.ValidationErrorNotValidYet,
   164  		&jwt.Parser{UseJSONNumber: true},
   165  	},
   166  	{
   167  		"JSON Number - expired and nbf",
   168  		"", // autogen
   169  		defaultKeyFunc,
   170  		jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100)), "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
   171  		false,
   172  		jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired,
   173  		&jwt.Parser{UseJSONNumber: true},
   174  	},
   175  	{
   176  		"SkipClaimsValidation during token parsing",
   177  		"", // autogen
   178  		defaultKeyFunc,
   179  		jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
   180  		true,
   181  		0,
   182  		&jwt.Parser{UseJSONNumber: true, SkipClaimsValidation: true},
   183  	},
   184  }
   185  
   186  func TestParser_Parse(t *testing.T) {
   187  	privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key")
   188  
   189  	// Iterate over test data set and run tests
   190  	for _, data := range jwtTestData {
   191  		// If the token string is blank, use helper function to generate string
   192  		if data.tokenString == "" {
   193  			data.tokenString = test.MakeSampleToken(data.claims, privateKey)
   194  		}
   195  
   196  		// Parse the token
   197  		var token *jwt.Token
   198  		var err error
   199  		var parser = data.parser
   200  		if parser == nil {
   201  			parser = new(jwt.Parser)
   202  		}
   203  		// Figure out correct claims type
   204  		switch data.claims.(type) {
   205  		case jwt.MapClaims:
   206  			token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
   207  		case *jwt.StandardClaims:
   208  			token, err = parser.ParseWithClaims(data.tokenString, &jwt.StandardClaims{}, data.keyfunc)
   209  		}
   210  
   211  		// Verify result matches expectation
   212  		if !reflect.DeepEqual(data.claims, token.Claims) {
   213  			t.Errorf("[%v] Claims mismatch. Expecting: %v  Got: %v", data.name, data.claims, token.Claims)
   214  		}
   215  
   216  		if data.valid && err != nil {
   217  			t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
   218  		}
   219  
   220  		if !data.valid && err == nil {
   221  			t.Errorf("[%v] Invalid token passed validation", data.name)
   222  		}
   223  
   224  		if (err == nil && !token.Valid) || (err != nil && token.Valid) {
   225  			t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name)
   226  		}
   227  
   228  		if data.errors != 0 {
   229  			if err == nil {
   230  				t.Errorf("[%v] Expecting error.  Didn't get one.", data.name)
   231  			} else {
   232  
   233  				ve := err.(*jwt.ValidationError)
   234  				// compare the bitfield part of the error
   235  				if e := ve.Errors; e != data.errors {
   236  					t.Errorf("[%v] Errors don't match expectation.  %v != %v", data.name, e, data.errors)
   237  				}
   238  
   239  				if err.Error() == keyFuncError.Error() && ve.Inner != keyFuncError {
   240  					t.Errorf("[%v] Inner error does not match expectation.  %v != %v", data.name, ve.Inner, keyFuncError)
   241  				}
   242  			}
   243  		}
   244  		if data.valid && token.Signature == "" {
   245  			t.Errorf("[%v] Signature is left unpopulated after parsing", data.name)
   246  		}
   247  	}
   248  }
   249  
   250  func TestParser_ParseUnverified(t *testing.T) {
   251  	privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key")
   252  
   253  	// Iterate over test data set and run tests
   254  	for _, data := range jwtTestData {
   255  		// If the token string is blank, use helper function to generate string
   256  		if data.tokenString == "" {
   257  			data.tokenString = test.MakeSampleToken(data.claims, privateKey)
   258  		}
   259  
   260  		// Parse the token
   261  		var token *jwt.Token
   262  		var err error
   263  		var parser = data.parser
   264  		if parser == nil {
   265  			parser = new(jwt.Parser)
   266  		}
   267  		// Figure out correct claims type
   268  		switch data.claims.(type) {
   269  		case jwt.MapClaims:
   270  			token, _, err = parser.ParseUnverified(data.tokenString, jwt.MapClaims{})
   271  		case *jwt.StandardClaims:
   272  			token, _, err = parser.ParseUnverified(data.tokenString, &jwt.StandardClaims{})
   273  		}
   274  
   275  		if err != nil {
   276  			t.Errorf("[%v] Invalid token", data.name)
   277  		}
   278  
   279  		// Verify result matches expectation
   280  		if !reflect.DeepEqual(data.claims, token.Claims) {
   281  			t.Errorf("[%v] Claims mismatch. Expecting: %v  Got: %v", data.name, data.claims, token.Claims)
   282  		}
   283  
   284  		if data.valid && err != nil {
   285  			t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
   286  		}
   287  	}
   288  }
   289  
   290  // Helper method for benchmarking various methods
   291  func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key interface{}) {
   292  	t := jwt.New(method)
   293  	b.ReportAllocs()
   294  	b.ResetTimer()
   295  	b.RunParallel(func(pb *testing.PB) {
   296  		for pb.Next() {
   297  			if _, err := t.SignedString(key); err != nil {
   298  				b.Fatal(err)
   299  			}
   300  		}
   301  	})
   302  
   303  }
   304  

View as plain text