Skip to content

Commit

Permalink
chore: update tests for new JWT handling
Browse files Browse the repository at this point in the history
  • Loading branch information
smlx committed Jun 30, 2023
1 parent f23267c commit 5ef8424
Show file tree
Hide file tree
Showing 5 changed files with 339 additions and 28 deletions.
5 changes: 5 additions & 0 deletions internal/keycloak/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ func (c *Client) ValidateToken(t *oauth2.Token, sub string,
opts ...jwt.ParserOption) (*LagoonClaims, error) {
return c.parseAccessToken(t, sub, opts...)
}

// SetClientID sets the Client ID for testing.
func (l *LagoonClaims) SetClientID(clientID string) {
l.clientID = clientID
}
66 changes: 45 additions & 21 deletions internal/keycloak/jwt_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keycloak_test

import (
"bytes"
"context"
"encoding/json"
"io"
Expand Down Expand Up @@ -136,6 +137,18 @@ func TestValidateTokenClaims(t *testing.T) {
// set up logger
log := zap.Must(zap.NewDevelopment())
// set up test cases
validClaims := keycloak.LagoonClaims{
AuthorizedParty: "auth-server",
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "http://lagoon-core-keycloak:8080/auth/realms/lagoon",
Subject: "7bc982a1-c90a-4229-8b5f-816c18d9dfbc",
Audience: jwt.ClaimStrings{"account"},
ExpiresAt: jwt.NewNumericDate(time.Date(2022, time.November, 14, 15, 20, 44, 0, time.UTC).In(time.Local)),
IssuedAt: jwt.NewNumericDate(time.Date(2022, time.November, 14, 15, 15, 44, 0, time.UTC).In(time.Local)),
ID: "b70c4250-a419-40f1-8e3a-a87c56f2c4a3",
},
}
validClaims.SetClientID("auth-server")
var testCases = map[string]struct {
input *oauth2.Token
validationTime time.Time
Expand All @@ -147,18 +160,8 @@ func TestValidateTokenClaims(t *testing.T) {
AccessToken: "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJrd0ZLNVlwMlI3QkxZalc4Z1NZNkxzQjNsSVlzcFI1TmlFdW5GRUdxZGdnIn0.eyJleHAiOjE2Njg0MzkyNDQsImlhdCI6MTY2ODQzODk0NCwianRpIjoiYjcwYzQyNTAtYTQxOS00MGYxLThlM2EtYTg3YzU2ZjJjNGEzIiwiaXNzIjoiaHR0cDovL2xhZ29vbi1jb3JlLWtleWNsb2FrOjgwODAvYXV0aC9yZWFsbXMvbGFnb29uIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjdiYzk4MmExLWM5MGEtNDIyOS04YjVmLTgxNmMxOGQ5ZGZiYyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImF1dGgtc2VydmVyIiwic2Vzc2lvbl9zdGF0ZSI6ImViZWNlNTAxLWIzMWUtNDBiNy1iMWIwLTU4MjhkYWY0ZmE3OSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsicGxhdGZvcm0tb3duZXIiLCJvZmZsaW5lX2FjY2VzcyIsImFkbWluIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJlYmVjZTUwMS1iMzFlLTQwYjctYjFiMC01ODI4ZGFmNGZhNzkiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6ImxhZ29vbmFkbWluIn0.GaVMQSKpZldYpY0bmNVY1EJKf8pZVq8bps1-xPLQvWn2KlnjkVFKMuE34j66HRKJ3ZJybDyCkBAIr2ImzunFy5_ur9GdXRBHOo5RtnpNL9YxGwUTWNAtTqOqXMi4QkY4AHfMkgHAhZRSMP3oADjiv2hOkIeummTXo6KTY7fOmumz1UkvRyfeWt-6tcSWrCBezvuMXhwJUF7_EuEPdLaNpiQ_H1wqhamHg1YZ6QzJ5z7NcD8f6dc-h7qUhTBlMGOGEeWThmxudrzOuHkcx6LBzutzPdQNhTo7d2PsAa4igz3RXZV65BBVMkqp8v8k1ZIxb2a_6DHngd2T-XDjzNFREQ",
},
validationTime: time.Date(2022, time.November, 14, 15, 16, 0, 0, time.UTC),
expectClaims: &keycloak.LagoonClaims{
AuthorizedParty: "auth-server",
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "http://lagoon-core-keycloak:8080/auth/realms/lagoon",
Subject: "7bc982a1-c90a-4229-8b5f-816c18d9dfbc",
Audience: jwt.ClaimStrings{"account"},
ExpiresAt: jwt.NewNumericDate(time.Date(2022, time.November, 14, 15, 20, 44, 0, time.UTC).In(time.Local)),
IssuedAt: jwt.NewNumericDate(time.Date(2022, time.November, 14, 15, 15, 44, 0, time.UTC).In(time.Local)),
ID: "b70c4250-a419-40f1-8e3a-a87c56f2c4a3",
},
},
expectError: false,
expectClaims: &validClaims,
expectError: false,
},
"invalid signature (last 5 chars)": {
input: &oauth2.Token{
Expand Down Expand Up @@ -206,14 +209,28 @@ func TestValidateTokenClaims(t *testing.T) {
expectError: true,
},
}
// init client
for name, tc := range testCases {
t.Run(name, func(tt *testing.T) {
// start mock keycloak server to serve the realm metadata (including the
// RSA public key) during keycloak.NewClient().
ts := httptest.NewServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
f, err := os.Open("testdata/realm.metadata.json")
// load the discovery JSON first, because the mux closure needs to
// reference its buffer
discoveryBuf, err := os.ReadFile("testdata/realm.oidc.discovery.json")
if err != nil {
tt.Fatal(err)
return
}
// configure router with the URLs that OIDC discovery and JWKS require
mux := http.NewServeMux()
mux.HandleFunc("/auth/realms/lagoon/.well-known/openid-configuration",
func(w http.ResponseWriter, r *http.Request) {
d := bytes.NewBuffer(discoveryBuf)
_, err = io.Copy(w, d)
if err != nil {
tt.Fatal(err)
}
})
mux.HandleFunc("/auth/realms/lagoon/protocol/openid-connect/certs",
func(w http.ResponseWriter, r *http.Request) {
f, err := os.Open("testdata/realm.oidc.certs.json")
if err != nil {
tt.Fatal(err)
return
Expand All @@ -222,18 +239,25 @@ func TestValidateTokenClaims(t *testing.T) {
if err != nil {
tt.Fatal(err)
}
}))
})
// start mock keycloak server to serve the realm oidc certs (including the
// RSA public key) during keycloak.NewClient().
ts := httptest.NewServer(mux)
defer ts.Close()
// now replace the example URL in the discovery JSON with the actual
// httptest server URL
discoveryBuf = bytes.ReplaceAll(discoveryBuf,
[]byte("https://keycloak.example.com"), []byte(ts.URL))
// init keycloak client
// note: client secret is empty because it isn't used in this test, but
// NOTE: client secret is empty because it isn't used in this test, but
// client ID is checked against azp in the token.
k, err := keycloak.NewClient(context.Background(), log, ts.URL,
"auth-server", "")
if err != nil {
tt.Fatal(err)
}
// run the validation
claims, err := k.ValidateToken(tc.input, "sub",
claims, err := k.ValidateToken(tc.input, "7bc982a1-c90a-4229-8b5f-816c18d9dfbc",
jwt.WithTimeFunc(func() time.Time { return tc.validationTime }))
// check the response
if tc.expectError {
Expand Down
7 changes: 0 additions & 7 deletions internal/keycloak/testdata/realm.metadata.json

This file was deleted.

17 changes: 17 additions & 0 deletions internal/keycloak/testdata/realm.oidc.certs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"keys": [
{
"alg": "RS256",
"e": "AQAB",
"kid": "kwFK5Yp2R7BLYjW8gSY6LsB3lIYspR5NiEunFEGqdgg",
"kty": "RSA",
"n": "mvoqDkFy0B1CSiQEF8zUNFw3-ePdIFSk1GOoQzVwpyBsZhjkv74A-tbZvSIAEX5Pu9DHN_5Hh6WGYgxVRvVC2Mpw5rHR4qf35Be-KsR--pLGLKkI8W0PEKVp5-occDuNqtMUMBHjLdWLd9d49tJjHQeHPexHRFI5Hv1KiMD159LYy8_T5UBuR_lI7Gy3JHfHcPlLLBVgA8rzIjxUzdn9jXIGIYG_vY6-fe8ElI-TvED0603x5gIPCAwMf33UdojXh_oIFyuRgwjolBzEIPPdasIcfJfR44XXV3bdDEa-bewvMJEgEyEMKdkBxbluPAXfDBvQ4prmlcaVqJO4Pez1GQ",
"use": "sig",
"x5c": [
"MIICmzCCAYMCBgF0t9ya7zANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZsYWdvb24wHhcNMjAwOTIyMjIwNzAyWhcNMzAwOTIyMjIwODQyWjARMQ8wDQYDVQQDDAZsYWdvb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCa+ioOQXLQHUJKJAQXzNQ0XDf5490gVKTUY6hDNXCnIGxmGOS/vgD61tm9IgARfk+70Mc3/keHpYZiDFVG9ULYynDmsdHip/fkF74qxH76ksYsqQjxbQ8QpWnn6hxwO42q0xQwEeMt1Yt313j20mMdB4c97EdEUjke/UqIwPXn0tjLz9PlQG5H+UjsbLckd8dw+UssFWADyvMiPFTN2f2NcgYhgb+9jr597wSUj5O8QPTrTfHmAg8IDAx/fdR2iNeH+ggXK5GDCOiUHMQg891qwhx8l9HjhddXdt0MRr5t7C8wkSATIQwp2QHFuW48Bd8MG9DimuaVxpWok7g97PUZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGM2pXGBMcQ+kxssb+xh67NDKSdR3NtKkVoT3cS+LRZRJ6UYYMJSSAeOanrigqAdJPqjzjazejFyq1Bn3Mgiw2GDz5oNbmMlH5IYjMNTaPVKxgyLtqNen8gGFMM6ZAw7vy7+g4aBBbSzMG0r+d27IrqdeqPWLWELSVyD6GiUbJKBQmqk8f0nRsJ4skFsq201reQ3DvHhXH3+iuCbb6uARLkjigW1PUILCOcYFamiJlMGC7dyfLMjHf+c432oZ8pSKhhZ6EQoxQbChSF6XKiZJEEzRlkfVyCCd2WmZQtupsKjCrAqhWzusFdDjmk89dXqTrWuNSEhTCGYgnXhskF/Kpo="
],
"x5t": "BZCFuj1AbEUY81mQ0yqRYr8SKQQ",
"x5t#S256": "xxaFA5-J65GFkgmN8mE8p3H9hE4EwJUElRUfRNOT3hE"
}
]
}
Loading

0 comments on commit 5ef8424

Please sign in to comment.