2014-12-28 23:24:41 +03:00
|
|
|
package jwt_test
|
2012-04-18 03:49:21 +04:00
|
|
|
|
|
|
|
import (
|
2021-09-24 22:32:29 +03:00
|
|
|
"crypto"
|
2015-07-20 20:23:11 +03:00
|
|
|
"crypto/rsa"
|
2015-11-03 02:22:08 +03:00
|
|
|
"encoding/json"
|
2022-01-20 00:55:19 +03:00
|
|
|
"errors"
|
2012-04-18 23:35:16 +04:00
|
|
|
"fmt"
|
2012-04-18 23:59:37 +04:00
|
|
|
"reflect"
|
|
|
|
"testing"
|
2014-03-08 02:43:11 +04:00
|
|
|
"time"
|
2015-07-17 20:28:08 +03:00
|
|
|
|
2022-08-27 12:36:37 +03:00
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
"github.com/golang-jwt/jwt/v5/test"
|
2012-04-18 03:49:21 +04:00
|
|
|
)
|
|
|
|
|
2021-08-03 16:51:01 +03:00
|
|
|
var errKeyFuncError error = fmt.Errorf("error loading key")
|
2015-12-31 18:48:39 +03:00
|
|
|
|
2014-10-12 00:54:16 +04:00
|
|
|
var (
|
2021-09-24 22:32:29 +03:00
|
|
|
jwtTestDefaultKey *rsa.PublicKey
|
|
|
|
jwtTestRSAPrivateKey *rsa.PrivateKey
|
|
|
|
jwtTestEC256PublicKey crypto.PublicKey
|
|
|
|
jwtTestEC256PrivateKey crypto.PrivateKey
|
2021-11-06 14:21:20 +03:00
|
|
|
paddedKey crypto.PublicKey
|
2021-09-24 22:32:29 +03:00
|
|
|
defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil }
|
|
|
|
ecdsaKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestEC256PublicKey, nil }
|
2021-11-06 14:21:20 +03:00
|
|
|
paddedKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return paddedKey, nil }
|
2021-09-24 22:32:29 +03:00
|
|
|
emptyKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, nil }
|
|
|
|
errorKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, errKeyFuncError }
|
|
|
|
nilKeyFunc jwt.Keyfunc = nil
|
2014-10-12 00:54:16 +04:00
|
|
|
)
|
|
|
|
|
2016-04-08 23:01:55 +03:00
|
|
|
func init() {
|
2021-09-24 22:32:29 +03:00
|
|
|
// Load public keys
|
2016-04-08 23:01:55 +03:00
|
|
|
jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub")
|
2021-09-24 22:32:29 +03:00
|
|
|
jwtTestEC256PublicKey = test.LoadECPublicKeyFromDisk("test/ec256-public.pem")
|
|
|
|
|
2021-11-06 14:21:20 +03:00
|
|
|
// Load padded public key - note there is only a public key for this key pair and should only be used for the
|
|
|
|
// two test cases below.
|
|
|
|
paddedKey = test.LoadECPublicKeyFromDisk("test/examplePaddedKey-public.pem")
|
|
|
|
|
2021-09-24 22:32:29 +03:00
|
|
|
// Load private keys
|
|
|
|
jwtTestRSAPrivateKey = test.LoadRSAPrivateKeyFromDisk("test/sample_key")
|
|
|
|
jwtTestEC256PrivateKey = test.LoadECPrivateKeyFromDisk("test/ec256-private.pem")
|
2021-11-06 14:21:20 +03:00
|
|
|
|
2016-04-08 23:01:55 +03:00
|
|
|
}
|
|
|
|
|
2012-04-18 23:59:37 +04:00
|
|
|
var jwtTestData = []struct {
|
2021-09-24 22:32:29 +03:00
|
|
|
name string
|
|
|
|
tokenString string
|
|
|
|
keyfunc jwt.Keyfunc
|
|
|
|
claims jwt.Claims
|
|
|
|
valid bool
|
2022-01-20 00:55:19 +03:00
|
|
|
err []error
|
2021-09-24 22:32:29 +03:00
|
|
|
parser *jwt.Parser
|
|
|
|
signingMethod jwt.SigningMethod // The method to sign the JWT token for test purpose
|
2012-04-18 23:18:31 +04:00
|
|
|
}{
|
2023-02-21 01:00:46 +03:00
|
|
|
{
|
|
|
|
"invalid JWT",
|
|
|
|
"thisisnotreallyajwt",
|
|
|
|
defaultKeyFunc,
|
|
|
|
nil,
|
|
|
|
false,
|
2023-02-21 10:54:35 +03:00
|
|
|
[]error{jwt.ErrTokenMalformed},
|
|
|
|
nil,
|
|
|
|
jwt.SigningMethodRS256,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"invalid JSON claim",
|
|
|
|
"eyJhbGciOiJSUzI1NiIsInppcCI6IkRFRiJ9.eNqqVkqtKFCyMjQ1s7Q0sbA0MtFRyk3NTUot8kxRslIKLbZQggn4JeamAoUcfRz99HxcXRWeze172tr4bFq7Ui0AAAD__w.jBXD4LT4aq4oXTgDoPkiV6n4QdSZPZI1Z4J8MWQC42aHK0oXwcovEU06dVbtB81TF-2byuu0-qi8J0GUttODT67k6gCl6DV_iuCOV7gczwTcvKslotUvXzoJ2wa0QuujnjxLEE50r0p6k0tsv_9OIFSUZzDksJFYNPlJH2eFG55DROx4TsOz98az37SujZi9GGbTc9SLgzFHPrHMrovRZ5qLC_w4JrdtsLzBBI11OQJgRYwV8fQf4O8IsMkHtetjkN7dKgUkJtRarNWOk76rpTPppLypiLU4_J0-wrElLMh1TzUVZW6Fz2cDHDDBACJgMmKQ2pOFEDK_vYZN74dLCF5GiTZV6DbXhNxO7lqT7JUN4a3p2z96G7WNRjblf2qZeuYdQvkIsiK-rCbSIE836XeY5gaBgkOzuEvzl_tMrpRmb5Oox1ibOfVT2KBh9Lvqsb1XbQjCio2CLE2ViCLqoe0AaRqlUyrk3n8BIG-r0IW4dcw96CEryEMIjsjVp9mtPXamJzf391kt8Rf3iRBqwv3zP7Plg1ResXbmsFUgOflAUPcYmfLug4W3W52ntcUlTHAKXrNfaJL9QQiYAaDukG-ZHDytsOWTuuXw7lVxjt-XYi1VbRAIjh1aIYSELEmEpE4Ny74htQtywYXMQNfJpB0nNn8IiWakgcYYMJ0TmKM",
|
|
|
|
defaultKeyFunc,
|
|
|
|
nil,
|
|
|
|
false,
|
2023-02-21 01:00:46 +03:00
|
|
|
[]error{jwt.ErrTokenMalformed},
|
|
|
|
nil,
|
|
|
|
jwt.SigningMethodRS256,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bearer in JWT",
|
|
|
|
"bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
|
|
defaultKeyFunc,
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
[]error{jwt.ErrTokenMalformed},
|
|
|
|
nil,
|
|
|
|
jwt.SigningMethodRS256,
|
|
|
|
},
|
2012-04-18 23:18:31 +04:00
|
|
|
{
|
2012-04-18 23:35:16 +04:00
|
|
|
"basic",
|
2012-04-18 23:18:31 +04:00
|
|
|
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
2014-10-12 00:54:16 +04:00
|
|
|
defaultKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar"},
|
2012-04-18 23:18:31 +04:00
|
|
|
true,
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2014-03-08 02:43:11 +04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"basic expired",
|
|
|
|
"", // autogen
|
2014-10-12 00:54:16 +04:00
|
|
|
defaultKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)},
|
2014-03-08 02:43:11 +04:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenExpired},
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2014-03-08 02:43:11 +04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"basic nbf",
|
|
|
|
"", // autogen
|
2014-10-12 00:54:16 +04:00
|
|
|
defaultKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)},
|
2014-03-08 02:43:11 +04:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenNotValidYet},
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2014-03-09 23:24:51 +04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"expired and nbf",
|
|
|
|
"", // autogen
|
2014-10-12 00:54:16 +04:00
|
|
|
defaultKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)},
|
2014-03-09 23:24:51 +04:00
|
|
|
false,
|
2023-02-21 10:54:35 +03:00
|
|
|
[]error{jwt.ErrTokenNotValidYet, jwt.ErrTokenExpired},
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2012-04-18 23:18:31 +04:00
|
|
|
},
|
|
|
|
{
|
2012-04-18 23:35:16 +04:00
|
|
|
"basic invalid",
|
2012-04-18 23:18:31 +04:00
|
|
|
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
2014-10-12 00:54:16 +04:00
|
|
|
defaultKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar"},
|
2014-10-12 00:54:16 +04:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenSignatureInvalid, rsa.ErrVerification},
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2014-10-12 00:54:16 +04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"basic nokeyfunc",
|
|
|
|
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
|
|
nilKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar"},
|
2014-10-12 00:54:16 +04:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenUnverifiable},
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2014-10-12 00:54:16 +04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"basic nokey",
|
|
|
|
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
|
|
emptyKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar"},
|
2012-04-18 23:18:31 +04:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenSignatureInvalid},
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2012-04-18 23:18:31 +04:00
|
|
|
},
|
2014-10-12 00:54:16 +04:00
|
|
|
{
|
|
|
|
"basic errorkey",
|
|
|
|
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
|
|
|
|
errorKeyFunc,
|
2015-08-18 20:18:57 +03:00
|
|
|
jwt.MapClaims{"foo": "bar"},
|
2014-10-12 00:54:16 +04:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenUnverifiable, errKeyFuncError},
|
2015-11-03 02:22:08 +03:00
|
|
|
nil,
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2015-11-03 02:22:08 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"invalid signing method",
|
|
|
|
"",
|
|
|
|
defaultKeyFunc,
|
2016-04-13 00:32:24 +03:00
|
|
|
jwt.MapClaims{"foo": "bar"},
|
2015-11-03 02:22:08 +03:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenSignatureInvalid},
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithValidMethods([]string{"HS256"})),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2015-11-03 02:22:08 +03:00
|
|
|
},
|
2015-11-03 02:24:32 +03:00
|
|
|
{
|
2021-09-24 22:32:29 +03:00
|
|
|
"valid RSA signing method",
|
2015-11-03 02:24:32 +03:00
|
|
|
"",
|
|
|
|
defaultKeyFunc,
|
2016-04-13 00:32:24 +03:00
|
|
|
jwt.MapClaims{"foo": "bar"},
|
2015-11-03 02:24:32 +03:00
|
|
|
true,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithValidMethods([]string{"RS256", "HS256"})),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ECDSA signing method not accepted",
|
|
|
|
"",
|
|
|
|
ecdsaKeyFunc,
|
|
|
|
jwt.MapClaims{"foo": "bar"},
|
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenSignatureInvalid},
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithValidMethods([]string{"RS256", "HS256"})),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodES256,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"valid ECDSA signing method",
|
|
|
|
"",
|
|
|
|
ecdsaKeyFunc,
|
|
|
|
jwt.MapClaims{"foo": "bar"},
|
|
|
|
true,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithValidMethods([]string{"HS256", "ES256"})),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodES256,
|
2015-11-03 02:24:32 +03:00
|
|
|
},
|
2015-11-03 02:22:08 +03:00
|
|
|
{
|
|
|
|
"JSON Number",
|
|
|
|
"",
|
|
|
|
defaultKeyFunc,
|
2016-04-13 00:32:24 +03:00
|
|
|
jwt.MapClaims{"foo": json.Number("123.4")},
|
|
|
|
true,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2016-04-13 00:32:24 +03:00
|
|
|
},
|
2016-04-05 00:42:10 +03:00
|
|
|
{
|
|
|
|
"JSON Number - basic expired",
|
|
|
|
"", // autogen
|
|
|
|
defaultKeyFunc,
|
2016-04-13 02:19:20 +03:00
|
|
|
jwt.MapClaims{"foo": "bar", "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
|
2016-04-05 00:42:10 +03:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenExpired},
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2016-04-05 00:42:10 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"JSON Number - basic nbf",
|
|
|
|
"", // autogen
|
|
|
|
defaultKeyFunc,
|
2016-04-13 02:19:20 +03:00
|
|
|
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
|
2016-04-05 00:42:10 +03:00
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenNotValidYet},
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2016-04-05 00:42:10 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"JSON Number - expired and nbf",
|
|
|
|
"", // autogen
|
|
|
|
defaultKeyFunc,
|
2016-04-13 02:19:20 +03:00
|
|
|
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100)), "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))},
|
2016-04-05 00:42:10 +03:00
|
|
|
false,
|
2023-02-21 10:54:35 +03:00
|
|
|
[]error{jwt.ErrTokenNotValidYet, jwt.ErrTokenExpired},
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2016-04-05 00:42:10 +03:00
|
|
|
},
|
2016-06-21 23:11:54 +03:00
|
|
|
{
|
|
|
|
"SkipClaimsValidation during token parsing",
|
|
|
|
"", // autogen
|
|
|
|
defaultKeyFunc,
|
|
|
|
jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))},
|
|
|
|
true,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber(), jwt.WithoutClaimsValidation()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2016-06-21 23:11:54 +03:00
|
|
|
},
|
2021-08-22 20:23:13 +03:00
|
|
|
{
|
|
|
|
"RFC7519 Claims",
|
|
|
|
"",
|
|
|
|
defaultKeyFunc,
|
|
|
|
&jwt.RegisteredClaims{
|
|
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Second * 10)),
|
|
|
|
},
|
|
|
|
true,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2021-08-22 20:23:13 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"RFC7519 Claims - single aud",
|
|
|
|
"",
|
|
|
|
defaultKeyFunc,
|
|
|
|
&jwt.RegisteredClaims{
|
|
|
|
Audience: jwt.ClaimStrings{"test"},
|
|
|
|
},
|
|
|
|
true,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2021-08-22 20:23:13 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"RFC7519 Claims - multiple aud",
|
|
|
|
"",
|
|
|
|
defaultKeyFunc,
|
|
|
|
&jwt.RegisteredClaims{
|
|
|
|
Audience: jwt.ClaimStrings{"test", "test"},
|
|
|
|
},
|
|
|
|
true,
|
2022-01-20 00:55:19 +03:00
|
|
|
nil,
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2021-08-22 20:23:13 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"RFC7519 Claims - single aud with wrong type",
|
|
|
|
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOjF9.8mAIDUfZNQT3TGm1QFIQp91OCpJpQpbB1-m9pA2mkHc", // { "aud": 1 }
|
|
|
|
defaultKeyFunc,
|
|
|
|
&jwt.RegisteredClaims{
|
|
|
|
Audience: nil, // because of the unmarshal error, this will be empty
|
|
|
|
},
|
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenMalformed},
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2021-08-22 20:23:13 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"RFC7519 Claims - multiple aud with wrong types",
|
|
|
|
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdCIsMV19.htEBUf7BVbfSmVoTFjXf3y6DLmDUuLy1vTJ14_EX7Ws", // { "aud": ["test", 1] }
|
|
|
|
defaultKeyFunc,
|
|
|
|
&jwt.RegisteredClaims{
|
|
|
|
Audience: nil, // because of the unmarshal error, this will be empty
|
|
|
|
},
|
|
|
|
false,
|
2022-01-20 00:55:19 +03:00
|
|
|
[]error{jwt.ErrTokenMalformed},
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
jwt.NewParser(jwt.WithJSONNumber()),
|
|
|
|
jwt.SigningMethodRS256,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"RFC7519 Claims - nbf with 60s skew",
|
|
|
|
"", // autogen
|
|
|
|
defaultKeyFunc,
|
|
|
|
&jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second * 100))},
|
|
|
|
false,
|
|
|
|
[]error{jwt.ErrTokenNotValidYet},
|
|
|
|
jwt.NewParser(jwt.WithLeeway(time.Minute)),
|
|
|
|
jwt.SigningMethodRS256,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"RFC7519 Claims - nbf with 120s skew",
|
|
|
|
"", // autogen
|
|
|
|
defaultKeyFunc,
|
|
|
|
&jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second * 100))},
|
|
|
|
true,
|
|
|
|
nil,
|
|
|
|
jwt.NewParser(jwt.WithLeeway(2 * time.Minute)),
|
2021-09-24 22:32:29 +03:00
|
|
|
jwt.SigningMethodRS256,
|
2021-08-22 20:23:13 +03:00
|
|
|
},
|
2014-10-12 00:54:16 +04:00
|
|
|
}
|
|
|
|
|
2021-09-24 22:32:29 +03:00
|
|
|
// signToken creates and returns a signed JWT token using signingMethod.
|
|
|
|
func signToken(claims jwt.Claims, signingMethod jwt.SigningMethod) string {
|
|
|
|
var privateKey interface{}
|
|
|
|
switch signingMethod {
|
|
|
|
case jwt.SigningMethodRS256:
|
|
|
|
privateKey = jwtTestRSAPrivateKey
|
|
|
|
case jwt.SigningMethodES256:
|
|
|
|
privateKey = jwtTestEC256PrivateKey
|
|
|
|
default:
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return test.MakeSampleToken(claims, signingMethod, privateKey)
|
|
|
|
}
|
|
|
|
|
2015-11-03 02:22:08 +03:00
|
|
|
func TestParser_Parse(t *testing.T) {
|
2016-04-08 23:01:55 +03:00
|
|
|
|
2016-04-13 00:32:24 +03:00
|
|
|
// Iterate over test data set and run tests
|
2012-04-18 23:18:31 +04:00
|
|
|
for _, data := range jwtTestData {
|
2021-08-22 20:23:13 +03:00
|
|
|
t.Run(data.name, func(t *testing.T) {
|
2021-09-24 22:32:29 +03:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
// If the token string is blank, use helper function to generate string
|
|
|
|
if data.tokenString == "" {
|
2021-09-24 22:32:29 +03:00
|
|
|
data.tokenString = signToken(data.claims, data.signingMethod)
|
2021-08-22 20:23:13 +03:00
|
|
|
}
|
2015-11-03 02:22:08 +03:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
// Parse the token
|
|
|
|
var token *jwt.Token
|
|
|
|
var err error
|
|
|
|
var parser = data.parser
|
|
|
|
if parser == nil {
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
parser = jwt.NewParser()
|
2021-08-22 20:23:13 +03:00
|
|
|
}
|
|
|
|
// Figure out correct claims type
|
|
|
|
switch data.claims.(type) {
|
|
|
|
case jwt.MapClaims:
|
|
|
|
token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
|
|
|
|
case *jwt.RegisteredClaims:
|
|
|
|
token, err = parser.ParseWithClaims(data.tokenString, &jwt.RegisteredClaims{}, data.keyfunc)
|
2023-02-21 01:00:46 +03:00
|
|
|
case nil:
|
|
|
|
token, err = parser.ParseWithClaims(data.tokenString, nil, data.keyfunc)
|
2021-08-22 20:23:13 +03:00
|
|
|
}
|
2012-04-18 23:59:37 +04:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
// Verify result matches expectation
|
2023-02-21 01:00:46 +03:00
|
|
|
if data.claims != nil && !reflect.DeepEqual(data.claims, token.Claims) {
|
2021-08-22 20:23:13 +03:00
|
|
|
t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
|
|
|
|
}
|
2015-07-17 20:28:08 +03:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
if data.valid && err != nil {
|
|
|
|
t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
|
|
|
|
}
|
2015-07-17 20:28:08 +03:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
if !data.valid && err == nil {
|
|
|
|
t.Errorf("[%v] Invalid token passed validation", data.name)
|
|
|
|
}
|
2015-07-17 20:28:08 +03:00
|
|
|
|
2023-02-21 01:00:46 +03:00
|
|
|
// Since the returned token is nil in the ErrTokenMalformed, we
|
|
|
|
// cannot make the comparison here
|
|
|
|
if !errors.Is(err, jwt.ErrTokenMalformed) &&
|
|
|
|
((err == nil && !token.Valid) || (err != nil && token.Valid)) {
|
2021-08-22 20:23:13 +03:00
|
|
|
t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name)
|
|
|
|
}
|
2016-04-13 00:52:39 +03:00
|
|
|
|
2022-01-20 00:55:19 +03:00
|
|
|
if data.err != nil {
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("[%v] Expecting error(s). Didn't get one.", data.name)
|
|
|
|
} else {
|
|
|
|
var all = false
|
|
|
|
for _, e := range data.err {
|
|
|
|
all = errors.Is(err, e)
|
2021-08-22 20:23:13 +03:00
|
|
|
}
|
2015-12-31 18:48:39 +03:00
|
|
|
|
2022-01-20 00:55:19 +03:00
|
|
|
if !all {
|
|
|
|
t.Errorf("[%v] Errors don't match expectation. %v should contain all of %v", data.name, err, data.err)
|
2021-08-22 20:23:13 +03:00
|
|
|
}
|
2015-12-31 18:48:39 +03:00
|
|
|
}
|
2014-03-08 02:43:11 +04:00
|
|
|
}
|
2022-01-20 00:55:19 +03:00
|
|
|
|
2021-09-24 22:32:29 +03:00
|
|
|
if data.valid {
|
|
|
|
if token.Signature == "" {
|
|
|
|
t.Errorf("[%v] Signature is left unpopulated after parsing", data.name)
|
|
|
|
}
|
|
|
|
if !token.Valid {
|
|
|
|
// The 'Valid' field should be set to true when invoking Parse()
|
|
|
|
t.Errorf("[%v] Token.Valid field mismatch. Expecting true, got %v", data.name, token.Valid)
|
|
|
|
}
|
2021-08-22 20:23:13 +03:00
|
|
|
}
|
|
|
|
})
|
2012-04-18 23:18:31 +04:00
|
|
|
}
|
2012-04-18 03:49:21 +04:00
|
|
|
}
|
2012-04-18 23:35:16 +04:00
|
|
|
|
2016-07-30 14:44:44 +03:00
|
|
|
func TestParser_ParseUnverified(t *testing.T) {
|
|
|
|
|
|
|
|
// Iterate over test data set and run tests
|
|
|
|
for _, data := range jwtTestData {
|
2021-08-22 20:23:13 +03:00
|
|
|
// Skip test data, that intentionally contains malformed tokens, as they would lead to an error
|
2023-02-21 10:54:35 +03:00
|
|
|
if len(data.err) == 1 && errors.Is(data.err[0], jwt.ErrTokenMalformed) {
|
2021-08-22 20:23:13 +03:00
|
|
|
continue
|
2016-07-30 14:44:44 +03:00
|
|
|
}
|
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
t.Run(data.name, func(t *testing.T) {
|
|
|
|
// If the token string is blank, use helper function to generate string
|
|
|
|
if data.tokenString == "" {
|
2021-09-24 22:32:29 +03:00
|
|
|
data.tokenString = signToken(data.claims, data.signingMethod)
|
2021-08-22 20:23:13 +03:00
|
|
|
}
|
2016-07-30 14:44:44 +03:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
// Parse the token
|
|
|
|
var token *jwt.Token
|
|
|
|
var err error
|
|
|
|
var parser = data.parser
|
|
|
|
if parser == nil {
|
|
|
|
parser = new(jwt.Parser)
|
|
|
|
}
|
|
|
|
// Figure out correct claims type
|
|
|
|
switch data.claims.(type) {
|
|
|
|
case jwt.MapClaims:
|
|
|
|
token, _, err = parser.ParseUnverified(data.tokenString, jwt.MapClaims{})
|
|
|
|
case *jwt.RegisteredClaims:
|
|
|
|
token, _, err = parser.ParseUnverified(data.tokenString, &jwt.RegisteredClaims{})
|
|
|
|
}
|
2016-07-30 14:44:44 +03:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("[%v] Invalid token", data.name)
|
|
|
|
}
|
2016-07-30 14:44:44 +03:00
|
|
|
|
2021-08-22 20:23:13 +03:00
|
|
|
// Verify result matches expectation
|
|
|
|
if !reflect.DeepEqual(data.claims, token.Claims) {
|
|
|
|
t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims)
|
|
|
|
}
|
|
|
|
|
|
|
|
if data.valid && err != nil {
|
|
|
|
t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
|
|
|
|
}
|
2021-09-24 22:32:29 +03:00
|
|
|
if token.Valid {
|
|
|
|
// The 'Valid' field should not be set to true when invoking ParseUnverified()
|
|
|
|
t.Errorf("[%v] Token.Valid field mismatch. Expecting false, got %v", data.name, token.Valid)
|
|
|
|
}
|
|
|
|
if token.Signature != "" {
|
|
|
|
// The signature was not validated, hence the 'Signature' field is not populated.
|
|
|
|
t.Errorf("[%v] Token.Signature field mismatch. Expecting '', got %v", data.name, token.Signature)
|
|
|
|
}
|
2021-08-22 20:23:13 +03:00
|
|
|
})
|
2016-07-30 14:44:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-06 14:21:20 +03:00
|
|
|
var setPaddingTestData = []struct {
|
|
|
|
name string
|
|
|
|
tokenString string
|
|
|
|
claims jwt.Claims
|
|
|
|
paddedDecode bool
|
2022-12-09 20:04:03 +03:00
|
|
|
strictDecode bool
|
2021-11-06 14:21:20 +03:00
|
|
|
signingMethod jwt.SigningMethod
|
|
|
|
keyfunc jwt.Keyfunc
|
|
|
|
valid bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Validated non-padded token with padding disabled",
|
|
|
|
tokenString: "",
|
|
|
|
claims: jwt.MapClaims{"foo": "paddedbar"},
|
|
|
|
paddedDecode: false,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Validated non-padded token with padding enabled",
|
|
|
|
tokenString: "",
|
|
|
|
claims: jwt.MapClaims{"foo": "paddedbar"},
|
|
|
|
paddedDecode: true,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Error for padded token with padding disabled",
|
|
|
|
tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==",
|
|
|
|
claims: jwt.MapClaims{"foo": "paddedbar"},
|
|
|
|
paddedDecode: false,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Validated padded token with padding enabled",
|
|
|
|
tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==",
|
|
|
|
claims: jwt.MapClaims{"foo": "paddedbar"},
|
|
|
|
paddedDecode: true,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Error for example padded token with padding disabled",
|
|
|
|
tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: false,
|
|
|
|
signingMethod: jwt.SigningMethodES256,
|
|
|
|
keyfunc: paddedKeyFunc,
|
|
|
|
valid: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Validated example padded token with padding enabled",
|
|
|
|
tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: true,
|
|
|
|
signingMethod: jwt.SigningMethodES256,
|
|
|
|
keyfunc: paddedKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
2022-12-09 20:04:03 +03:00
|
|
|
// DecodeStrict tests, DecodePaddingAllowed=false
|
|
|
|
{
|
|
|
|
name: "Validated non-padded token with padding disabled, non-strict decode, non-tweaked signature",
|
|
|
|
tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
|
|
|
|
"g",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: false,
|
|
|
|
strictDecode: false,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Validated non-padded token with padding disabled, non-strict decode, tweaked signature",
|
|
|
|
tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
|
|
|
|
"h",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: false,
|
|
|
|
strictDecode: false,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Validated non-padded token with padding disabled, strict decode, non-tweaked signature",
|
|
|
|
tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
|
|
|
|
"g",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: false,
|
|
|
|
strictDecode: true,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Error for non-padded token with padding disabled, strict decode, tweaked signature",
|
|
|
|
tokenString: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ.bI15h-7mN0f-2diX5I4ErgNQy1uM-rJS5Sz7O0iTWtWSBxY1h6wy8Ywxe5EZTEO6GiIfk7Lk-72Ex-c5aA40QKhPwWB9BJ8O_LfKpezUVBOn0jRItDnVdsk4ccl2zsOVkbA4U4QvdrSbOYMbwoRHzDXfTFpoeMWtn3ez0aENJ8dh4E1echHp5ByI9Pu2aBsvM1WVcMt_BySweCL3f4T7jNZeXDr7Txd00yUd2gdsHYPjXorOvsgaBKN5GLsWd1zIY5z-2gCC8CRSN-IJ4NNX5ifh7l-bOXE2q7szTqa9pvyE9y6TQJhNMSE2FotRce_TOPBWgGpQ-K2I7E8x7wZ8O" +
|
|
|
|
"h",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: false,
|
|
|
|
strictDecode: true,
|
|
|
|
signingMethod: jwt.SigningMethodRS256,
|
|
|
|
keyfunc: defaultKeyFunc,
|
|
|
|
valid: false,
|
|
|
|
},
|
|
|
|
// DecodeStrict tests, DecodePaddingAllowed=true
|
|
|
|
{
|
|
|
|
name: "Validated padded token with padding enabled, non-strict decode, non-tweaked signature",
|
|
|
|
tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
|
|
|
|
"w==",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: true,
|
|
|
|
strictDecode: false,
|
|
|
|
signingMethod: jwt.SigningMethodES256,
|
|
|
|
keyfunc: paddedKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Validated padded token with padding enabled, non-strict decode, tweaked signature",
|
|
|
|
tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
|
|
|
|
"x==",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: true,
|
|
|
|
strictDecode: false,
|
|
|
|
signingMethod: jwt.SigningMethodES256,
|
|
|
|
keyfunc: paddedKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Validated padded token with padding enabled, strict decode, non-tweaked signature",
|
|
|
|
tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
|
|
|
|
"w==",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: true,
|
|
|
|
strictDecode: true,
|
|
|
|
signingMethod: jwt.SigningMethodES256,
|
|
|
|
keyfunc: paddedKeyFunc,
|
|
|
|
valid: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Error for padded token with padding enabled, strict decode, tweaked signature",
|
|
|
|
tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3gr" +
|
|
|
|
"x==",
|
|
|
|
claims: nil,
|
|
|
|
paddedDecode: true,
|
|
|
|
strictDecode: true,
|
|
|
|
signingMethod: jwt.SigningMethodES256,
|
|
|
|
keyfunc: paddedKeyFunc,
|
|
|
|
valid: false,
|
|
|
|
},
|
2021-11-06 14:21:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Extension of Parsing, this is to test out functionality specific to switching codecs with padding.
|
|
|
|
func TestSetPadding(t *testing.T) {
|
|
|
|
for _, data := range setPaddingTestData {
|
|
|
|
t.Run(data.name, func(t *testing.T) {
|
|
|
|
jwt.DecodePaddingAllowed = data.paddedDecode
|
2022-12-09 20:04:03 +03:00
|
|
|
jwt.DecodeStrict = data.strictDecode
|
2021-11-06 14:21:20 +03:00
|
|
|
|
2022-12-09 20:04:03 +03:00
|
|
|
// If the token string is blank, use helper function to generate string
|
2021-11-06 14:21:20 +03:00
|
|
|
if data.tokenString == "" {
|
|
|
|
data.tokenString = signToken(data.claims, data.signingMethod)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the token
|
|
|
|
var token *jwt.Token
|
|
|
|
var err error
|
New validation API (#236)
* New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
|
2021-11-06 14:21:20 +03:00
|
|
|
|
|
|
|
// Figure out correct claims type
|
|
|
|
token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc)
|
|
|
|
|
|
|
|
if (err == nil) != data.valid || token.Valid != data.valid {
|
|
|
|
t.Errorf("[%v] Error Parsing Token with decoding padding set to %v: %v",
|
|
|
|
data.name,
|
|
|
|
data.paddedDecode,
|
|
|
|
err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
jwt.DecodePaddingAllowed = false
|
2022-12-09 20:04:03 +03:00
|
|
|
jwt.DecodeStrict = false
|
2021-11-06 14:21:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-03 23:57:36 +03:00
|
|
|
func BenchmarkParseUnverified(b *testing.B) {
|
|
|
|
|
|
|
|
// Iterate over test data set and run tests
|
|
|
|
for _, data := range jwtTestData {
|
|
|
|
// If the token string is blank, use helper function to generate string
|
|
|
|
if data.tokenString == "" {
|
2021-09-24 22:32:29 +03:00
|
|
|
data.tokenString = signToken(data.claims, data.signingMethod)
|
2021-08-03 23:57:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the token
|
|
|
|
var parser = data.parser
|
|
|
|
if parser == nil {
|
|
|
|
parser = new(jwt.Parser)
|
|
|
|
}
|
|
|
|
// Figure out correct claims type
|
|
|
|
switch data.claims.(type) {
|
|
|
|
case jwt.MapClaims:
|
|
|
|
b.Run("map_claims", func(b *testing.B) {
|
|
|
|
benchmarkParsing(b, parser, data.tokenString, jwt.MapClaims{})
|
|
|
|
})
|
2022-08-28 19:17:04 +03:00
|
|
|
case *jwt.RegisteredClaims:
|
|
|
|
b.Run("registered_claims", func(b *testing.B) {
|
|
|
|
benchmarkParsing(b, parser, data.tokenString, &jwt.RegisteredClaims{})
|
2021-08-03 23:57:36 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper method for benchmarking various parsing methods
|
|
|
|
func benchmarkParsing(b *testing.B, parser *jwt.Parser, tokenString string, claims jwt.Claims) {
|
|
|
|
b.Helper()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
_, _, err := parser.ParseUnverified(tokenString, jwt.MapClaims{})
|
|
|
|
if err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper method for benchmarking various signing methods
|
2015-04-11 23:53:09 +03:00
|
|
|
func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key interface{}) {
|
2021-08-03 23:57:36 +03:00
|
|
|
b.Helper()
|
2015-04-11 23:53:09 +03:00
|
|
|
t := jwt.New(method)
|
2021-07-13 09:31:42 +03:00
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
2015-04-11 23:53:09 +03:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
2015-04-12 00:04:22 +03:00
|
|
|
if _, err := t.SignedString(key); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
2015-04-11 23:53:09 +03:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|