282 lines
8.0 KiB
Go
282 lines
8.0 KiB
Go
package token
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/rsa"
|
|
"encoding/json"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
func TestJWKHS256(t *testing.T) {
|
|
key := `{
|
|
"kty":"oct",
|
|
"alg":"HS256",
|
|
"k":"4S9YZLHK1traIaXQooCnPfBw_yR8j9VEPaAMWAog_YQ"
|
|
}`
|
|
var j map[string]interface{}
|
|
err := json.Unmarshal([]byte(key), &j)
|
|
if err != nil {
|
|
t.Fatalf("Unmarshal: %v", err)
|
|
}
|
|
k, err := ParseKey(j)
|
|
if err != nil {
|
|
t.Fatalf("ParseKey: %v", err)
|
|
}
|
|
kk, ok := k.([]byte)
|
|
if !ok || len(kk) != 32 {
|
|
t.Errorf("ParseKey: got %v", kk)
|
|
}
|
|
}
|
|
|
|
func TestJWKES256(t *testing.T) {
|
|
key := `{
|
|
"kty":"EC",
|
|
"alg":"ES256",
|
|
"crv":"P-256",
|
|
"x":"dElK9qBNyCpRXdvJsn4GdjrFzScSzpkz_I0JhKbYC88",
|
|
"y":"pBhVb37haKvwEoleoW3qxnT4y5bK35_RTP7_RmFKR6Q"
|
|
}`
|
|
var j map[string]interface{}
|
|
err := json.Unmarshal([]byte(key), &j)
|
|
if err != nil {
|
|
t.Fatalf("Unmarshal: %v", err)
|
|
}
|
|
k, err := ParseKey(j)
|
|
if err != nil {
|
|
t.Fatalf("ParseKey: %v", err)
|
|
}
|
|
kk, ok := k.(*ecdsa.PublicKey)
|
|
if !ok || kk.Params().Name != "P-256" {
|
|
t.Errorf("ParseKey: got %v", kk)
|
|
}
|
|
if !kk.IsOnCurve(kk.X, kk.Y) {
|
|
t.Errorf("point is not on curve")
|
|
}
|
|
}
|
|
|
|
func TestJWKRS256(t *testing.T) {
|
|
key := `{
|
|
"kty": "RSA",
|
|
"alg": "RS256",
|
|
"n": "pkW_7FkYAlKo4NSs-npeA4y6hHZk274RmQ1pf1nqNmXfipYqO4yySLWERZlj3B_yOCkXGn_MPQ-dZ5wiJEi1wW2RNMzb4_r1Q2l2GWZDTRLz4GGHIV0ZCdupacjVXN4lIa-oNJx2N8Pgfsla2zYRkaE9Le19uG5ncP1TW6INqd9-bSll95PIF59OQ10BvZGgGc1MYqVNB0mI0Q9OwSG4R2yaPGAnp8v2Wdjc0hDHzNBHajcjzsx0ZTM44s-rj-1-Z0JN-Gx1tG2UTPvrWXJcqfLvwE-9mGPfct8NgMDDdS_dX-xNF3RK-F93OwVfg6lccnCwOWpNwF6ZoFqxEXFcxw",
|
|
"e": "AQAB"
|
|
}`
|
|
var j map[string]interface{}
|
|
err := json.Unmarshal([]byte(key), &j)
|
|
if err != nil {
|
|
t.Fatalf("Unmarshal: %v", err)
|
|
}
|
|
k, err := ParseKey(j)
|
|
if err != nil {
|
|
t.Fatalf("ParseKey: %v", err)
|
|
}
|
|
kk, ok := k.(*rsa.PublicKey)
|
|
if !ok || kk.Size() != 256 {
|
|
t.Errorf("ParseKey: got %v", kk)
|
|
}
|
|
}
|
|
|
|
func TestMatchHall(t *testing.T) {
|
|
type tt struct {
|
|
p, g string
|
|
s bool
|
|
}
|
|
good := []tt{
|
|
{"/hall/a/", "a", false},
|
|
{"/hall/a/b/", "a/b", false},
|
|
{"/hall/a/", "a", true},
|
|
{"/hall/a/", "a/b", true},
|
|
{"/hall/a/b/", "a/b", true},
|
|
{"/hall/a/b/", "a/b/c", true},
|
|
}
|
|
|
|
bad := []tt{
|
|
{"/hall/a/", "b", false},
|
|
{"/hall/a", "a", false},
|
|
{"/hall/a", "a", true},
|
|
{"/hall/a/", "a/b", false},
|
|
{"/hall/a/b/", "a", false},
|
|
{"/hall/a/b/", "a", true},
|
|
}
|
|
|
|
for _, test := range good {
|
|
if !matchHall(test.p, test.g, test.s) {
|
|
t.Errorf("%v %v %v didn't match", test.p, test.g, test.s)
|
|
}
|
|
}
|
|
|
|
for _, test := range bad {
|
|
if matchHall(test.p, test.g, test.s) {
|
|
t.Errorf("%v %v %v matched", test.p, test.g, test.s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func makeTestJWT(t *testing.T, key any, claims jwt.MapClaims) string {
|
|
t.Helper()
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
value, err := token.SignedString(key)
|
|
if err != nil {
|
|
t.Fatalf("SignedString: %v", err)
|
|
}
|
|
return value
|
|
}
|
|
|
|
func TestJWT(t *testing.T) {
|
|
key := `{"alg":"HS256","k":"H7pCkktUl5KyPCZ7CKw09y1j460tfIv4dRcS1XstUKY","key_ops":["sign","verify"],"kty":"oct"}`
|
|
var k map[string]interface{}
|
|
err := json.Unmarshal([]byte(key), &k)
|
|
if err != nil {
|
|
t.Fatalf("Unmarshal: %v", err)
|
|
}
|
|
|
|
keys := []map[string]interface{}{k}
|
|
signingKey, err := ParseKey(k)
|
|
if err != nil {
|
|
t.Fatalf("ParseKey: %v", err)
|
|
}
|
|
username := "Username"
|
|
otherUser := "otherUser"
|
|
baseClaims := jwt.MapClaims{
|
|
"aud": "https://skald.org:8443/hall/auth/",
|
|
"permissions": []string{"present"},
|
|
"iat": int64(1645310294),
|
|
"exp": int64(2906750294),
|
|
"iss": "http://localhost:1234/",
|
|
}
|
|
|
|
goodToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
|
"sub": "Username",
|
|
"aud": baseClaims["aud"],
|
|
"permissions": baseClaims["permissions"],
|
|
"iat": baseClaims["iat"],
|
|
"exp": baseClaims["exp"],
|
|
"iss": baseClaims["iss"],
|
|
})
|
|
|
|
tok, err := Parse(goodToken, keys)
|
|
if err != nil {
|
|
t.Errorf("Couldn't parse goodToken: %v", err)
|
|
}
|
|
|
|
username, perms, err := tok.Check("skald.org:8443", "auth", &username)
|
|
if err != nil {
|
|
t.Errorf("goodToken is not valid: %v", err)
|
|
}
|
|
if username != "Username" || !reflect.DeepEqual(perms, []string{"present"}) {
|
|
t.Errorf("Expected username, [present], got %v %v", username, perms)
|
|
}
|
|
|
|
username, perms, err = tok.Check("skald.org:8443", "auth", &otherUser)
|
|
if err != nil {
|
|
t.Errorf("goodToken is not valid: %v", err)
|
|
}
|
|
if username != "Username" || !reflect.DeepEqual(perms, []string{"present"}) {
|
|
t.Errorf("Expected username, [present], got %v %v", username, perms)
|
|
}
|
|
|
|
username, perms, err = tok.Check("", "auth", &username)
|
|
if err != nil {
|
|
t.Errorf("goodToken is not valid: %v", err)
|
|
}
|
|
|
|
_, _, err = tok.Check("skald.org", "auth", &username)
|
|
if err == nil {
|
|
t.Errorf("goodToken is valid for wrong hostname")
|
|
}
|
|
|
|
_, _, err = tok.Check("skald.org:8443", "not-auth", &username)
|
|
if err == nil {
|
|
t.Errorf("goodToken is valid for wrong hall")
|
|
}
|
|
|
|
_, _, err = tok.Check("skald.org:8443", "auth/subhall", &username)
|
|
if err == nil {
|
|
t.Errorf("goodToken is valid for subhall")
|
|
}
|
|
|
|
emptySubToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
|
"sub": "",
|
|
"aud": baseClaims["aud"],
|
|
"permissions": baseClaims["permissions"],
|
|
"iat": baseClaims["iat"],
|
|
"exp": baseClaims["exp"],
|
|
"iss": baseClaims["iss"],
|
|
})
|
|
|
|
tok, err = Parse(emptySubToken, keys)
|
|
if err != nil {
|
|
t.Errorf("Couldn't parse emptySubToken: %v", err)
|
|
}
|
|
username, perms, err = tok.Check("skald.org:8443", "auth", &otherUser)
|
|
if err != nil {
|
|
t.Errorf("anonymousToken is not valid: %v", err)
|
|
}
|
|
if username != "" || !reflect.DeepEqual(perms, []string{"present"}) {
|
|
t.Errorf("Expected \"\", [present], got %v %v", username, perms)
|
|
}
|
|
|
|
noSubToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
|
"aud": baseClaims["aud"],
|
|
"permissions": baseClaims["permissions"],
|
|
"iat": baseClaims["iat"],
|
|
"exp": baseClaims["exp"],
|
|
"iss": baseClaims["iss"],
|
|
})
|
|
|
|
tok, err = Parse(noSubToken, keys)
|
|
if err != nil {
|
|
t.Errorf("Couldn't parse noSubToken: %v", err)
|
|
}
|
|
username, perms, err = tok.Check("skald.org:8443", "auth", &otherUser)
|
|
if err != nil {
|
|
t.Errorf("noSubToken is not valid: %v", err)
|
|
}
|
|
if username != "" || !reflect.DeepEqual(perms, []string{"present"}) {
|
|
t.Errorf("Expected \"\", [present], got %v %v", username, perms)
|
|
}
|
|
|
|
badToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQ2OSwiZXhwIjoyOTA2NzUwNDY5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
|
|
|
_, err = Parse(badToken, keys)
|
|
if err == nil {
|
|
t.Errorf("badToken is good")
|
|
}
|
|
|
|
expiredToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDMyMiwiZXhwIjoxNjQ1MzEwMzUyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.jyqRhoV6iK54SvlP33Fy630aDo-sLNmKKi1kcfqs378"
|
|
|
|
_, err = Parse(expiredToken, keys)
|
|
if err == nil {
|
|
t.Errorf("expiredToken is good")
|
|
}
|
|
|
|
noneToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQwMSwiZXhwIjoxNjQ1MzEwNDMxLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
|
_, err = Parse(noneToken, keys)
|
|
if err == nil {
|
|
t.Errorf("noneToken is good")
|
|
}
|
|
|
|
subhallsToken := makeTestJWT(t, signingKey, jwt.MapClaims{
|
|
"sub": "Username",
|
|
"aud": baseClaims["aud"],
|
|
"include-subhalls": true,
|
|
"permissions": baseClaims["permissions"],
|
|
"iat": baseClaims["iat"],
|
|
"exp": baseClaims["exp"],
|
|
"iss": baseClaims["iss"],
|
|
})
|
|
tok, err = Parse(subhallsToken, keys)
|
|
if err != nil {
|
|
t.Errorf("subhallsToken is not valid: %v", err)
|
|
}
|
|
|
|
_, _, err = tok.Check("skald.org:8443", "auth/subhall", &username)
|
|
if err != nil {
|
|
t.Errorf("subhallsToken is not valid for subhall: %v", err)
|
|
}
|
|
}
|