mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-30 09:38:26 -05:00
206 lines
4.9 KiB
Go
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}
|
|
}
|