Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert Encoding/Decoding changes for better compatibility #117

Merged
merged 10 commits into from Nov 6, 2021
83 changes: 83 additions & 0 deletions parser_test.go
Expand Up @@ -435,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
Expand Down
28 changes: 28 additions & 0 deletions token.go
Expand Up @@ -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
ajermaky marked this conversation as resolved.
Show resolved Hide resolved
// 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)
ajermaky marked this conversation as resolved.
Show resolved Hide resolved
}

// 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.
Expand Down Expand Up @@ -112,5 +133,12 @@ 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 l := len(seg) % 4; l > 0 {
seg += strings.Repeat("=", 4-l)
}
return base64.URLEncoding.DecodeString(seg)
}

return base64.RawURLEncoding.DecodeString(seg)
}