Use PinnipedSession type instead of fosite's DefaultSesssion type
This will allow us to store custom data inside the fosite session storage for all downstream OIDC sessions. Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
parent
6e41c10584
commit
c6f1d29538
@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/oauth2"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
@ -18,6 +17,7 @@ import (
|
||||
"go.pinniped.dev/internal/crud"
|
||||
"go.pinniped.dev/internal/fositestorage"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -26,7 +26,7 @@ const (
|
||||
ErrInvalidAccessTokenRequestVersion = constable.Error("access token request data has wrong version")
|
||||
ErrInvalidAccessTokenRequestData = constable.Error("access token request data must be present")
|
||||
|
||||
accessTokenStorageVersion = "1"
|
||||
accessTokenStorageVersion = "2"
|
||||
)
|
||||
|
||||
type RevocationStorage interface {
|
||||
@ -110,7 +110,7 @@ func newValidEmptyAccessTokenSession() *session {
|
||||
return &session{
|
||||
Request: &fosite.Request{
|
||||
Client: &clientregistry.Client{},
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@ -22,6 +21,8 @@ import (
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
const namespace = "test-ns"
|
||||
@ -51,7 +52,7 @@ func TestAccessTokenStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/access-token",
|
||||
@ -84,16 +85,10 @@ func TestAccessTokenStorage(t *testing.T) {
|
||||
RequestObjectSigningAlgorithm: "",
|
||||
TokenEndpointAuthSigningAlgorithm: "",
|
||||
}},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: &openid.DefaultSession{
|
||||
Claims: nil,
|
||||
Headers: nil,
|
||||
ExpiresAt: nil,
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
RequestedAudience: nil,
|
||||
GrantedAudience: nil,
|
||||
}
|
||||
@ -107,6 +102,7 @@ func TestAccessTokenStorage(t *testing.T) {
|
||||
err = storage.DeleteAccessTokenSession(ctx, "fancy-signature")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
require.Equal(t, wantActions, client.Actions())
|
||||
}
|
||||
|
||||
@ -125,7 +121,7 @@ func TestAccessTokenStorageRevocation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/access-token",
|
||||
@ -151,11 +147,8 @@ func TestAccessTokenStorageRevocation(t *testing.T) {
|
||||
TokenEndpointAuthMethod: "something",
|
||||
},
|
||||
},
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: &openid.DefaultSession{
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
}
|
||||
err := storage.CreateAccessTokenSession(ctx, "fancy-signature", request)
|
||||
require.NoError(t, err)
|
||||
@ -164,6 +157,7 @@ func TestAccessTokenStorageRevocation(t *testing.T) {
|
||||
err = storage.RevokeAccessToken(ctx, "abcd-1")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
require.Equal(t, wantActions, client.Actions())
|
||||
}
|
||||
|
||||
@ -190,7 +184,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1"},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/access-token",
|
||||
@ -200,7 +194,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
|
||||
_, err = storage.GetAccessTokenSession(ctx, "fancy-signature", nil)
|
||||
|
||||
require.EqualError(t, err, "access token request data has wrong version: access token session for fancy-signature has version not-the-right-version instead of 1")
|
||||
require.EqualError(t, err, "access token request data has wrong version: access token session for fancy-signature has version not-the-right-version instead of 2")
|
||||
}
|
||||
|
||||
func TestNilSessionRequest(t *testing.T) {
|
||||
@ -218,7 +212,7 @@ func TestNilSessionRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/access-token",
|
||||
@ -246,10 +240,10 @@ func TestCreateWithWrongRequesterDataTypes(t *testing.T) {
|
||||
Client: &clientregistry.Client{},
|
||||
}
|
||||
err := storage.CreateAccessTokenSession(ctx, "signature-doesnt-matter", request)
|
||||
require.EqualError(t, err, "requester's session must be of type openid.DefaultSession")
|
||||
require.EqualError(t, err, "requester's session must be of type PinnipedSession")
|
||||
|
||||
request = &fosite.Request{
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
Client: nil,
|
||||
}
|
||||
err = storage.CreateAccessTokenSession(ctx, "signature-doesnt-matter", request)
|
||||
@ -261,7 +255,7 @@ func TestCreateWithoutRequesterID(t *testing.T) {
|
||||
|
||||
request := &fosite.Request{
|
||||
ID: "", // empty ID
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
Client: &clientregistry.Client{},
|
||||
}
|
||||
err := storage.CreateAccessTokenSession(ctx, "signature-doesnt-matter", request)
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/oauth2"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
@ -19,6 +18,7 @@ import (
|
||||
"go.pinniped.dev/internal/crud"
|
||||
"go.pinniped.dev/internal/fositestorage"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -27,7 +27,7 @@ const (
|
||||
ErrInvalidAuthorizeRequestData = constable.Error("authorization request data must be present")
|
||||
ErrInvalidAuthorizeRequestVersion = constable.Error("authorization request data has wrong version")
|
||||
|
||||
authorizeCodeStorageVersion = "1"
|
||||
authorizeCodeStorageVersion = "2"
|
||||
)
|
||||
|
||||
var _ oauth2.AuthorizeCodeStorage = &authorizeCodeStorage{}
|
||||
@ -139,7 +139,7 @@ func NewValidEmptyAuthorizeCodeSession() *AuthorizeCodeSession {
|
||||
return &AuthorizeCodeSession{
|
||||
Request: &fosite.Request{
|
||||
Client: &clientregistry.Client{},
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -169,161 +169,172 @@ func (e *errSerializationFailureWithCause) Error() string {
|
||||
// ExpectedAuthorizeCodeSessionJSONFromFuzzing is used for round tripping tests.
|
||||
// It is exported to allow integration tests to use it.
|
||||
const ExpectedAuthorizeCodeSessionJSONFromFuzzing = `{
|
||||
"active": true,
|
||||
"request": {
|
||||
"active": true,
|
||||
"request": {
|
||||
"id": "曑x螠Gæ鄋楨",
|
||||
"requestedAt": "2082-11-10T18:36:11.627253638Z",
|
||||
"client": {
|
||||
"id": ":NJ¸Ɣ8(黋馛ÄRɴJa¶z",
|
||||
"client_secret": "UQ==",
|
||||
"redirect_uris": [
|
||||
"ǖ枭kʍ切厦ȳ箦;¥ʊXĝ奨誷傥祩d",
|
||||
"zŇZ",
|
||||
"優蒼ĊɌț訫DŽǽeʀO2ƚ&N"
|
||||
],
|
||||
"grant_types": [
|
||||
"唐W6ɻ橩斚薛ɑƐ"
|
||||
],
|
||||
"response_types": [
|
||||
"w",
|
||||
"ǔŭe[u@阽羂ŷ-Ĵ½輢OÅ濲喾H"
|
||||
],
|
||||
"scopes": [
|
||||
"G螩歐湡ƙı唡ɸğƎ&胢輢Ƈĵƚ"
|
||||
],
|
||||
"audience": [
|
||||
"ě"
|
||||
],
|
||||
"public": false,
|
||||
"jwks_uri": "o*泞羅ʘ Ⱦķ瀊垰7ã\")",
|
||||
"jwks": {
|
||||
"keys": [
|
||||
{
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
"x": "nK9xgX_iN7u3u_i8YOO7ZRT_WK028Vd_nhtsUu7Eo6E",
|
||||
"x5u": {
|
||||
"Scheme": "",
|
||||
"Opaque": "",
|
||||
"User": null,
|
||||
"Host": "",
|
||||
"Path": "",
|
||||
"RawPath": "",
|
||||
"ForceQuery": false,
|
||||
"RawQuery": "",
|
||||
"Fragment": "",
|
||||
"RawFragment": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
"x": "UbbswQgzWhfGCRlwQmMp6fw_HoIoqkIaKT-2XN2fuYU",
|
||||
"x5u": {
|
||||
"Scheme": "",
|
||||
"Opaque": "",
|
||||
"User": null,
|
||||
"Host": "",
|
||||
"Path": "",
|
||||
"RawPath": "",
|
||||
"ForceQuery": false,
|
||||
"RawQuery": "",
|
||||
"Fragment": "",
|
||||
"RawFragment": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"token_endpoint_auth_method": "ƿʥǟȒ伉<x¹T鼓c吏",
|
||||
"request_uris": [
|
||||
"Ć捘j]=谅ʑɑɮ$Ól4Ȟ",
|
||||
",Q7钎漡臧n"
|
||||
],
|
||||
"request_object_signing_alg": "3@¡廜+v,淬Ʋ4Dʧ呩锏緍场",
|
||||
"token_endpoint_auth_signing_alg": "(ưƓǴ罷ǹ~]ea胠"
|
||||
"id": ":NJ¸Ɣ8(黋馛ÄRɴJa¶z",
|
||||
"client_secret": "UQ==",
|
||||
"redirect_uris": [
|
||||
"ǖ枭kʍ切厦ȳ箦;¥ʊXĝ奨誷傥祩d",
|
||||
"zŇZ",
|
||||
"優蒼ĊɌț訫DŽǽeʀO2ƚ\u0026N"
|
||||
],
|
||||
"grant_types": [
|
||||
"唐W6ɻ橩斚薛ɑƐ"
|
||||
],
|
||||
"response_types": [
|
||||
"w",
|
||||
"ǔŭe[u@阽羂ŷ-Ĵ½輢OÅ濲喾H"
|
||||
],
|
||||
"scopes": [
|
||||
"G螩歐湡ƙı唡ɸğƎ\u0026胢輢Ƈĵƚ"
|
||||
],
|
||||
"audience": [
|
||||
"ě"
|
||||
],
|
||||
"public": false,
|
||||
"jwks_uri": "o*泞羅ʘ Ⱦķ瀊垰7ã\")",
|
||||
"jwks": {
|
||||
"keys": [
|
||||
{
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
"x": "nK9xgX_iN7u3u_i8YOO7ZRT_WK028Vd_nhtsUu7Eo6E",
|
||||
"x5u": {
|
||||
"Scheme": "",
|
||||
"Opaque": "",
|
||||
"User": null,
|
||||
"Host": "",
|
||||
"Path": "",
|
||||
"RawPath": "",
|
||||
"ForceQuery": false,
|
||||
"RawQuery": "",
|
||||
"Fragment": "",
|
||||
"RawFragment": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
"x": "UbbswQgzWhfGCRlwQmMp6fw_HoIoqkIaKT-2XN2fuYU",
|
||||
"x5u": {
|
||||
"Scheme": "",
|
||||
"Opaque": "",
|
||||
"User": null,
|
||||
"Host": "",
|
||||
"Path": "",
|
||||
"RawPath": "",
|
||||
"ForceQuery": false,
|
||||
"RawQuery": "",
|
||||
"Fragment": "",
|
||||
"RawFragment": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"token_endpoint_auth_method": "ƿʥǟȒ伉\u003cx¹T鼓c吏",
|
||||
"request_uris": [
|
||||
"Ć捘j]=谅ʑɑɮ$Ól4Ȟ",
|
||||
",Q7钎漡臧n"
|
||||
],
|
||||
"request_object_signing_alg": "3@¡廜+v,淬Ʋ4Dʧ呩锏緍场",
|
||||
"token_endpoint_auth_signing_alg": "(ưƓǴ罷ǹ~]ea胠"
|
||||
},
|
||||
"scopes": [
|
||||
"ĩv絹b垇IŕĩǀŻQ'k頂箨J-a稆",
|
||||
"啶#昏Q遐*\\髎bŸ"
|
||||
"ĩv絹b垇IŕĩǀŻQ'k頂箨J-a稆",
|
||||
"啶#昏Q遐*\\髎bŸ"
|
||||
],
|
||||
"grantedScopes": [
|
||||
"慂UFƼĮǡ鑻Z"
|
||||
"慂UFƼĮǡ鑻Z"
|
||||
],
|
||||
"form": {
|
||||
"褾攚ŝlĆ厦駳骪l拁乖¡J¿Ƈ妔": [
|
||||
"懧¥ɂĵ~Čyʊ恀c\"NJřðȿ/",
|
||||
"裢?霃谥vƘ:ƿ/濔Aʉ<",
|
||||
"ȭ$奍囀Dž悷鵱民撲ʓeŘ嬀j¤"
|
||||
],
|
||||
"诞": [
|
||||
"狲N<Cq罉ZPſĝEK郊©l",
|
||||
"餚LJ/ɷȑ潠[ĝU噤'pX ",
|
||||
"Y妶ǵ!ȁu狍ɶȳsčɦƦ诱"
|
||||
]
|
||||
"褾攚ŝlĆ厦駳骪l拁乖¡J¿Ƈ妔": [
|
||||
"懧¥ɂĵ~Čyʊ恀c\"NJřðȿ/",
|
||||
"裢?霃谥vƘ:ƿ/濔Aʉ\u003c",
|
||||
"ȭ$奍囀Dž悷鵱民撲ʓeŘ嬀j¤"
|
||||
],
|
||||
"诞": [
|
||||
"狲N\u003cCq罉ZPſĝEK郊©l",
|
||||
"餚LJ/ɷȑ潠[ĝU噤'pX ",
|
||||
"Y妶ǵ!ȁu狍ɶȳsčɦƦ诱"
|
||||
]
|
||||
},
|
||||
"session": {
|
||||
"Claims": {
|
||||
"JTI": "攬林Ñz焁糳¿o>Q鱙翑ȲŻ",
|
||||
"Issuer": "锰劝旣樎Ȱ鍌#ȳńƩŴȭ",
|
||||
"Subject": "绝TFNJĆw宵ɚeY48珎²",
|
||||
"Audience": [
|
||||
"éã越|j¦鲶H股ƲLŋZ-{5£踉4"
|
||||
],
|
||||
"Nonce": "5^驜Ŗ~ů崧軒q腟u尿",
|
||||
"ExpiresAt": "2065-11-30T13:47:03.613000626Z",
|
||||
"IssuedAt": "1976-02-22T09:57:20.479850437Z",
|
||||
"RequestedAt": "2016-04-13T04:18:53.648949323Z",
|
||||
"AuthTime": "2098-07-12T04:38:54.034043015Z",
|
||||
"AccessTokenHash": "嫯R",
|
||||
"AuthenticationContextClassReference": "¤'+ʣ",
|
||||
"AuthenticationMethodsReference": "L&ɽ艄ʬʏ",
|
||||
"CodeHash": "ğǫ\\aȊ4ț髄Al",
|
||||
"Extra": {
|
||||
"PƢ曰": {
|
||||
"ĸŴB岺Ð嫹Sx镯荫ő": [
|
||||
843216989
|
||||
],
|
||||
"疂ư墫ɓ": {
|
||||
"\\BRë_g\"ʎ啴SƇMǃļ": {
|
||||
"ʦ4": false
|
||||
},
|
||||
"鶡萷ɵ啜s攦": null
|
||||
}
|
||||
},
|
||||
"曓蓳n匟鯘磹*金爃鶴滱ůĮǐ_c3#": 2520197933
|
||||
}
|
||||
},
|
||||
"Headers": {
|
||||
"Extra": {
|
||||
"寱ĊƑ÷Ƒ螞费Ďğ~劰û橸ɽ銐ƭ?}": {
|
||||
"ȜʁɁ;Bd謺錳4帳ŅǃĊd": {
|
||||
"翢砜Fȏl鐉诳DT=3骜": {
|
||||
"ų厷ɁOƪ穋嶿鳈恱va|载ǰɱ汶C": false
|
||||
},
|
||||
"鸨EJ毕懴řĬń戹%c": null
|
||||
"fosite": {
|
||||
"Claims": {
|
||||
"JTI": "u妔隤ʑƍš駎竪0ɔ闏À1",
|
||||
"Issuer": "麤ã桒嘞\\摗Ǘū稖咾鎅ǸÖ绝TF",
|
||||
"Subject": "巽ēđų蓼tùZ蛆鬣a\"ÙǞ0觢Û±",
|
||||
"Audience": [
|
||||
"H股ƲL",
|
||||
"肟v\u0026đehpƧ",
|
||||
"5^驜Ŗ~ů崧軒q腟u尿"
|
||||
],
|
||||
"Nonce": "ğ",
|
||||
"ExpiresAt": "2016-11-22T21:33:58.460521133Z",
|
||||
"IssuedAt": "1990-07-25T23:42:07.055978334Z",
|
||||
"RequestedAt": "1971-01-30T00:23:36.377684025Z",
|
||||
"AuthTime": "2088-11-09T12:09:14.051840239Z",
|
||||
"AccessTokenHash": "蕖¤'+ʣȍ瓁U4鞀",
|
||||
"AuthenticationContextClassReference": "ʏÑęN\u003c_z",
|
||||
"AuthenticationMethodsReference": "ț髄A",
|
||||
"CodeHash": "4磔_袻vÓG-壧丵礴鋈k蟵pAɂʅ",
|
||||
"Extra": {
|
||||
"#\u0026PƢ曰l騌蘙螤\\阏Đ镴Ƥm蔻ǭ\\鿞": 1677215584,
|
||||
"Y\u0026鶡萷ɵ啜s攦Ɩïdnǔ": {
|
||||
",t猟i\u0026\u0026Q@ǤǟǗǪ飘ȱF?Ƈ": {
|
||||
"~劰û橸ɽ銐ƭ?}H": null,
|
||||
"癑勦e骲v0H晦XŘO溪V蔓": {
|
||||
"碼Ǫ": false
|
||||
}
|
||||
},
|
||||
"钻煐ɨəÅDČ{Ȩʦ4撎": [
|
||||
3684968178
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"室癑勦e骲v0H晦XŘO溪V蔓Ȍ+~ē": [
|
||||
954647573
|
||||
]
|
||||
},
|
||||
"麈ƵDǀ\\郂üţ垂": 1572524915
|
||||
"Headers": {
|
||||
"Extra": {
|
||||
"ĊdŘ鸨EJ毕懴řĬń戹": {
|
||||
"诳DT=3骜Ǹ,": {
|
||||
"\u003e": {
|
||||
"ǰ": false
|
||||
},
|
||||
"ɁOƪ穋嶿鳈恱va": null
|
||||
},
|
||||
"豑觳翢砜Fȏl": [
|
||||
927958776
|
||||
]
|
||||
},
|
||||
"埅ȜʁɁ;Bd謺錳4帳Ņ": 388005986
|
||||
}
|
||||
},
|
||||
"ExpiresAt": {
|
||||
"C]ɲ'=ĸ闒NȢȰ.醋": "1970-07-19T18:03:29.902062193Z",
|
||||
"fɤȆʪ融ƆuŤn": "2064-01-24T20:34:16.593152073Z",
|
||||
"爣縗ɦüHêQ仏1ő": "2102-03-17T06:24:40.256846902Z"
|
||||
},
|
||||
"Username": "韁臯氃妪婝rȤ\"h丬鎒ơ娻}ɼƟ",
|
||||
"Subject": "闺髉龳ǽÙ龦O亾EW莛8嘶×"
|
||||
},
|
||||
"custom": {
|
||||
"providerUID": "鵮碡ʯiŬŽ非Ĝ眧Ĭ葜SŦ餧Ĭ倏4",
|
||||
"providerName": "nŐǛ3",
|
||||
"providerType": "闣ʬ橳(ý綃ʃʚƟ覣k眐4Ĉt",
|
||||
"oidc": {
|
||||
"upstreamRefreshToken": "嵽痊w©Ź榨Q|ôɵt毇妬"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExpiresAt": {
|
||||
"'=ĸ闒NȢȰ.醋fʜ": "2031-10-18T22:07:34.950803105Z",
|
||||
"ɦüHêQ仏1őƖ2Ė暮唍ǞʜƢú4": "2049-05-13T15:27:20.968432454Z"
|
||||
},
|
||||
"Username": "+韁臯氃妪婝rȤ\"h丬鎒ơ娻}ɼƟȥE",
|
||||
"Subject": "龳ǽÙ龦O亾EW莛8嘶×姮c恭企"
|
||||
},
|
||||
"requestedAudience": [
|
||||
"邖ɐ5檄¬",
|
||||
"Ĭ葜SŦ餧Ĭ倏4ĵ嶼仒篻ɥ闣ʬ橳(ý綃"
|
||||
"6鉢緋uƴŤȱʀļÂ?墖\u003cƬb獭潜Ʃ饾"
|
||||
],
|
||||
"grantedAudience": [
|
||||
"ʚƟ覣k眐4ĈtC嵽痊w©Ź榨Q|ô",
|
||||
"猊Ia瓕巈環_ɑ彨ƍ蛊ʚ£:設虝2"
|
||||
"|鬌R蜚蠣麹概÷驣7Ʀ澉1æɽ誮rʨ鷞"
|
||||
]
|
||||
},
|
||||
"version": "1"
|
||||
}`
|
||||
},
|
||||
"version": "2"
|
||||
}`
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/oauth2"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
@ -34,6 +33,8 @@ import (
|
||||
|
||||
"go.pinniped.dev/internal/fositestorage"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
const namespace = "test-ns"
|
||||
@ -62,7 +63,7 @@ func TestAuthorizationCodeStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"active":true,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"active":true,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/authcode",
|
||||
@ -81,7 +82,7 @@ func TestAuthorizationCodeStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"active":false,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"active":false,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/authcode",
|
||||
@ -113,16 +114,10 @@ func TestAuthorizationCodeStorage(t *testing.T) {
|
||||
TokenEndpointAuthSigningAlgorithm: "",
|
||||
},
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: &openid.DefaultSession{
|
||||
Claims: nil,
|
||||
Headers: nil,
|
||||
ExpiresAt: nil,
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
RequestedAudience: nil,
|
||||
GrantedAudience: nil,
|
||||
}
|
||||
@ -136,6 +131,8 @@ func TestAuthorizationCodeStorage(t *testing.T) {
|
||||
err = storage.InvalidateAuthorizeCodeSession(ctx, "fancy-signature")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
testutil.LogActualJSONFromUpdateAction(t, client, 3) // makes it easier to update expected values when needed
|
||||
require.Equal(t, wantActions, client.Actions())
|
||||
|
||||
// Doing a Get on an invalidated session should still return the session, but also return an error.
|
||||
@ -173,7 +170,7 @@ func TestInvalidateWhenConflictOnUpdateHappens(t *testing.T) {
|
||||
request := &fosite.Request{
|
||||
ID: "some-request-id",
|
||||
Client: &clientregistry.Client{},
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
}
|
||||
err := storage.CreateAuthorizeCodeSession(ctx, "fancy-signature", request)
|
||||
require.NoError(t, err)
|
||||
@ -193,7 +190,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"not-the-right-version", "active": true}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1"},"version":"not-the-right-version","active": true}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/authcode",
|
||||
@ -203,7 +200,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
|
||||
_, err = storage.GetAuthorizeCodeSession(ctx, "fancy-signature", nil)
|
||||
|
||||
require.EqualError(t, err, "authorization request data has wrong version: authorization code session for fancy-signature has version not-the-right-version instead of 1")
|
||||
require.EqualError(t, err, "authorization request data has wrong version: authorization code session for fancy-signature has version not-the-right-version instead of 2")
|
||||
}
|
||||
|
||||
func TestNilSessionRequest(t *testing.T) {
|
||||
@ -218,7 +215,7 @@ func TestNilSessionRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value", "version":"1", "active": true}`),
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value", "version":"2", "active": true}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/authcode",
|
||||
@ -246,10 +243,10 @@ func TestCreateWithWrongRequesterDataTypes(t *testing.T) {
|
||||
Client: &clientregistry.Client{},
|
||||
}
|
||||
err := storage.CreateAuthorizeCodeSession(ctx, "signature-doesnt-matter", request)
|
||||
require.EqualError(t, err, "requester's session must be of type openid.DefaultSession")
|
||||
require.EqualError(t, err, "requester's session must be of type PinnipedSession")
|
||||
|
||||
request = &fosite.Request{
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
Client: nil,
|
||||
}
|
||||
err = storage.CreateAuthorizeCodeSession(ctx, "signature-doesnt-matter", request)
|
||||
@ -274,7 +271,7 @@ func TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession(t *testing.T) {
|
||||
|
||||
// checked above
|
||||
defaultClient := validSession.Request.Client.(*clientregistry.Client)
|
||||
defaultSession := validSession.Request.Session.(*openid.DefaultSession)
|
||||
pinnipedSession := validSession.Request.Session.(*psession.PinnipedSession)
|
||||
|
||||
// makes it easier to use a raw string
|
||||
replacer := strings.NewReplacer("`", "a")
|
||||
@ -297,12 +294,12 @@ func TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession(t *testing.T) {
|
||||
*fc = defaultClient
|
||||
},
|
||||
func(fs *fosite.Session, c fuzz.Continue) {
|
||||
c.Fuzz(defaultSession)
|
||||
*fs = defaultSession
|
||||
c.Fuzz(pinnipedSession)
|
||||
*fs = pinnipedSession
|
||||
},
|
||||
|
||||
// these types contain an interface{} that we need to handle
|
||||
// this is safe because we explicitly provide the openid.DefaultSession concrete type
|
||||
// this is safe because we explicitly provide the PinnipedSession concrete type
|
||||
func(value *map[string]interface{}, c fuzz.Continue) {
|
||||
// cover all the JSON data types just in case
|
||||
*value = map[string]interface{}{
|
||||
@ -382,7 +379,7 @@ func TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession(t *testing.T) {
|
||||
|
||||
// set these to match CreateAuthorizeCodeSession so that .JSONEq works
|
||||
validSession.Active = true
|
||||
validSession.Version = "1"
|
||||
validSession.Version = "2"
|
||||
|
||||
validSessionJSONBytes, err := json.MarshalIndent(validSession, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
@ -5,16 +5,16 @@ package fositestorage
|
||||
|
||||
import (
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
|
||||
"go.pinniped.dev/internal/constable"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrInvalidRequestType = constable.Error("requester must be of type fosite.Request")
|
||||
ErrInvalidClientType = constable.Error("requester's client must be of type clientregistry.Client")
|
||||
ErrInvalidSessionType = constable.Error("requester's session must be of type openid.DefaultSession")
|
||||
ErrInvalidSessionType = constable.Error("requester's session must be of type PinnipedSession")
|
||||
StorageRequestIDLabelName = "storage.pinniped.dev/request-id" //nolint:gosec // this is not a credential
|
||||
)
|
||||
|
||||
@ -27,7 +27,7 @@ func ValidateAndExtractAuthorizeRequest(requester fosite.Requester) (*fosite.Req
|
||||
if !ok2 {
|
||||
return nil, ErrInvalidClientType
|
||||
}
|
||||
_, ok3 := request.Session.(*openid.DefaultSession)
|
||||
_, ok3 := request.Session.(*psession.PinnipedSession)
|
||||
if !ok3 {
|
||||
return nil, ErrInvalidSessionType
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"go.pinniped.dev/internal/crud"
|
||||
"go.pinniped.dev/internal/fositestorage"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -27,7 +28,7 @@ const (
|
||||
ErrInvalidOIDCRequestData = constable.Error("oidc request data must be present")
|
||||
ErrMalformedAuthorizationCode = constable.Error("malformed authorization code")
|
||||
|
||||
oidcStorageVersion = "1"
|
||||
oidcStorageVersion = "2"
|
||||
)
|
||||
|
||||
var _ openid.OpenIDConnectRequestStorage = &openIDConnectRequestStorage{}
|
||||
@ -112,7 +113,7 @@ func newValidEmptyOIDCSession() *session {
|
||||
return &session{
|
||||
Request: &fosite.Request{
|
||||
Client: &clientregistry.Client{},
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import (
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
const namespace = "test-ns"
|
||||
@ -50,7 +52,7 @@ func TestOpenIdConnectStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/oidc",
|
||||
@ -84,16 +86,10 @@ func TestOpenIdConnectStorage(t *testing.T) {
|
||||
TokenEndpointAuthSigningAlgorithm: "",
|
||||
},
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: &openid.DefaultSession{
|
||||
Claims: nil,
|
||||
Headers: nil,
|
||||
ExpiresAt: nil,
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
RequestedAudience: nil,
|
||||
GrantedAudience: nil,
|
||||
}
|
||||
@ -107,6 +103,7 @@ func TestOpenIdConnectStorage(t *testing.T) {
|
||||
err = storage.DeleteOpenIDConnectSession(ctx, "fancy-code.fancy-signature")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
require.Equal(t, wantActions, client.Actions())
|
||||
}
|
||||
|
||||
@ -130,7 +127,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1"},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/oidc",
|
||||
@ -140,7 +137,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
|
||||
_, err = storage.GetOpenIDConnectSession(ctx, "fancy-code.fancy-signature", nil)
|
||||
|
||||
require.EqualError(t, err, "oidc request data has wrong version: oidc session for fancy-signature has version not-the-right-version instead of 1")
|
||||
require.EqualError(t, err, "oidc request data has wrong version: oidc session for fancy-signature has version not-the-right-version instead of 2")
|
||||
}
|
||||
|
||||
func TestNilSessionRequest(t *testing.T) {
|
||||
@ -155,7 +152,7 @@ func TestNilSessionRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/oidc",
|
||||
@ -183,10 +180,10 @@ func TestCreateWithWrongRequesterDataTypes(t *testing.T) {
|
||||
Client: &clientregistry.Client{},
|
||||
}
|
||||
err := storage.CreateOpenIDConnectSession(ctx, "authcode.signature-doesnt-matter", request)
|
||||
require.EqualError(t, err, "requester's session must be of type openid.DefaultSession")
|
||||
require.EqualError(t, err, "requester's session must be of type PinnipedSession")
|
||||
|
||||
request = &fosite.Request{
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
Client: nil,
|
||||
}
|
||||
err = storage.CreateOpenIDConnectSession(ctx, "authcode.signature-doesnt-matter", request)
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/ory/fosite/handler/pkce"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
@ -18,6 +17,7 @@ import (
|
||||
"go.pinniped.dev/internal/crud"
|
||||
"go.pinniped.dev/internal/fositestorage"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -26,7 +26,7 @@ const (
|
||||
ErrInvalidPKCERequestVersion = constable.Error("pkce request data has wrong version")
|
||||
ErrInvalidPKCERequestData = constable.Error("pkce request data must be present")
|
||||
|
||||
pkceStorageVersion = "1"
|
||||
pkceStorageVersion = "2"
|
||||
)
|
||||
|
||||
var _ pkce.PKCERequestStorage = &pkceStorage{}
|
||||
@ -96,7 +96,7 @@ func newValidEmptyPKCESession() *session {
|
||||
return &session{
|
||||
Request: &fosite.Request{
|
||||
Client: &clientregistry.Client{},
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/ory/fosite/handler/pkce"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -23,6 +22,8 @@ import (
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
const namespace = "test-ns"
|
||||
@ -51,7 +52,7 @@ func TestPKCEStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/pkce",
|
||||
@ -85,16 +86,10 @@ func TestPKCEStorage(t *testing.T) {
|
||||
TokenEndpointAuthSigningAlgorithm: "",
|
||||
},
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: &openid.DefaultSession{
|
||||
Claims: nil,
|
||||
Headers: nil,
|
||||
ExpiresAt: nil,
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
RequestedAudience: nil,
|
||||
GrantedAudience: nil,
|
||||
}
|
||||
@ -108,6 +103,7 @@ func TestPKCEStorage(t *testing.T) {
|
||||
err = storage.DeletePKCERequestSession(ctx, "fancy-signature")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
require.Equal(t, wantActions, client.Actions())
|
||||
}
|
||||
|
||||
@ -134,7 +130,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1"},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/pkce",
|
||||
@ -144,7 +140,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
|
||||
_, err = storage.GetPKCERequestSession(ctx, "fancy-signature", nil)
|
||||
|
||||
require.EqualError(t, err, "pkce request data has wrong version: pkce session for fancy-signature has version not-the-right-version instead of 1")
|
||||
require.EqualError(t, err, "pkce request data has wrong version: pkce session for fancy-signature has version not-the-right-version instead of 2")
|
||||
}
|
||||
|
||||
func TestNilSessionRequest(t *testing.T) {
|
||||
@ -162,7 +158,7 @@ func TestNilSessionRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/pkce",
|
||||
@ -190,10 +186,10 @@ func TestCreateWithWrongRequesterDataTypes(t *testing.T) {
|
||||
Client: &clientregistry.Client{},
|
||||
}
|
||||
err := storage.CreatePKCERequestSession(ctx, "signature-doesnt-matter", request)
|
||||
require.EqualError(t, err, "requester's session must be of type openid.DefaultSession")
|
||||
require.EqualError(t, err, "requester's session must be of type PinnipedSession")
|
||||
|
||||
request = &fosite.Request{
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
Client: nil,
|
||||
}
|
||||
err = storage.CreatePKCERequestSession(ctx, "signature-doesnt-matter", request)
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/oauth2"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
@ -18,6 +17,7 @@ import (
|
||||
"go.pinniped.dev/internal/crud"
|
||||
"go.pinniped.dev/internal/fositestorage"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -26,7 +26,7 @@ const (
|
||||
ErrInvalidRefreshTokenRequestVersion = constable.Error("refresh token request data has wrong version")
|
||||
ErrInvalidRefreshTokenRequestData = constable.Error("refresh token request data must be present")
|
||||
|
||||
refreshTokenStorageVersion = "1"
|
||||
refreshTokenStorageVersion = "2"
|
||||
)
|
||||
|
||||
type RevocationStorage interface {
|
||||
@ -110,7 +110,7 @@ func newValidEmptyRefreshTokenSession() *session {
|
||||
return &session{
|
||||
Request: &fosite.Request{
|
||||
Client: &clientregistry.Client{},
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@ -22,6 +21,8 @@ import (
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
const namespace = "test-ns"
|
||||
@ -50,7 +51,7 @@ func TestRefreshTokenStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/refresh-token",
|
||||
@ -84,16 +85,10 @@ func TestRefreshTokenStorage(t *testing.T) {
|
||||
TokenEndpointAuthSigningAlgorithm: "",
|
||||
},
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: &openid.DefaultSession{
|
||||
Claims: nil,
|
||||
Headers: nil,
|
||||
ExpiresAt: nil,
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
RequestedScope: nil,
|
||||
GrantedScope: nil,
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
RequestedAudience: nil,
|
||||
GrantedAudience: nil,
|
||||
}
|
||||
@ -107,6 +102,7 @@ func TestRefreshTokenStorage(t *testing.T) {
|
||||
err = storage.DeleteRefreshTokenSession(ctx, "fancy-signature")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
require.Equal(t, wantActions, client.Actions())
|
||||
}
|
||||
|
||||
@ -125,7 +121,7 @@ func TestRefreshTokenStorageRevocation(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/refresh-token",
|
||||
@ -151,11 +147,8 @@ func TestRefreshTokenStorageRevocation(t *testing.T) {
|
||||
TokenEndpointAuthMethod: "something",
|
||||
},
|
||||
},
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: &openid.DefaultSession{
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
Form: url.Values{"key": []string{"val"}},
|
||||
Session: testutil.NewFakePinnipedSession(),
|
||||
}
|
||||
err := storage.CreateRefreshTokenSession(ctx, "fancy-signature", request)
|
||||
require.NoError(t, err)
|
||||
@ -164,6 +157,7 @@ func TestRefreshTokenStorageRevocation(t *testing.T) {
|
||||
err = storage.RevokeRefreshToken(ctx, "abcd-1")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
require.Equal(t, wantActions, client.Actions())
|
||||
}
|
||||
|
||||
@ -190,7 +184,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"requestedAudience":null,"grantedAudience":null},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1"},"version":"not-the-right-version"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/refresh-token",
|
||||
@ -200,7 +194,7 @@ func TestWrongVersion(t *testing.T) {
|
||||
|
||||
_, err = storage.GetRefreshTokenSession(ctx, "fancy-signature", nil)
|
||||
|
||||
require.EqualError(t, err, "refresh token request data has wrong version: refresh token session for fancy-signature has version not-the-right-version instead of 1")
|
||||
require.EqualError(t, err, "refresh token request data has wrong version: refresh token session for fancy-signature has version not-the-right-version instead of 2")
|
||||
}
|
||||
|
||||
func TestNilSessionRequest(t *testing.T) {
|
||||
@ -218,7 +212,7 @@ func TestNilSessionRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"1"}`),
|
||||
"pinniped-storage-data": []byte(`{"nonsense-key": "nonsense-value","version":"2"}`),
|
||||
"pinniped-storage-version": []byte("1"),
|
||||
},
|
||||
Type: "storage.pinniped.dev/refresh-token",
|
||||
@ -246,10 +240,10 @@ func TestCreateWithWrongRequesterDataTypes(t *testing.T) {
|
||||
Client: &clientregistry.Client{},
|
||||
}
|
||||
err := storage.CreateRefreshTokenSession(ctx, "signature-doesnt-matter", request)
|
||||
require.EqualError(t, err, "requester's session must be of type openid.DefaultSession")
|
||||
require.EqualError(t, err, "requester's session must be of type PinnipedSession")
|
||||
|
||||
request = &fosite.Request{
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
Client: nil,
|
||||
}
|
||||
err = storage.CreateRefreshTokenSession(ctx, "signature-doesnt-matter", request)
|
||||
@ -261,7 +255,7 @@ func TestCreateWithoutRequesterID(t *testing.T) {
|
||||
|
||||
request := &fosite.Request{
|
||||
ID: "", // empty ID
|
||||
Session: &openid.DefaultSession{},
|
||||
Session: &psession.PinnipedSession{},
|
||||
Client: &clientregistry.Client{},
|
||||
}
|
||||
err := storage.CreateRefreshTokenSession(ctx, "signature-doesnt-matter", request)
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"go.pinniped.dev/internal/oidc/downstreamsession"
|
||||
"go.pinniped.dev/internal/oidc/provider"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||
"go.pinniped.dev/pkg/oidcclient/pkce"
|
||||
)
|
||||
@ -173,12 +174,14 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
_, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, &openid.DefaultSession{
|
||||
Claims: &jwt.IDTokenClaims{
|
||||
// Temporary claim values to allow `NewAuthorizeResponse` to perform other OIDC validations.
|
||||
Subject: "none",
|
||||
AuthTime: now,
|
||||
RequestedAt: now,
|
||||
_, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, &psession.PinnipedSession{
|
||||
Fosite: &openid.DefaultSession{
|
||||
Claims: &jwt.IDTokenClaims{
|
||||
// Temporary claim values to allow `NewAuthorizeResponse` to perform other OIDC validations.
|
||||
Subject: "none",
|
||||
AuthTime: now,
|
||||
RequestedAt: now,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"go.pinniped.dev/internal/oidc"
|
||||
"go.pinniped.dev/internal/oidc/provider"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,19 +36,21 @@ const (
|
||||
)
|
||||
|
||||
// MakeDownstreamSession creates a downstream OIDC session.
|
||||
func MakeDownstreamSession(subject string, username string, groups []string) *openid.DefaultSession {
|
||||
func MakeDownstreamSession(subject string, username string, groups []string) *psession.PinnipedSession {
|
||||
now := time.Now().UTC()
|
||||
openIDSession := &openid.DefaultSession{
|
||||
Claims: &jwt.IDTokenClaims{
|
||||
Subject: subject,
|
||||
RequestedAt: now,
|
||||
AuthTime: now,
|
||||
openIDSession := &psession.PinnipedSession{
|
||||
Fosite: &openid.DefaultSession{
|
||||
Claims: &jwt.IDTokenClaims{
|
||||
Subject: subject,
|
||||
RequestedAt: now,
|
||||
AuthTime: now,
|
||||
},
|
||||
},
|
||||
}
|
||||
if groups == nil {
|
||||
groups = []string{}
|
||||
}
|
||||
openIDSession.Claims.Extra = map[string]interface{}{
|
||||
openIDSession.IDTokenClaims().Extra = map[string]interface{}{
|
||||
oidc.DownstreamUsernameClaim: username,
|
||||
oidc.DownstreamGroupsClaim: groups,
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package token provides a handler for the OIDC token endpoint.
|
||||
@ -8,19 +8,19 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
|
||||
"go.pinniped.dev/internal/httputil/httperr"
|
||||
"go.pinniped.dev/internal/oidc"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
func NewHandler(
|
||||
oauthHelper fosite.OAuth2Provider,
|
||||
) http.Handler {
|
||||
return httperr.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
var session openid.DefaultSession
|
||||
accessRequest, err := oauthHelper.NewAccessRequest(r.Context(), r, &session)
|
||||
session := psession.NewPinnipedSession()
|
||||
accessRequest, err := oauthHelper.NewAccessRequest(r.Context(), r, session)
|
||||
if err != nil {
|
||||
plog.Info("token request error", oidc.FositeErrorForLog(err)...)
|
||||
oauthHelper.WriteAccessError(w, accessRequest, err)
|
||||
|
@ -46,6 +46,7 @@ import (
|
||||
"go.pinniped.dev/internal/here"
|
||||
"go.pinniped.dev/internal/oidc"
|
||||
"go.pinniped.dev/internal/oidc/jwks"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
"go.pinniped.dev/internal/testutil/oidctestutil"
|
||||
)
|
||||
@ -58,7 +59,6 @@ const (
|
||||
goodNonce = "some-nonce-value-with-enough-bytes-to-exceed-min-allowed"
|
||||
goodSubject = "https://issuer?sub=some-subject"
|
||||
goodUsername = "some-username"
|
||||
goodGroups = "group1,groups2"
|
||||
|
||||
hmacSecret = "this needs to be at least 32 characters to meet entropy requirements"
|
||||
|
||||
@ -72,6 +72,8 @@ const (
|
||||
var (
|
||||
goodAuthTime = time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC)
|
||||
goodRequestedAtTime = time.Date(7, 6, 5, 4, 3, 2, 1, time.UTC)
|
||||
goodGroups = []string{"group1", "groups2"}
|
||||
expectedGoodGroups = []interface{}{"group1", "groups2"}
|
||||
|
||||
hmacSecretFunc = func() []byte {
|
||||
return []byte(hmacSecret)
|
||||
@ -813,7 +815,7 @@ func TestTokenExchange(t *testing.T) {
|
||||
require.Equal(t, goodSubject, tokenClaims["sub"])
|
||||
require.Equal(t, goodIssuer, tokenClaims["iss"])
|
||||
require.Equal(t, goodUsername, tokenClaims["username"])
|
||||
require.Equal(t, goodGroups, tokenClaims["groups"])
|
||||
require.Equal(t, expectedGoodGroups, tokenClaims["groups"])
|
||||
|
||||
// Also assert that some are the same as the original downstream ID token.
|
||||
requireClaimsAreEqual(t, "iss", claimsOfFirstIDToken, tokenClaims) // issuer
|
||||
@ -1358,18 +1360,25 @@ func makeOauthHelperWithNilPrivateJWTSigningKey(
|
||||
func simulateAuthEndpointHavingAlreadyRun(t *testing.T, authRequest *http.Request, oauthHelper fosite.OAuth2Provider) fosite.AuthorizeResponder {
|
||||
// We only set the fields in the session that Fosite wants us to set.
|
||||
ctx := context.Background()
|
||||
session := &openid.DefaultSession{
|
||||
Claims: &jwt.IDTokenClaims{
|
||||
Subject: goodSubject,
|
||||
RequestedAt: goodRequestedAtTime,
|
||||
AuthTime: goodAuthTime,
|
||||
Extra: map[string]interface{}{
|
||||
oidc.DownstreamUsernameClaim: goodUsername,
|
||||
oidc.DownstreamGroupsClaim: goodGroups,
|
||||
session := &psession.PinnipedSession{
|
||||
Fosite: &openid.DefaultSession{
|
||||
Claims: &jwt.IDTokenClaims{
|
||||
Subject: goodSubject,
|
||||
RequestedAt: goodRequestedAtTime,
|
||||
AuthTime: goodAuthTime,
|
||||
Extra: map[string]interface{}{
|
||||
oidc.DownstreamUsernameClaim: goodUsername,
|
||||
oidc.DownstreamGroupsClaim: goodGroups,
|
||||
},
|
||||
},
|
||||
Subject: "", // not used, note that callback_handler.go does not set this
|
||||
Username: "", // not used, note that callback_handler.go does not set this
|
||||
},
|
||||
Custom: &psession.PinnipedSessionData{
|
||||
OIDC: &psession.OIDCSessionData{
|
||||
UpstreamRefreshToken: "starting-fake-refresh-token",
|
||||
},
|
||||
},
|
||||
Subject: "", // not used, note that callback_handler.go does not set this
|
||||
Username: "", // not used, note that callback_handler.go does not set this
|
||||
}
|
||||
authRequester, err := oauthHelper.NewAuthorizeRequest(ctx, authRequest)
|
||||
require.NoError(t, err)
|
||||
@ -1588,19 +1597,19 @@ func requireValidStoredRequest(
|
||||
require.Equal(t, wantRequestForm, request.GetRequestForm()) // Fosite stores access token request without form
|
||||
|
||||
// Cast session to the type we think it should be.
|
||||
session, ok := request.GetSession().(*openid.DefaultSession)
|
||||
require.Truef(t, ok, "could not cast %T to %T", request.GetSession(), &openid.DefaultSession{})
|
||||
session, ok := request.GetSession().(*psession.PinnipedSession)
|
||||
require.Truef(t, ok, "could not cast %T to %T", request.GetSession(), &psession.PinnipedSession{})
|
||||
|
||||
// Assert that the session claims are what we think they should be, but only if we are doing OIDC.
|
||||
if contains(wantGrantedScopes, "openid") {
|
||||
claims := session.Claims
|
||||
claims := session.Fosite.Claims
|
||||
require.Empty(t, claims.JTI) // When claims.JTI is empty, Fosite will generate a UUID for this field.
|
||||
require.Equal(t, goodSubject, claims.Subject)
|
||||
|
||||
// Our custom claims from the authorize endpoint should still be set.
|
||||
require.Equal(t, map[string]interface{}{
|
||||
"username": goodUsername,
|
||||
"groups": goodGroups,
|
||||
"groups": expectedGoodGroups,
|
||||
}, claims.Extra)
|
||||
|
||||
// We are in charge of setting these fields. For the purpose of testing, we ensure that the
|
||||
@ -1610,7 +1619,7 @@ func requireValidStoredRequest(
|
||||
|
||||
// These fields will all be given good defaults by fosite at runtime and we only need to use them
|
||||
// if we want to override the default behaviors. We currently don't need to override these defaults,
|
||||
// so they do not end up being stored. Fosite sets its defaults at runtime in openid.DefaultSession's
|
||||
// so they do not end up being stored. Fosite sets its defaults at runtime in openid.DefaultStrategy's
|
||||
// GenerateIDToken() method.
|
||||
require.Empty(t, claims.Issuer)
|
||||
require.Empty(t, claims.Audience)
|
||||
@ -1630,11 +1639,11 @@ func requireValidStoredRequest(
|
||||
}
|
||||
|
||||
// Assert that the session headers are what we think they should be.
|
||||
headers := session.Headers
|
||||
headers := session.Fosite.Headers
|
||||
require.Empty(t, headers)
|
||||
|
||||
// Assert that the token expirations are what we think they should be.
|
||||
authCodeExpiresAt, ok := session.ExpiresAt[fosite.AuthorizeCode]
|
||||
authCodeExpiresAt, ok := session.Fosite.ExpiresAt[fosite.AuthorizeCode]
|
||||
require.True(t, ok, "expected session to hold expiration time for auth code")
|
||||
testutil.RequireTimeInDelta(
|
||||
t,
|
||||
@ -1644,7 +1653,7 @@ func requireValidStoredRequest(
|
||||
)
|
||||
|
||||
// OpenID Connect sessions do not store access token expiration information.
|
||||
accessTokenExpiresAt, ok := session.ExpiresAt[fosite.AccessToken]
|
||||
accessTokenExpiresAt, ok := session.Fosite.ExpiresAt[fosite.AccessToken]
|
||||
if wantAccessTokenExpiresAt {
|
||||
require.True(t, ok, "expected session to hold expiration time for access token")
|
||||
testutil.RequireTimeInDelta(
|
||||
@ -1658,8 +1667,8 @@ func requireValidStoredRequest(
|
||||
}
|
||||
|
||||
// We don't use these, so they should be empty.
|
||||
require.Empty(t, session.Username)
|
||||
require.Empty(t, session.Subject)
|
||||
require.Empty(t, session.Fosite.Username)
|
||||
require.Empty(t, session.Fosite.Subject)
|
||||
}
|
||||
|
||||
func requireGarbageCollectTimeInDelta(t *testing.T, tokenString string, typeLabel string, secrets v1.SecretInterface, wantExpirationTime time.Time, deltaTime time.Duration) {
|
||||
@ -1709,7 +1718,7 @@ func requireValidIDToken(
|
||||
IssuedAt int64 `json:"iat"`
|
||||
RequestedAt int64 `json:"rat"`
|
||||
AuthTime int64 `json:"auth_time"`
|
||||
Groups string `json:"groups"`
|
||||
Groups []string `json:"groups"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
|
99
internal/psession/pinniped_session.go
Normal file
99
internal/psession/pinniped_session.go
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package psession
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/mohae/deepcopy"
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/ory/fosite/token/jwt"
|
||||
)
|
||||
|
||||
// PinnipedSession is a session container which includes the fosite standard stuff plus custom Pinniped stuff.
|
||||
type PinnipedSession struct {
|
||||
// Delegate most things to the standard fosite OpenID JWT session.
|
||||
Fosite *openid.DefaultSession `json:"fosite,omitempty"`
|
||||
|
||||
// Custom Pinniped extensions to the session data.
|
||||
Custom *PinnipedSessionData `json:"custom,omitempty"`
|
||||
}
|
||||
|
||||
var _ openid.Session = &PinnipedSession{}
|
||||
|
||||
// PinnipedSessionData is the custom session data needed by Pinniped. It should be treated as a union type,
|
||||
// where the value of ProviderType decides which other fields to use.
|
||||
type PinnipedSessionData struct {
|
||||
// The Kubernetes resource UID of the identity provider CRD for the upstream IDP used to start this session.
|
||||
// This should be validated again upon downstream refresh to make sure that we are not refreshing against
|
||||
// a different identity provider CRD which just happens to have the same name.
|
||||
// This implies that when a user deletes an identity provider CRD, then the sessions that were started
|
||||
// using that identity provider will not be able to perform any more downstream refreshes.
|
||||
ProviderUID string `json:"providerUID"`
|
||||
|
||||
// The Kubernetes resource name of the identity provider CRD for the upstream IDP used to start this session.
|
||||
// Used during a downstream refresh to decide which upstream to refresh.
|
||||
// Also used to decide which of the pointer types below should be used.
|
||||
ProviderName string `json:"providerName"`
|
||||
|
||||
// The type of the identity provider for the upstream IDP used to start this session.
|
||||
// Used during a downstream refresh to decide which upstream to refresh.
|
||||
ProviderType string `json:"providerType"`
|
||||
|
||||
// Only used when ProviderType == "oidc".
|
||||
OIDC *OIDCSessionData `json:"oidc,omitempty"`
|
||||
}
|
||||
|
||||
// OIDCSessionData is the additional data needed by Pinniped when the upstream IDP is an OIDC provider.
|
||||
type OIDCSessionData struct {
|
||||
UpstreamRefreshToken string `json:"upstreamRefreshToken"`
|
||||
}
|
||||
|
||||
// NewPinnipedSession returns a new empty session.
|
||||
func NewPinnipedSession() *PinnipedSession {
|
||||
return &PinnipedSession{
|
||||
Fosite: &openid.DefaultSession{
|
||||
Claims: &jwt.IDTokenClaims{},
|
||||
Headers: &jwt.Headers{},
|
||||
},
|
||||
Custom: &PinnipedSessionData{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) Clone() fosite.Session {
|
||||
// Implementation copied from openid.DefaultSession's clone method.
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
return deepcopy.Copy(s).(fosite.Session)
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) SetExpiresAt(key fosite.TokenType, exp time.Time) {
|
||||
s.Fosite.SetExpiresAt(key, exp)
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) GetExpiresAt(key fosite.TokenType) time.Time {
|
||||
return s.Fosite.GetExpiresAt(key)
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) GetUsername() string {
|
||||
return s.Fosite.GetUsername()
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) SetSubject(subject string) {
|
||||
s.Fosite.SetSubject(subject)
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) GetSubject() string {
|
||||
return s.Fosite.GetSubject()
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) IDTokenHeaders() *jwt.Headers {
|
||||
return s.Fosite.IDTokenHeaders()
|
||||
}
|
||||
|
||||
func (s *PinnipedSession) IDTokenClaims() *jwt.IDTokenClaims {
|
||||
return s.Fosite.IDTokenClaims()
|
||||
}
|
@ -16,7 +16,6 @@ import (
|
||||
|
||||
coreosoidc "github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/oauth2"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
@ -31,6 +30,7 @@ import (
|
||||
pkce2 "go.pinniped.dev/internal/fositestorage/pkce"
|
||||
"go.pinniped.dev/internal/fositestoragei"
|
||||
"go.pinniped.dev/internal/oidc/provider"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||
"go.pinniped.dev/pkg/oidcclient/oidctypes"
|
||||
@ -563,7 +563,7 @@ func validateAuthcodeStorage(
|
||||
wantDownstreamRequestedScopes []string,
|
||||
wantDownstreamClientID string,
|
||||
wantDownstreamRedirectURI string,
|
||||
) (*fosite.Request, *openid.DefaultSession) {
|
||||
) (*fosite.Request, *psession.PinnipedSession) {
|
||||
t.Helper()
|
||||
|
||||
const (
|
||||
@ -591,16 +591,16 @@ func validateAuthcodeStorage(
|
||||
testutil.RequireTimeInDelta(t, time.Now(), storedRequestFromAuthcode.RequestedAt, timeComparisonFudgeFactor)
|
||||
|
||||
// We're not using these fields yet, so confirm that we did not set them (for now).
|
||||
require.Empty(t, storedSessionFromAuthcode.Subject)
|
||||
require.Empty(t, storedSessionFromAuthcode.Username)
|
||||
require.Empty(t, storedSessionFromAuthcode.Headers)
|
||||
require.Empty(t, storedSessionFromAuthcode.Fosite.Subject)
|
||||
require.Empty(t, storedSessionFromAuthcode.Fosite.Username)
|
||||
require.Empty(t, storedSessionFromAuthcode.Fosite.Headers)
|
||||
|
||||
// The authcode that we are issuing should be good for the length of time that we declare in the fosite config.
|
||||
testutil.RequireTimeInDelta(t, time.Now().Add(authCodeExpirationSeconds*time.Second), storedSessionFromAuthcode.ExpiresAt[fosite.AuthorizeCode], timeComparisonFudgeFactor)
|
||||
require.Len(t, storedSessionFromAuthcode.ExpiresAt, 1)
|
||||
testutil.RequireTimeInDelta(t, time.Now().Add(authCodeExpirationSeconds*time.Second), storedSessionFromAuthcode.Fosite.ExpiresAt[fosite.AuthorizeCode], timeComparisonFudgeFactor)
|
||||
require.Len(t, storedSessionFromAuthcode.Fosite.ExpiresAt, 1)
|
||||
|
||||
// Now confirm the ID token claims.
|
||||
actualClaims := storedSessionFromAuthcode.Claims
|
||||
actualClaims := storedSessionFromAuthcode.Fosite.Claims
|
||||
|
||||
// Check the user's identity, which are put into the downstream ID token's subject, username and groups claims.
|
||||
require.Equal(t, wantDownstreamIDTokenSubject, actualClaims.Subject)
|
||||
@ -642,7 +642,7 @@ func validatePKCEStorage(
|
||||
oauthStore fositestoragei.AllFositeStorage,
|
||||
storeKey string,
|
||||
storedRequestFromAuthcode *fosite.Request,
|
||||
storedSessionFromAuthcode *openid.DefaultSession,
|
||||
storedSessionFromAuthcode *psession.PinnipedSession,
|
||||
wantDownstreamPKCEChallenge, wantDownstreamPKCEChallengeMethod string,
|
||||
) {
|
||||
t.Helper()
|
||||
@ -667,7 +667,7 @@ func validateIDSessionStorage(
|
||||
oauthStore fositestoragei.AllFositeStorage,
|
||||
storeKey string,
|
||||
storedRequestFromAuthcode *fosite.Request,
|
||||
storedSessionFromAuthcode *openid.DefaultSession,
|
||||
storedSessionFromAuthcode *psession.PinnipedSession,
|
||||
wantDownstreamNonce string,
|
||||
) {
|
||||
t.Helper()
|
||||
@ -686,13 +686,13 @@ func validateIDSessionStorage(
|
||||
require.Equal(t, wantDownstreamNonce, storedRequestFromIDSession.Form.Get("nonce"))
|
||||
}
|
||||
|
||||
func castStoredAuthorizeRequest(t *testing.T, storedAuthorizeRequest fosite.Requester) (*fosite.Request, *openid.DefaultSession) {
|
||||
func castStoredAuthorizeRequest(t *testing.T, storedAuthorizeRequest fosite.Requester) (*fosite.Request, *psession.PinnipedSession) {
|
||||
t.Helper()
|
||||
|
||||
storedRequest, ok := storedAuthorizeRequest.(*fosite.Request)
|
||||
require.Truef(t, ok, "could not cast %T to %T", storedAuthorizeRequest, &fosite.Request{})
|
||||
storedSession, ok := storedAuthorizeRequest.GetSession().(*openid.DefaultSession)
|
||||
require.Truef(t, ok, "could not cast %T to %T", storedAuthorizeRequest.GetSession(), &openid.DefaultSession{})
|
||||
storedSession, ok := storedAuthorizeRequest.GetSession().(*psession.PinnipedSession)
|
||||
require.Truef(t, ok, "could not cast %T to %T", storedAuthorizeRequest.GetSession(), &psession.PinnipedSession{})
|
||||
|
||||
return storedRequest, storedSession
|
||||
}
|
||||
|
43
internal/testutil/psession.go
Normal file
43
internal/testutil/psession.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
testing2 "k8s.io/client-go/testing"
|
||||
|
||||
"go.pinniped.dev/internal/psession"
|
||||
)
|
||||
|
||||
func NewFakePinnipedSession() *psession.PinnipedSession {
|
||||
return &psession.PinnipedSession{
|
||||
Fosite: &openid.DefaultSession{
|
||||
Claims: nil,
|
||||
Headers: nil,
|
||||
ExpiresAt: nil,
|
||||
Username: "snorlax",
|
||||
Subject: "panda",
|
||||
},
|
||||
Custom: &psession.PinnipedSessionData{
|
||||
ProviderUID: "fake-provider-uid",
|
||||
ProviderType: "fake-provider-type",
|
||||
ProviderName: "fake-provider-name",
|
||||
OIDC: &psession.OIDCSessionData{
|
||||
UpstreamRefreshToken: "fake-upstream-refresh-token",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func LogActualJSONFromCreateAction(t *testing.T, client *fake.Clientset, actionIndex int) {
|
||||
t.Log("actual value of CreateAction secret data", string(client.Actions()[actionIndex].(testing2.CreateActionImpl).Object.(*v1.Secret).Data["pinniped-storage-data"]))
|
||||
}
|
||||
|
||||
func LogActualJSONFromUpdateAction(t *testing.T, client *fake.Clientset, actionIndex int) {
|
||||
t.Log("actual value of UpdateAction secret data", string(client.Actions()[actionIndex].(testing2.UpdateActionImpl).Object.(*v1.Secret).Data["pinniped-storage-data"]))
|
||||
}
|
Loading…
Reference in New Issue
Block a user