Files
opencloud/pkg/oidc/client_test.go
Jörn Friedrich Dreyer b07b5a1149 use plain pkg module
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
2025-01-13 16:42:19 +01:00

206 lines
4.9 KiB
Go

package oidc_test
import (
"context"
"crypto/rand"
"crypto/rsa"
"testing"
"github.com/MicahParks/keyfunc/v2"
"github.com/golang-jwt/jwt/v5"
"github.com/opencloud-eu/opencloud/pkg/oidc"
)
type signingKey struct {
priv interface{}
jwks *keyfunc.JWKS
}
func TestLogoutVerify(t *testing.T) {
tests := []logoutVerificationTest{
{
name: "good token",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
},
{
name: "invalid issuer",
issuer: "https://bar",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo1",
"sub": "248289761001",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "invalid sig",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
verificationKey: newRSAKey(t),
wantErr: true,
},
{
name: "no sid and no sub",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "Prohibited nonce present",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"nonce": "123",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "Wrong Event string",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": map[string]interface{}{
"http://blah.blah.blash/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "No Event string",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
}),
signKey: newRSAKey(t),
wantErr: true,
},
}
for _, test := range tests {
t.Run(test.name, test.run)
}
}
type logoutVerificationTest struct {
// Name of the subtest.
name string
// If not provided defaults to "https://foo"
issuer string
// JWT payload (just the claims).
logoutToken *jwt.Token
// Key to sign the ID Token with.
signKey *signingKey
// If not provided defaults to signKey. Only useful when
// testing invalid signatures.
verificationKey *signingKey
wantErr bool
}
func (v logoutVerificationTest) runGetToken(t *testing.T) (*oidc.LogoutToken, error) {
// token := v.signKey.sign(t, []byte(v.logoutToken))
v.logoutToken.Header["kid"] = "1"
token, err := v.logoutToken.SignedString(v.signKey.priv)
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
issuer := "https://foo"
var jwks *keyfunc.JWKS
if v.verificationKey == nil {
jwks = v.signKey.jwks
} else {
jwks = v.verificationKey.jwks
}
pm := oidc.ProviderMetadata{}
verifier := oidc.NewOIDCClient(
oidc.WithOidcIssuer(issuer),
oidc.WithJWKS(jwks),
oidc.WithProviderMetadata(&pm),
)
return verifier.VerifyLogoutToken(ctx, token)
}
func (l logoutVerificationTest) run(t *testing.T) {
_, err := l.runGetToken(t)
if err != nil && !l.wantErr {
t.Errorf("%v", err)
}
if err == nil && l.wantErr {
t.Errorf("expected error")
}
}
func newRSAKey(t testing.TB) *signingKey {
priv, err := rsa.GenerateKey(rand.Reader, 1028)
if err != nil {
t.Fatal(err)
}
givenKey := keyfunc.NewGivenRSA(
&priv.PublicKey,
keyfunc.GivenKeyOptions{Algorithm: jwt.SigningMethodRS256.Alg()},
)
jwks := keyfunc.NewGiven(
map[string]keyfunc.GivenKey{
"1": givenKey,
},
)
return &signingKey{priv, jwks}
}