GetExpiresAt() -> GetExpirationTime()

This commit is contained in:
Christian Banse 2022-08-27 13:07:17 +02:00
parent 3098ea8845
commit 1d88540186
5 changed files with 73 additions and 64 deletions

View File

@ -7,66 +7,9 @@ package jwt
// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 namely `exp`, // https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 namely `exp`,
// `iat`, `nbf`, `iss` and `aud`. // `iat`, `nbf`, `iss` and `aud`.
type Claims interface { type Claims interface {
GetExpiryAt() *NumericDate GetExpirationTime() *NumericDate
GetIssuedAt() *NumericDate GetIssuedAt() *NumericDate
GetNotBefore() *NumericDate GetNotBefore() *NumericDate
GetIssuer() string GetIssuer() string
GetAudience() ClaimStrings GetAudience() ClaimStrings
} }
// RegisteredClaims are a structured version of the JWT Claims Set,
// restricted to Registered Claim Names, as referenced at
// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
//
// This type can be used on its own, but then additional private and
// public claims embedded in the JWT will not be parsed. The typical use-case
// therefore is to embedded this in a user-defined claim type.
//
// See examples for how to use this with your own claim types.
type RegisteredClaims struct {
// the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
Issuer string `json:"iss,omitempty"`
// the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
Subject string `json:"sub,omitempty"`
// the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
Audience ClaimStrings `json:"aud,omitempty"`
// the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
ExpiresAt *NumericDate `json:"exp,omitempty"`
// the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
NotBefore *NumericDate `json:"nbf,omitempty"`
// the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
IssuedAt *NumericDate `json:"iat,omitempty"`
// the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
ID string `json:"jti,omitempty"`
}
// GetExpiryAt implements the Claims interface.
func (c RegisteredClaims) GetExpiryAt() *NumericDate {
return c.ExpiresAt
}
// GetNotBefore implements the Claims interface.
func (c RegisteredClaims) GetNotBefore() *NumericDate {
return c.NotBefore
}
// GetIssuedAt implements the Claims interface.
func (c RegisteredClaims) GetIssuedAt() *NumericDate {
return c.IssuedAt
}
// GetAudience implements the Claims interface.
func (c RegisteredClaims) GetAudience() ClaimStrings {
return c.Audience
}
// GetIssuer implements the Claims interface.
func (c RegisteredClaims) GetIssuer() string {
return c.Issuer
}

View File

@ -8,8 +8,8 @@ import (
// This is the default claims type if you don't supply one // This is the default claims type if you don't supply one
type MapClaims map[string]interface{} type MapClaims map[string]interface{}
// GetExpiryAt implements the Claims interface. // GetExpirationTime implements the Claims interface.
func (m MapClaims) GetExpiryAt() *NumericDate { func (m MapClaims) GetExpirationTime() *NumericDate {
return m.ParseNumericDate("exp") return m.ParseNumericDate("exp")
} }
@ -33,6 +33,9 @@ func (m MapClaims) GetIssuer() string {
return m.ParseString("iss") return m.ParseString("iss")
} }
// ParseNumericDate tries to parse a key in the map claims type as a number
// date. This will succeed, if the underlying type is either a [float64] or a
// [json.Number]. Otherwise, nil will be returned.
func (m MapClaims) ParseNumericDate(key string) *NumericDate { func (m MapClaims) ParseNumericDate(key string) *NumericDate {
v, ok := m[key] v, ok := m[key]
if !ok { if !ok {
@ -55,6 +58,8 @@ func (m MapClaims) ParseNumericDate(key string) *NumericDate {
return nil return nil
} }
// ParseClaimsString tries to parse a key in the map claims type as a
// [ClaimsStrings] type, which can either be a string or an array of string.
func (m MapClaims) ParseClaimsString(key string) ClaimStrings { func (m MapClaims) ParseClaimsString(key string) ClaimStrings {
var cs []string var cs []string
switch v := m[key].(type) { switch v := m[key].(type) {
@ -75,6 +80,8 @@ func (m MapClaims) ParseClaimsString(key string) ClaimStrings {
return cs return cs
} }
// ParseString tries to parse a key in the map claims type as a
// [string] type. Otherwise, an empty string is returned.
func (m MapClaims) ParseString(key string) string { func (m MapClaims) ParseString(key string) string {
iss, _ := m[key].(string) iss, _ := m[key].(string)

View File

@ -3,6 +3,7 @@ package jwt_test
import ( import (
"crypto" "crypto"
"crypto/rsa" "crypto/rsa"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
@ -55,7 +56,7 @@ var jwtTestData = []struct {
parser *jwt.Parser parser *jwt.Parser
signingMethod jwt.SigningMethod // The method to sign the JWT token for test purpose signingMethod jwt.SigningMethod // The method to sign the JWT token for test purpose
}{ }{
/*{ {
"basic", "basic",
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
defaultKeyFunc, defaultKeyFunc,
@ -317,7 +318,7 @@ var jwtTestData = []struct {
[]error{jwt.ErrTokenNotValidYet}, []error{jwt.ErrTokenNotValidYet},
jwt.NewParser(jwt.WithValidator(jwt.NewValidator(jwt.WithLeeway(time.Minute)))), jwt.NewParser(jwt.WithValidator(jwt.NewValidator(jwt.WithLeeway(time.Minute)))),
jwt.SigningMethodRS256, jwt.SigningMethodRS256,
},*/ },
{ {
"RFC7519 Claims - nbf with 120s skew", "RFC7519 Claims - nbf with 120s skew",
"", // autogen "", // autogen

58
registered_claims.go Normal file
View File

@ -0,0 +1,58 @@
package jwt
// RegisteredClaims are a structured version of the JWT Claims Set,
// restricted to Registered Claim Names, as referenced at
// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
//
// This type can be used on its own, but then additional private and
// public claims embedded in the JWT will not be parsed. The typical use-case
// therefore is to embedded this in a user-defined claim type.
//
// See examples for how to use this with your own claim types.
type RegisteredClaims struct {
// the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
Issuer string `json:"iss,omitempty"`
// the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
Subject string `json:"sub,omitempty"`
// the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
Audience ClaimStrings `json:"aud,omitempty"`
// the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
ExpiresAt *NumericDate `json:"exp,omitempty"`
// the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
NotBefore *NumericDate `json:"nbf,omitempty"`
// the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
IssuedAt *NumericDate `json:"iat,omitempty"`
// the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
ID string `json:"jti,omitempty"`
}
// GetExpirationTime implements the Claims interface.
func (c RegisteredClaims) GetExpirationTime() *NumericDate {
return c.ExpiresAt
}
// GetNotBefore implements the Claims interface.
func (c RegisteredClaims) GetNotBefore() *NumericDate {
return c.NotBefore
}
// GetIssuedAt implements the Claims interface.
func (c RegisteredClaims) GetIssuedAt() *NumericDate {
return c.IssuedAt
}
// GetAudience implements the Claims interface.
func (c RegisteredClaims) GetAudience() ClaimStrings {
return c.Audience
}
// GetIssuer implements the Claims interface.
func (c RegisteredClaims) GetIssuer() string {
return c.Issuer
}

View File

@ -15,7 +15,7 @@ func (v *Validator) Validate(claims Claims) error {
now := TimeFunc() now := TimeFunc()
if !v.VerifyExpiresAt(claims, now, false) { if !v.VerifyExpiresAt(claims, now, false) {
exp := claims.GetExpiryAt() exp := claims.GetExpirationTime()
delta := now.Sub(exp.Time) delta := now.Sub(exp.Time)
vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta) vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta)
vErr.Errors |= ValidationErrorExpired vErr.Errors |= ValidationErrorExpired
@ -47,7 +47,7 @@ func (v *Validator) VerifyAudience(claims Claims, cmp string, req bool) bool {
// VerifyExpiresAt compares the exp claim against cmp (cmp < exp). // VerifyExpiresAt compares the exp claim against cmp (cmp < exp).
// If req is false, it will return true, if exp is unset. // If req is false, it will return true, if exp is unset.
func (v *Validator) VerifyExpiresAt(claims Claims, cmp time.Time, req bool) bool { func (v *Validator) VerifyExpiresAt(claims Claims, cmp time.Time, req bool) bool {
exp := claims.GetExpiryAt() exp := claims.GetExpirationTime()
if exp == nil { if exp == nil {
return verifyExp(nil, cmp, req, v.leeway) return verifyExp(nil, cmp, req, v.leeway)
} }