From 08b2b9621b54e1db56823f1bc383a67d792cb6cd Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Fri, 29 Oct 2021 14:30:08 -0700 Subject: [PATCH 01/10] Revert Encoding/Decoding changes for better compatibility --- token.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/token.go b/token.go index 4c93e7aa..d8c10e06 100644 --- a/token.go +++ b/token.go @@ -104,7 +104,7 @@ func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func EncodeSegment(seg []byte) string { - return base64.RawURLEncoding.EncodeToString(seg) + return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") } // DecodeSegment decodes a JWT specific base64url encoding with padding stripped @@ -112,5 +112,9 @@ func EncodeSegment(seg []byte) string { // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func DecodeSegment(seg string) ([]byte, error) { - return base64.RawURLEncoding.DecodeString(seg) + if l := len(seg) % 4; l > 0 { + seg += strings.Repeat("=", 4-l) + } + + return base64.URLEncoding.DecodeString(seg) } From 58386171502ba911b6d71cddf424ceca03fa4054 Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Sat, 30 Oct 2021 18:31:26 -0700 Subject: [PATCH 02/10] Revert encoding changes and keep decoding --- token.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/token.go b/token.go index d8c10e06..a5e25904 100644 --- a/token.go +++ b/token.go @@ -104,7 +104,7 @@ func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func EncodeSegment(seg []byte) string { - return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") + return strings.TrimRight(base64.RawURLEncoding.EncodeToString(seg), "=") } // DecodeSegment decodes a JWT specific base64url encoding with padding stripped From d7f2c4640b616f1e3a0193284e94d6667511c420 Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Sat, 30 Oct 2021 19:15:06 -0700 Subject: [PATCH 03/10] Update Decode Segment and add test case to parser --- parser_test.go | 10 ++++++++++ token.go | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/parser_test.go b/parser_test.go index 6d1b7c71..599d25dd 100644 --- a/parser_test.go +++ b/parser_test.go @@ -57,6 +57,16 @@ var jwtTestData = []struct { nil, jwt.SigningMethodRS256, }, + { + "basic with padding", + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==", + defaultKeyFunc, + jwt.MapClaims{"foo": "paddedbar"}, + true, + 0, + nil, + jwt.SigningMethodRS256, + }, { "basic expired", "", // autogen diff --git a/token.go b/token.go index a5e25904..35a21652 100644 --- a/token.go +++ b/token.go @@ -104,7 +104,7 @@ func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func EncodeSegment(seg []byte) string { - return strings.TrimRight(base64.RawURLEncoding.EncodeToString(seg), "=") + return base64.RawURLEncoding.EncodeToString(seg) } // DecodeSegment decodes a JWT specific base64url encoding with padding stripped @@ -112,9 +112,9 @@ func EncodeSegment(seg []byte) string { // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func DecodeSegment(seg string) ([]byte, error) { - if l := len(seg) % 4; l > 0 { - seg += strings.Repeat("=", 4-l) + if strings.Contains(seg, "=") { + return base64.URLEncoding.DecodeString(seg) } - return base64.URLEncoding.DecodeString(seg) + return base64.RawURLEncoding.DecodeString(seg) } From 25379bc310c9269859ce193e9329344d563335bd Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Sun, 31 Oct 2021 10:20:36 -0700 Subject: [PATCH 04/10] Switching to utilizing global var --- parser_test.go | 93 ++++++++++++++++++++++++++++++++++++++++++++------ token.go | 26 +++++++++++++- 2 files changed, 108 insertions(+), 11 deletions(-) diff --git a/parser_test.go b/parser_test.go index 599d25dd..4b520f5c 100644 --- a/parser_test.go +++ b/parser_test.go @@ -57,16 +57,6 @@ var jwtTestData = []struct { nil, jwt.SigningMethodRS256, }, - { - "basic with padding", - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJwYWRkZWRiYXIifQ==.20kGGJaYekGTRFf8b0TwhuETcR8lv5z2363X5jf7G1yTWVTwOmte5Ii8L8_OQbYwPoiVHmZY6iJPbt_DhCN42AeFY74BcsUhR-BVrYUVhKK0RppuzEcSlILDNeQsJDLEL035CPm1VO6Jrgk7enQPIctVxUesRgswP71OpGvJxy3j1k_J8p0WzZvRZTe1D_2Misa0UDGwnEIHhmr97fIpMSZjFxlcygQw8QN34IHLHIXMaTY1eiCf4CCr6rOS9wUeu7P3CPkmFq9XhxBT_LLCmIMhHnxP5x27FUJE_JZlfek0MmARcrhpsZS2sFhHAiWrjxjOE27jkDtv1nEwn65wMw==", - defaultKeyFunc, - jwt.MapClaims{"foo": "paddedbar"}, - true, - 0, - nil, - jwt.SigningMethodRS256, - }, { "basic expired", "", // autogen @@ -445,6 +435,89 @@ func TestParser_ParseUnverified(t *testing.T) { } } +var setPaddingTestData = []struct { + name string + tokenString string + claims jwt.Claims + paddedDecode uint64 + signingMethod jwt.SigningMethod + keyfunc jwt.Keyfunc + valid bool +}{ + { + name: "Validated non-padded token with padding disabled", + tokenString: "", + claims: jwt.MapClaims{"foo": "paddedbar"}, + paddedDecode: jwt.DisablePadding, + signingMethod: jwt.SigningMethodRS256, + keyfunc: defaultKeyFunc, + valid: true, + }, + { + name: "Validated non-padded token with padding enabled", + tokenString: "", + claims: jwt.MapClaims{"foo": "paddedbar"}, + paddedDecode: jwt.AllowPadding, + 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: jwt.DisablePadding, + 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: jwt.AllowPadding, + signingMethod: jwt.SigningMethodRS256, + keyfunc: defaultKeyFunc, + valid: true, + }, +} + +// 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) { + + // If the token string is blank, use helper function to generate string + jwt.SetDecodePadding(data.paddedDecode) + + if data.tokenString == "" { + data.tokenString = signToken(data.claims, data.signingMethod) + + } + fmt.Println(data.tokenString) + + // Parse the token + var token *jwt.Token + var err error + parser := new(jwt.Parser) + + // 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.SetDecodePadding(jwt.DisablePadding) + + } +} + func BenchmarkParseUnverified(b *testing.B) { // Iterate over test data set and run tests diff --git a/token.go b/token.go index 35a21652..fd343478 100644 --- a/token.go +++ b/token.go @@ -4,9 +4,30 @@ import ( "encoding/base64" "encoding/json" "strings" + "sync/atomic" "time" ) +const ( + DisablePadding uint64 = 0 // Utilizes RawURLEncoding + AllowPadding uint64 = 1 // Utilizes URLEncoding + +) + +var decodePaddingAllowed uint64 + +// SetDecodePadding will switch the codec used for encoding/decoding JWTs respectively. Note that the JWS RFC7515 +// states that the tokens will utilize a Base64url encoding with no padding. Unfortuneately, some implementations +// of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global +// variable, and updating it will change the behavior on a package level. +func SetDecodePadding(setPadding uint64) { + atomic.SwapUint64(&decodePaddingAllowed, setPadding) +} + +func init() { + SetDecodePadding(DisablePadding) +} + // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). // You can override it to use another time value. This is useful for testing or if your // server uses a different time zone than your tokens. @@ -112,7 +133,10 @@ func EncodeSegment(seg []byte) string { // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func DecodeSegment(seg string) ([]byte, error) { - if strings.Contains(seg, "=") { + if atomic.LoadUint64(&decodePaddingAllowed) == AllowPadding { + if l := len(seg) % 4; l > 0 { + seg += strings.Repeat("=", 4-l) + } return base64.URLEncoding.DecodeString(seg) } From edf4019278ffa9ce90438a7bbb0b16a3b90ab9f6 Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Sun, 31 Oct 2021 11:49:41 -0700 Subject: [PATCH 05/10] Small changes --- parser_test.go | 1 - token.go | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/parser_test.go b/parser_test.go index 4b520f5c..4bdcbc8d 100644 --- a/parser_test.go +++ b/parser_test.go @@ -494,7 +494,6 @@ func TestSetPadding(t *testing.T) { data.tokenString = signToken(data.claims, data.signingMethod) } - fmt.Println(data.tokenString) // Parse the token var token *jwt.Token diff --git a/token.go b/token.go index fd343478..fbbcd059 100644 --- a/token.go +++ b/token.go @@ -17,17 +17,13 @@ const ( var decodePaddingAllowed uint64 // SetDecodePadding will switch the codec used for encoding/decoding JWTs respectively. Note that the JWS RFC7515 -// states that the tokens will utilize a Base64url encoding with no padding. Unfortuneately, some implementations +// states that the tokens will utilize a Base64url encoding with no padding. Unfortunately, some implementations // of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global // variable, and updating it will change the behavior on a package level. func SetDecodePadding(setPadding uint64) { atomic.SwapUint64(&decodePaddingAllowed, setPadding) } -func init() { - SetDecodePadding(DisablePadding) -} - // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). // You can override it to use another time value. This is useful for testing or if your // server uses a different time zone than your tokens. From 7cc0ea7d0d1691d5e4c923b4e6c3d2577ef7bab5 Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Sun, 31 Oct 2021 11:53:16 -0700 Subject: [PATCH 06/10] Revert atomic changes to utilize boolean --- parser_test.go | 62 +++++++++++++++++++++++++------------------------- token.go | 17 ++++---------- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/parser_test.go b/parser_test.go index 4bdcbc8d..eac45a75 100644 --- a/parser_test.go +++ b/parser_test.go @@ -436,49 +436,49 @@ func TestParser_ParseUnverified(t *testing.T) { } var setPaddingTestData = []struct { - name string - tokenString string - claims jwt.Claims - paddedDecode uint64 + name string + tokenString string + claims jwt.Claims + paddedDecode bool signingMethod jwt.SigningMethod - keyfunc jwt.Keyfunc - valid bool + keyfunc jwt.Keyfunc + valid bool }{ { - name: "Validated non-padded token with padding disabled", - tokenString: "", - claims: jwt.MapClaims{"foo": "paddedbar"}, - paddedDecode: jwt.DisablePadding, + name: "Validated non-padded token with padding disabled", + tokenString: "", + claims: jwt.MapClaims{"foo": "paddedbar"}, + paddedDecode: false, signingMethod: jwt.SigningMethodRS256, - keyfunc: defaultKeyFunc, - valid: true, + keyfunc: defaultKeyFunc, + valid: true, }, { - name: "Validated non-padded token with padding enabled", - tokenString: "", - claims: jwt.MapClaims{"foo": "paddedbar"}, - paddedDecode: jwt.AllowPadding, + name: "Validated non-padded token with padding enabled", + tokenString: "", + claims: jwt.MapClaims{"foo": "paddedbar"}, + paddedDecode: true, signingMethod: jwt.SigningMethodRS256, - keyfunc: defaultKeyFunc, - valid: true, + 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: jwt.DisablePadding, + 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, + 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: jwt.AllowPadding, + 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, + keyfunc: defaultKeyFunc, + valid: true, }, } @@ -512,7 +512,7 @@ func TestSetPadding(t *testing.T) { } }) - jwt.SetDecodePadding(jwt.DisablePadding) + jwt.SetDecodePadding(false) } } diff --git a/token.go b/token.go index fbbcd059..79244c7c 100644 --- a/token.go +++ b/token.go @@ -4,24 +4,17 @@ import ( "encoding/base64" "encoding/json" "strings" - "sync/atomic" "time" ) -const ( - DisablePadding uint64 = 0 // Utilizes RawURLEncoding - AllowPadding uint64 = 1 // Utilizes URLEncoding - -) - -var decodePaddingAllowed uint64 +var decodePaddingAllowed bool // SetDecodePadding will switch the codec used for encoding/decoding JWTs respectively. Note that the JWS RFC7515 // states that the tokens will utilize a Base64url encoding with no padding. Unfortunately, some implementations // of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global -// variable, and updating it will change the behavior on a package level. -func SetDecodePadding(setPadding uint64) { - atomic.SwapUint64(&decodePaddingAllowed, setPadding) +// variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe. +func SetDecodePadding(setPadding bool) { + decodePaddingAllowed = setPadding } // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). @@ -129,7 +122,7 @@ func EncodeSegment(seg []byte) string { // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func DecodeSegment(seg string) ([]byte, error) { - if atomic.LoadUint64(&decodePaddingAllowed) == AllowPadding { + if decodePaddingAllowed { if l := len(seg) % 4; l > 0 { seg += strings.Repeat("=", 4-l) } From f7e4a4fab09bf936effa1121ccfb8b717781c170 Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Sun, 31 Oct 2021 12:02:22 -0700 Subject: [PATCH 07/10] Remove setter and export variable directly --- parser_test.go | 4 ++-- token.go | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/parser_test.go b/parser_test.go index eac45a75..bcd39765 100644 --- a/parser_test.go +++ b/parser_test.go @@ -488,7 +488,7 @@ func TestSetPadding(t *testing.T) { t.Run(data.name, func(t *testing.T) { // If the token string is blank, use helper function to generate string - jwt.SetDecodePadding(data.paddedDecode) + jwt.DecodePaddingAllowed = data.paddedDecode if data.tokenString == "" { data.tokenString = signToken(data.claims, data.signingMethod) @@ -512,7 +512,7 @@ func TestSetPadding(t *testing.T) { } }) - jwt.SetDecodePadding(false) + jwt.DecodePaddingAllowed = false } } diff --git a/token.go b/token.go index 79244c7c..791a636c 100644 --- a/token.go +++ b/token.go @@ -7,15 +7,13 @@ import ( "time" ) -var decodePaddingAllowed bool -// SetDecodePadding will switch the codec used for encoding/decoding JWTs respectively. Note that the JWS RFC7515 +// DecodePaddingAllowed will switch the codec used for encoding/decoding JWTs respectively. Note that the JWS RFC7515 // states that the tokens will utilize a Base64url encoding with no padding. Unfortunately, some implementations // of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global // variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe. -func SetDecodePadding(setPadding bool) { - decodePaddingAllowed = setPadding -} +// To use the non-recommended decoding, set this boolean to `true` prior to using this package. +var DecodePaddingAllowed bool // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). // You can override it to use another time value. This is useful for testing or if your @@ -122,7 +120,7 @@ func EncodeSegment(seg []byte) string { // Deprecated: In a future release, we will demote this function to a non-exported function, since it // should only be used internally func DecodeSegment(seg string) ([]byte, error) { - if decodePaddingAllowed { + if DecodePaddingAllowed { if l := len(seg) % 4; l > 0 { seg += strings.Repeat("=", 4-l) } From e3e7b461619d9f8ad0f99112861e0f5fdc857ee2 Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Wed, 3 Nov 2021 21:28:24 -0700 Subject: [PATCH 08/10] Add example cognito token alongside public key --- parser_test.go | 44 +++++++++++++++++++++++++++------- test/exampleCognito-public.pem | 4 ++++ 2 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 test/exampleCognito-public.pem diff --git a/parser_test.go b/parser_test.go index bcd39765..b3aaabcb 100644 --- a/parser_test.go +++ b/parser_test.go @@ -16,15 +16,17 @@ import ( var errKeyFuncError error = fmt.Errorf("error loading key") var ( - jwtTestDefaultKey *rsa.PublicKey - jwtTestRSAPrivateKey *rsa.PrivateKey - jwtTestEC256PublicKey crypto.PublicKey - jwtTestEC256PrivateKey crypto.PrivateKey - defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil } - ecdsaKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestEC256PublicKey, nil } - 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 + jwtTestDefaultKey *rsa.PublicKey + jwtTestRSAPrivateKey *rsa.PrivateKey + jwtTestEC256PublicKey crypto.PublicKey + jwtTestEC256PrivateKey crypto.PrivateKey + exampleCognitoPublicKey crypto.PublicKey + defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil } + ecdsaKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestEC256PublicKey, nil } + exampleCognitoKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return exampleCognitoPublicKey, nil } + 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 ) func init() { @@ -32,9 +34,14 @@ func init() { jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub") jwtTestEC256PublicKey = test.LoadECPublicKeyFromDisk("test/ec256-public.pem") + // Load cognito public key - note there is only a public key for this key pair and should only be used for the + // two test cases below. + exampleCognitoPublicKey = test.LoadECPublicKeyFromDisk("test/exampleCognito-public.pem") + // Load private keys jwtTestRSAPrivateKey = test.LoadRSAPrivateKeyFromDisk("test/sample_key") jwtTestEC256PrivateKey = test.LoadECPrivateKeyFromDisk("test/ec256-private.pem") + } var jwtTestData = []struct { @@ -480,6 +487,24 @@ var setPaddingTestData = []struct { keyfunc: defaultKeyFunc, valid: true, }, + { + name: "Error for padded cognito token with padding disabled", + tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==", + claims: nil, + paddedDecode: false, + signingMethod: jwt.SigningMethodES256, + keyfunc: exampleCognitoKeyFunc, + valid: false, + }, + { + name: "Validated padded cognito token with padding enabled", + tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==", + claims: nil, + paddedDecode: true, + signingMethod: jwt.SigningMethodES256, + keyfunc: exampleCognitoKeyFunc, + valid: true, + }, } // Extension of Parsing, this is to test out functionality specific to switching codecs with padding. @@ -499,6 +524,7 @@ func TestSetPadding(t *testing.T) { var token *jwt.Token var err error parser := new(jwt.Parser) + parser.SkipClaimsValidation = true // Figure out correct claims type token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc) diff --git a/test/exampleCognito-public.pem b/test/exampleCognito-public.pem new file mode 100644 index 00000000..cb84e6c8 --- /dev/null +++ b/test/exampleCognito-public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIcaUjXhC7Mn2OonyfHF+zjblKkns +4GLbILnHrZr+aQwddiff5urCDAZ177t81Mn39CDs3uhlNDxfRIRheGnK/Q== +-----END PUBLIC KEY----- \ No newline at end of file From 9eac92d5be1e10ceda4f4d7a942b3067f5ce53bb Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Thu, 4 Nov 2021 10:11:54 -0700 Subject: [PATCH 09/10] Update names --- parser_test.go | 32 ++++++++++++++++---------------- token.go | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/parser_test.go b/parser_test.go index b3aaabcb..4f719a4e 100644 --- a/parser_test.go +++ b/parser_test.go @@ -16,17 +16,17 @@ import ( var errKeyFuncError error = fmt.Errorf("error loading key") var ( - jwtTestDefaultKey *rsa.PublicKey - jwtTestRSAPrivateKey *rsa.PrivateKey - jwtTestEC256PublicKey crypto.PublicKey - jwtTestEC256PrivateKey crypto.PrivateKey - exampleCognitoPublicKey crypto.PublicKey - defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil } - ecdsaKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestEC256PublicKey, nil } - exampleCognitoKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return exampleCognitoPublicKey, nil } - 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 + jwtTestDefaultKey *rsa.PublicKey + jwtTestRSAPrivateKey *rsa.PrivateKey + jwtTestEC256PublicKey crypto.PublicKey + jwtTestEC256PrivateKey crypto.PrivateKey + paddedKey crypto.PublicKey + defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil } + ecdsaKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestEC256PublicKey, nil } + paddedKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return paddedKey, nil } + 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 ) func init() { @@ -36,7 +36,7 @@ func init() { // Load cognito public key - note there is only a public key for this key pair and should only be used for the // two test cases below. - exampleCognitoPublicKey = test.LoadECPublicKeyFromDisk("test/exampleCognito-public.pem") + paddedKey = test.LoadECPublicKeyFromDisk("test/exampleCognito-public.pem") // Load private keys jwtTestRSAPrivateKey = test.LoadRSAPrivateKeyFromDisk("test/sample_key") @@ -488,21 +488,21 @@ var setPaddingTestData = []struct { valid: true, }, { - name: "Error for padded cognito token with padding disabled", + name: "Error for example padded token with padding disabled", tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==", claims: nil, paddedDecode: false, signingMethod: jwt.SigningMethodES256, - keyfunc: exampleCognitoKeyFunc, + keyfunc: paddedKeyFunc, valid: false, }, { - name: "Validated padded cognito token with padding enabled", + name: "Validated example padded token with padding enabled", tokenString: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vY29nbml0by1pZHAuZXUtd2VzdC0yLmFtYXpvbmF3cy5jb20vIiwiY2xpZW50IjoiN0xUY29QWnJWNDR6ZVg2WUs5VktBcHZPM3EiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nIiwiZXhwIjoxNjI5NDcwMTAxfQ==.eyJzdWIiOiIxMjM0NTY3OC1hYmNkLTEyMzQtYWJjZC0xMjM0NTY3OGFiY2QiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IjEyMzQ1Njc4LWFiY2QtMTIzNC1hYmNkLTEyMzQ1Njc4YWJjZCIsImV4cCI6MTYyOTQ3MDEwMSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkcC5ldS13ZXN0LTIuYW1hem9uYXdzLmNvbS8ifQ==.sx0muJ754glJvwWgkHaPrOI3L1gaPjRLLUvOQRk0WitnqC5Dtt1knorcbOzlEcH9zwPM2jYYIAYQz_qEyM3grw==", claims: nil, paddedDecode: true, signingMethod: jwt.SigningMethodES256, - keyfunc: exampleCognitoKeyFunc, + keyfunc: paddedKeyFunc, valid: true, }, } diff --git a/token.go b/token.go index 791a636c..12344138 100644 --- a/token.go +++ b/token.go @@ -8,7 +8,7 @@ import ( ) -// DecodePaddingAllowed will switch the codec used for encoding/decoding JWTs respectively. Note that the JWS RFC7515 +// DecodePaddingAllowed will switch the codec used for decoding JWTs respectively. Note that the JWS RFC7515 // states that the tokens will utilize a Base64url encoding with no padding. Unfortunately, some implementations // of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global // variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe. From 03aa267f2548925835821aa380683a1fd9273e81 Mon Sep 17 00:00:00 2001 From: Ara Jermakyan Date: Fri, 5 Nov 2021 17:34:48 -0700 Subject: [PATCH 10/10] More name changes --- parser_test.go | 4 ++-- ...{exampleCognito-public.pem => examplePaddedKey-public.pem} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename test/{exampleCognito-public.pem => examplePaddedKey-public.pem} (100%) diff --git a/parser_test.go b/parser_test.go index 4f719a4e..7a7bf0ab 100644 --- a/parser_test.go +++ b/parser_test.go @@ -34,9 +34,9 @@ func init() { jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub") jwtTestEC256PublicKey = test.LoadECPublicKeyFromDisk("test/ec256-public.pem") - // Load cognito public key - note there is only a public key for this key pair and should only be used for the + // 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/exampleCognito-public.pem") + paddedKey = test.LoadECPublicKeyFromDisk("test/examplePaddedKey-public.pem") // Load private keys jwtTestRSAPrivateKey = test.LoadRSAPrivateKeyFromDisk("test/sample_key") diff --git a/test/exampleCognito-public.pem b/test/examplePaddedKey-public.pem similarity index 100% rename from test/exampleCognito-public.pem rename to test/examplePaddedKey-public.pem