Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
package jwtex
import (
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"testing"
)
const (
expiredCred = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFhIiwiYXVkaWVuY2UiOiJncmVldGluZy1zZXJ2aWNlIiwiaWF0IjoxNTMxMTQ4NTA4fQ.vWUvZv-E2rWaKvLuZ7xl4l4yqU8pkK0--jZi7JYl62w"
cred = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFhIiwiYXVkaWVuY2UiOiJncmVldGluZy1zZXJ2aWNlIiwiaWF0IjoyMTQ3NDgzNjQ3fQ.tObQL4l0z9ZDze_QKqwOdHqy0LkPutdFM8LE4W-rBYM"
)
func TestValidateCred(t *testing.T) {
gt, err := ValidateCred(cred, "a")
if err != nil {
t.Fatal("Received error while properly parsing the example jwt JWT")
}
if gt.Audience != "jwtex" {
t.Fatal("Unable to fetch the internals of the JWT")
}
}
func TestWrongKey(t *testing.T) {
// This is the wrong key
_, err := ValidateCred(cred, "b")
if err == nil {
t.Fatal("No error while parsing JWT with the wrong key")
}
}
func TestFuzzSigLen(t *testing.T) {
parts := strings.Split(cred, ".")
if len(parts) != 3 {
t.Fatal("Couldn't parse jwt properly")
}
sig := []byte(parts[2])
c := fmt.Sprintf("%s.%s.%s", parts[0], parts[1], string(sig[:12]))
_, err := ValidateCred(c, "a")
if err == nil {
t.Fatal("No error while parsing JWt with truncated signature")
}
}
func TestFuzzBytePosition(t *testing.T) {
parts := strings.Split(cred, ".")
if len(parts) != 3 {
t.Fatal("Couldn't parse jwt properly")
}
sig := []byte(parts[2])
// Mess with some of the bytes by xorswapping a few byte positions
sig[0] = sig[0] ^ sig[1]
sig[1] = sig[0] ^ sig[1]
sig[0] = sig[0] ^ sig[1]
sig[2] = sig[2] ^ sig[3]
sig[3] = sig[2] ^ sig[3]
sig[2] = sig[2] ^ sig[3]
c := fmt.Sprintf("%s.%s.%s", parts[0], parts[1], string(sig))
_, err := ValidateCred(c, "a")
if err == nil {
t.Fatal("No error while parsing JWT with swapped byte positions")
}
}
func TestFuzzAlg(t *testing.T) {
var (
headers = make(map[string]string)
)
parts := strings.Split(cred, ".")
b64JwtHeader := parts[0]
jwtHeader, err := base64.RawURLEncoding.DecodeString(b64JwtHeader)
if err != nil {
t.Fatalf("Could not base64 decode nopadding jwt header: %s", err)
}
err = json.Unmarshal([]byte(jwtHeader), &headers)
if err != nil {
t.Fatalf("Failed to parse jwt header: %s", err)
}
if _, ok := headers["alg"]; !ok {
t.Fatal("JWT does not have an algorithm header")
}
headers["alg"] = "none"
newHeader, err := json.Marshal(headers)
if err != nil {
t.Fatalf("Failed to marshal jwt header: %s", err)
}
// Recreate the JWT header. This should also cause the signature to fail
// but we should also fail for an incorrect alg. Defects like alg=none
// are very real.
// Read:
// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
c := fmt.Sprintf("%s.%s.%s", string(newHeader), parts[1], parts[2])
_, err = ValidateCred(c, "a")
if err == nil {
t.Fatal("No error while parsing JWT with none algorithm")
}
}
func TestExpiration(t *testing.T) {
gt, err := ValidateCred(expiredCred, "a")
if err == nil {
t.Fatal("Did not receive error while validating expired token")
}
gt, err = ValidateCred(cred, "a")
if err != nil {
t.Fatal("Received error while properly parsing the test example JWT")
}
if gt.Valid() != nil {
t.Fatalf("Never expire testing JWT is not validating: %s", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment