Skip to content

Commit

Permalink
Fix when JWK url is base64 encoded
Browse files Browse the repository at this point in the history
Added additional check for URL when payload is decoded

Additionally added test helpers for JWK tests
  • Loading branch information
buger committed Jan 12, 2018
1 parent 4649ba6 commit d605cff
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 1 deletion.
51 changes: 51 additions & 0 deletions helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"testing"
"time"

jwt "github.com/dgrijalva/jwt-go"
"github.com/gorilla/websocket"
"github.com/miekg/dns"
"github.com/satori/go.uuid"
Expand Down Expand Up @@ -188,6 +189,56 @@ func createSession(sGen ...func(s *user.SessionState)) string {
return key
}

func createStandardPolicy() *user.Policy {
return &user.Policy{
Rate: 1000.0,
Per: 1.0,
QuotaMax: -1,
QuotaRenewalRate: -1,
AccessRights: map[string]user.AccessDefinition{},
Active: true,
KeyExpiresIn: 60,
}
}

func createPolicy(pGen ...func(p *user.Policy)) string {
pID := keyGen.GenerateAuthKey("")
pol := createStandardPolicy()
pol.ID = pID

if len(pGen) > 0 {
pGen[0](pol)
}

policiesMu.Lock()
policiesByID[pID] = *pol
policiesMu.Unlock()

return pID
}

func createJWKToken(jGen ...func(*jwt.Token)) string {
// Create the token
token := jwt.New(jwt.GetSigningMethod("RS512"))
// Set the token ID

if len(jGen) > 0 {
jGen[0](token)
}

// Sign and get the complete encoded token as a string
signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(jwtRSAPrivKey))
if err != nil {
panic("Couldn't extract private key: " + err.Error())
}
tokenString, err := token.SignedString(signKey)
if err != nil {
panic("Couldn't create JWT token: " + err.Error())
}

return tokenString
}

func firstVals(vals map[string][]string) map[string]string {
m := make(map[string]string, len(vals))
for k, vs := range vals {
Expand Down
12 changes: 11 additions & 1 deletion mw_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ func (k *JWTMiddleware) getSecret(token *jwt.Token) ([]byte, error) {
config := k.Spec.APIDefinition
// Check for central JWT source
if config.JWTSource != "" {

// Is it a URL?
if httpScheme.MatchString(config.JWTSource) {
secret, err := k.getSecretFromURL(config.JWTSource, token.Header["kid"].(string), k.Spec.JWTSigningMethod)
Expand All @@ -137,6 +136,17 @@ func (k *JWTMiddleware) getSecret(token *jwt.Token) ([]byte, error) {
if err != nil {
return nil, err
}

// Is decoded url too?
if httpScheme.MatchString(string(decodedCert)) {
secret, err := k.getSecretFromURL(string(decodedCert), token.Header["kid"].(string), k.Spec.JWTSigningMethod)
if err != nil {
return nil, err
}

return secret, nil
}

return decodedCert, nil
}

Expand Down
46 changes: 46 additions & 0 deletions mw_jwt_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"encoding/base64"
"net/http"
"net/http/httptest"
"net/url"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/dgrijalva/jwt-go"
"github.com/justinas/alice"

"github.com/TykTechnologies/tyk/test"
"github.com/TykTechnologies/tyk/user"
)

Expand Down Expand Up @@ -759,3 +761,47 @@ func TestJWTSessionRSAWithJWK(t *testing.T) {
t.Error("Initial request failed with non-200 code, should have passed!: ", recorder.Code)
}
}

func TestJWTSessionRSAWithEncodedJWK(t *testing.T) {
ts := newTykTestServer()
defer ts.Close()

spec := buildAPI(func(spec *APISpec) {
spec.UseKeylessAccess = false
spec.EnableJWT = true
spec.JWTSigningMethod = "rsa"
spec.JWTIdentityBaseField = "user_id"
spec.JWTPolicyFieldName = "policy_id"
spec.Proxy.ListenPath = "/"
})[0]

pID := createPolicy()
jwtToken := createJWKToken(func(t *jwt.Token) {
t.Header["kid"] = "12345"
// Set some claims
t.Claims.(jwt.MapClaims)["foo"] = "bar"
t.Claims.(jwt.MapClaims)["user_id"] = "user"
t.Claims.(jwt.MapClaims)["policy_id"] = pID
t.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 72).Unix()
})

authHeaders := map[string]string{"authorization": jwtToken}

t.Run("Direct JWK URL", func(t *testing.T) {
spec.JWTSource = testHttpJWK
loadAPI(spec)

ts.Run(t, test.TestCase{
Headers: authHeaders, Code: 200,
})
})

t.Run("Base64 JWK URL", func(t *testing.T) {
spec.JWTSource = base64.StdEncoding.EncodeToString([]byte(testHttpJWK))
loadAPI(spec)

ts.Run(t, test.TestCase{
Headers: authHeaders, Code: 200,
})
})
}

0 comments on commit d605cff

Please sign in to comment.