reorganize federation domain packages to be more intuitive

Co-authored-by: Benjamin A. Petersen <ben@benjaminapetersen.me>
This commit is contained in:
Ryan Richard 2023-06-22 15:12:33 -07:00
parent 3160b5bad1
commit 86c791b8a6
101 changed files with 401 additions and 377 deletions

View File

@ -26,7 +26,7 @@ import (
"go.pinniped.dev/internal/controller/conditionsutil"
"go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamldap"
)

View File

@ -29,9 +29,9 @@ import (
"go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/endpointaddr"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/mocks/mockldapconn"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/upstreamldap"
)
@ -2010,7 +2010,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
pinnipedInformers := pinnipedinformers.NewSharedInformerFactory(fakePinnipedClient, 0)
fakeKubeClient := fake.NewSimpleClientset(tt.inputSecrets...)
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
cache := provider.NewDynamicUpstreamIDPProvider()
cache := dynamicupstreamprovider.NewDynamicUpstreamIDPProvider()
cache.SetActiveDirectoryIdentityProviders([]upstreamprovider.UpstreamLDAPIdentityProviderI{
upstreamldap.New(upstreamldap.ProviderConfig{Name: "initial-entry"}),
})

View File

@ -25,8 +25,8 @@ import (
"go.pinniped.dev/internal/celtransformer"
pinnipedcontroller "go.pinniped.dev/internal/controller"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/plog"
)

View File

@ -27,8 +27,8 @@ import (
pinnipedfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
pinnipedinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/testutil"
)

View File

@ -20,7 +20,7 @@ import (
"go.pinniped.dev/internal/controller/conditionsutil"
"go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamldap"
)

View File

@ -28,9 +28,9 @@ import (
"go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/endpointaddr"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/mocks/mockldapconn"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/upstreamldap"
)
@ -1139,7 +1139,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
pinnipedInformers := pinnipedinformers.NewSharedInformerFactory(fakePinnipedClient, 0)
fakeKubeClient := fake.NewSimpleClientset(tt.inputSecrets...)
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
cache := provider.NewDynamicUpstreamIDPProvider()
cache := dynamicupstreamprovider.NewDynamicUpstreamIDPProvider()
cache.SetLDAPIdentityProviders([]upstreamprovider.UpstreamLDAPIdentityProviderI{
upstreamldap.New(upstreamldap.ProviderConfig{Name: "initial-entry"}),
})

View File

@ -21,7 +21,7 @@ import (
pinnipedcontroller "go.pinniped.dev/internal/controller"
"go.pinniped.dev/internal/controller/conditionsutil"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/oidcclientsecretstorage"
"go.pinniped.dev/internal/plog"
)

View File

@ -34,8 +34,8 @@ import (
"go.pinniped.dev/internal/controller/conditionsutil"
"go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/net/phttp"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamoidc"
)
@ -94,7 +94,7 @@ type UpstreamOIDCIdentityProviderICache interface {
SetOIDCIdentityProviders([]upstreamprovider.UpstreamOIDCIdentityProviderI)
}
// lruValidatorCache caches the *oidc.Provider associated with a particular issuer/TLS configuration.
// lruValidatorCache caches the *coreosoidc.Provider associated with a particular issuer/TLS configuration.
type lruValidatorCache struct{ cache *cache.Expiring }
type lruValidatorCacheEntry struct {

View File

@ -28,8 +28,8 @@ import (
pinnipedinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions"
"go.pinniped.dev/internal/certauthority"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"
@ -81,7 +81,7 @@ func TestOIDCUpstreamWatcherControllerFilterSecret(t *testing.T) {
pinnipedInformers := pinnipedinformers.NewSharedInformerFactory(fakePinnipedClient, 0)
fakeKubeClient := fake.NewSimpleClientset()
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
cache := provider.NewDynamicUpstreamIDPProvider()
cache := dynamicupstreamprovider.NewDynamicUpstreamIDPProvider()
cache.SetOIDCIdentityProviders([]upstreamprovider.UpstreamOIDCIdentityProviderI{
&upstreamoidc.ProviderConfig{Name: "initial-entry"},
})
@ -1416,7 +1416,7 @@ oidc: issuer did not match the issuer returned by provider, expected "` + testIs
fakeKubeClient := fake.NewSimpleClientset(tt.inputSecrets...)
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
testLog := testlogger.NewLegacy(t) //nolint:staticcheck // old test with lots of log statements
cache := provider.NewDynamicUpstreamIDPProvider()
cache := dynamicupstreamprovider.NewDynamicUpstreamIDPProvider()
cache.SetOIDCIdentityProviders([]upstreamprovider.UpstreamOIDCIdentityProviderI{
&upstreamoidc.ProviderConfig{Name: "initial-entry"},
})

View File

@ -16,7 +16,7 @@ import (
"go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamldap"
)

View File

@ -21,13 +21,13 @@ import (
pinnipedcontroller "go.pinniped.dev/internal/controller"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/fositestorage/accesstoken"
"go.pinniped.dev/internal/fositestorage/authorizationcode"
"go.pinniped.dev/internal/fositestorage/openidconnect"
"go.pinniped.dev/internal/fositestorage/pkce"
"go.pinniped.dev/internal/fositestorage/refreshtoken"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/psession"
)
@ -144,7 +144,7 @@ func (c *garbageCollectorController) Sync(ctx controllerlib.Context) error {
// cleaning them out of etcd storage.
fourHoursAgo := frozenClock.Now().Add(-4 * time.Hour)
nowIsLessThanFourHoursBeyondSecretGCTime := garbageCollectAfterTime.After(fourHoursAgo)
if errors.As(revokeErr, &provider.RetryableRevocationError{}) && nowIsLessThanFourHoursBeyondSecretGCTime {
if errors.As(revokeErr, &dynamicupstreamprovider.RetryableRevocationError{}) && nowIsLessThanFourHoursBeyondSecretGCTime {
// Hasn't been very long since secret expired, so skip deletion to try revocation again later.
plog.Trace("garbage collector keeping Secret to retry upstream OIDC token revocation later", logKV(secret)...)
continue

View File

@ -25,12 +25,12 @@ import (
clocktesting "k8s.io/utils/clock/testing"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/fositestorage/accesstoken"
"go.pinniped.dev/internal/fositestorage/authorizationcode"
"go.pinniped.dev/internal/fositestorage/refreshtoken"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"
@ -138,7 +138,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
// Defer starting the informers until the last possible moment so that the
// nested Before's can keep adding things to the informer caches.
var startInformersAndController = func(idpCache provider.DynamicUpstreamIDPProvider) {
var startInformersAndController = func(idpCache dynamicupstreamprovider.DynamicUpstreamIDPProvider) {
// Set this at the last second to allow for injection of server override.
subject = GarbageCollectorController(
idpCache,
@ -774,7 +774,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
WithName("upstream-oidc-provider-name").
WithResourceUID("upstream-oidc-provider-uid").
// make the upstream revocation fail in a retryable way
WithRevokeTokenError(provider.NewRetryableRevocationError(errors.New("some retryable upstream revocation error")))
WithRevokeTokenError(dynamicupstreamprovider.NewRetryableRevocationError(errors.New("some retryable upstream revocation error")))
idpListerBuilder := oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyOIDCUpstream.Build())
startInformersAndController(idpListerBuilder.BuildDynamicUpstreamIDPProvider())

View File

@ -1,4 +1,4 @@
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package clientregistry defines Pinniped's OAuth2/OIDC clients.
@ -18,7 +18,7 @@ import (
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
supervisorclient "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/oidcclientsecretstorage"
"go.pinniped.dev/internal/plog"
)

View File

@ -1,4 +1,4 @@
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package clientregistry
@ -21,7 +21,7 @@ import (
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/oidcclientsecretstorage"
"go.pinniped.dev/internal/testutil"
)

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package csp defines helpers related to HTML Content Security Policies.

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package csp

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package csrftoken

View File

@ -1,4 +1,4 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package csrftoken

View File

@ -20,9 +20,9 @@ import (
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/authenticators"
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/pkg/oidcclient/oidctypes"

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package dynamiccodec provides a type that can encode information using a just-in-time signing and
@ -10,7 +10,7 @@ import (
"github.com/gorilla/securecookie"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/federationdomain/oidc"
)
var _ oidc.Codec = &Codec{}

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package dynamiccodec

View File

@ -1,7 +1,7 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package provider
package dynamictlscertprovider
import (
"crypto/tls"

View File

@ -1,13 +1,13 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package provider
package dynamicupstreamprovider
import (
"fmt"
"sync"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
)
type DynamicUpstreamIDPProvider interface {

View File

@ -16,17 +16,17 @@ import (
"golang.org/x/oauth2"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/federationdomain/csrftoken"
"go.pinniped.dev/internal/federationdomain/downstreamsession"
"go.pinniped.dev/internal/federationdomain/endpoints/login"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/formposthtml"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/resolvedprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/httputil/securityheader"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/csrftoken"
"go.pinniped.dev/internal/oidc/downstreamsession"
"go.pinniped.dev/internal/oidc/login"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/oidc/provider/formposthtml"
"go.pinniped.dev/internal/oidc/provider/resolvedprovider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/pkg/oidcclient/nonce"

View File

@ -30,11 +30,12 @@ import (
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
"go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1"
"go.pinniped.dev/internal/authenticators"
"go.pinniped.dev/internal/federationdomain/csrftoken"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/storage"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/csrftoken"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"
@ -232,18 +233,18 @@ func TestAuthorizationEndpoint(t *testing.T) {
jwksProviderIsUnused := jwks.NewDynamicJWKSProvider()
timeoutsConfiguration := oidc.DefaultOIDCTimeoutsConfiguration()
createOauthHelperWithRealStorage := func(secretsClient v1.SecretInterface, oidcClientsClient v1alpha1.OIDCClientInterface) (fosite.OAuth2Provider, *oidc.KubeStorage) {
createOauthHelperWithRealStorage := func(secretsClient v1.SecretInterface, oidcClientsClient v1alpha1.OIDCClientInterface) (fosite.OAuth2Provider, *storage.KubeStorage) {
// Configure fosite the same way that the production code would when using Kube storage.
// Inject this into our test subject at the last second so we get a fresh storage for every test.
// Use lower minimum required bcrypt cost than we would use in production to keep unit the tests fast.
kubeOauthStore := oidc.NewKubeStorage(secretsClient, oidcClientsClient, timeoutsConfiguration, bcrypt.MinCost)
kubeOauthStore := storage.NewKubeStorage(secretsClient, oidcClientsClient, timeoutsConfiguration, bcrypt.MinCost)
return oidc.FositeOauth2Helper(kubeOauthStore, downstreamIssuer, hmacSecretFunc, jwksProviderIsUnused, timeoutsConfiguration), kubeOauthStore
}
createOauthHelperWithNullStorage := func(secretsClient v1.SecretInterface, oidcClientsClient v1alpha1.OIDCClientInterface) (fosite.OAuth2Provider, *oidc.NullStorage) {
createOauthHelperWithNullStorage := func(secretsClient v1.SecretInterface, oidcClientsClient v1alpha1.OIDCClientInterface) (fosite.OAuth2Provider, *storage.NullStorage) {
// Configure fosite the same way that the production code would, using NullStorage to turn off storage.
// Use lower minimum required bcrypt cost than we would use in production to keep unit the tests fast.
nullOauthStore := oidc.NewNullStorage(secretsClient, oidcClientsClient, bcrypt.MinCost)
nullOauthStore := storage.NewNullStorage(secretsClient, oidcClientsClient, bcrypt.MinCost)
return oidc.FositeOauth2Helper(nullOauthStore, downstreamIssuer, hmacSecretFunc, jwksProviderIsUnused, timeoutsConfiguration), nullOauthStore
}
@ -3175,7 +3176,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
},
}
runOneTestCase := func(t *testing.T, test testCase, subject http.Handler, kubeOauthStore *oidc.KubeStorage, supervisorClient *supervisorfake.Clientset, kubeClient *fake.Clientset, secretsClient v1.SecretInterface) {
runOneTestCase := func(t *testing.T, test testCase, subject http.Handler, kubeOauthStore *storage.KubeStorage, supervisorClient *supervisorfake.Clientset, kubeClient *fake.Clientset, secretsClient v1.SecretInterface) {
if test.kubeResources != nil {
test.kubeResources(t, supervisorClient, kubeClient)
}

View File

@ -10,12 +10,12 @@ import (
"github.com/ory/fosite"
"go.pinniped.dev/internal/federationdomain/downstreamsession"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/formposthtml"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/httputil/securityheader"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/downstreamsession"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/oidc/provider/formposthtml"
"go.pinniped.dev/internal/plog"
)

View File

@ -21,9 +21,10 @@ import (
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/storage"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"
@ -1451,7 +1452,7 @@ func TestCallbackEndpoint(t *testing.T) {
// Inject this into our test subject at the last second so we get a fresh storage for every test.
timeoutsConfiguration := oidc.DefaultOIDCTimeoutsConfiguration()
// Use lower minimum required bcrypt cost than we would use in production to keep unit the tests fast.
oauthStore := oidc.NewKubeStorage(secrets, oidcClientsClient, timeoutsConfiguration, bcrypt.MinCost)
oauthStore := storage.NewKubeStorage(secrets, oidcClientsClient, timeoutsConfiguration, bcrypt.MinCost)
hmacSecretFunc := func() []byte { return []byte("some secret - must have at least 32 bytes") }
require.GreaterOrEqual(t, len(hmacSecretFunc()), 32, "fosite requires that hmac secrets have at least 32 bytes")
jwksProviderIsUnused := jwks.NewDynamicJWKSProvider()

View File

@ -11,7 +11,7 @@ import (
"go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/federationdomain/oidc"
)
// Metadata holds all fields (that we care about) from the OpenID Provider Metadata section in the

View File

@ -10,8 +10,8 @@ import (
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc"
)
func TestDiscovery(t *testing.T) {

View File

@ -11,7 +11,7 @@ import (
"sort"
"go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
)
// NewHandler returns an http.Handler that serves the upstream IDP discovery endpoint.

View File

@ -10,8 +10,8 @@ import (
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/testutil/oidctestutil"
)

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package jwks

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package discovery provides a handler for the OIDC discovery endpoint.

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package jwks

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package login
@ -6,8 +6,8 @@ package login
import (
"net/http"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/login/loginhtml"
"go.pinniped.dev/internal/federationdomain/endpoints/login/loginhtml"
"go.pinniped.dev/internal/federationdomain/oidc"
)
const (

View File

@ -10,9 +10,9 @@ import (
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/idplister"
"go.pinniped.dev/internal/oidc/login/loginhtml"
"go.pinniped.dev/internal/federationdomain/endpoints/login/loginhtml"
"go.pinniped.dev/internal/federationdomain/idplister"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/testutil"
)

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package login
@ -8,11 +8,11 @@ import (
"net/url"
idpdiscoveryv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
"go.pinniped.dev/internal/federationdomain/endpoints/login/loginhtml"
"go.pinniped.dev/internal/federationdomain/formposthtml"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/httputil/securityheader"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/login/loginhtml"
"go.pinniped.dev/internal/oidc/provider/formposthtml"
"go.pinniped.dev/internal/plog"
)

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package login
@ -13,8 +13,8 @@ import (
"github.com/gorilla/securecookie"
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"
)

View File

@ -1,4 +1,4 @@
/* Copyright 2022 the Pinniped contributors. All Rights Reserved. */
/* Copyright 2022-2023 the Pinniped contributors. All Rights Reserved. */
/* SPDX-License-Identifier: Apache-2.0 */
html {

View File

@ -1,5 +1,5 @@
<!--
Copyright 2022 the Pinniped contributors. All Rights Reserved.
Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
Notes:

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package loginhtml defines HTML templates used by the Supervisor.
@ -11,7 +11,7 @@ import (
"github.com/tdewolff/minify/v2/minify"
"go.pinniped.dev/internal/oidc/provider/csp"
"go.pinniped.dev/internal/federationdomain/csp"
)
//nolint:gochecknoglobals // This package uses globals to ensure that all parsing and minifying happens at init.

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package loginhtml
@ -8,9 +8,9 @@ import (
"fmt"
"testing"
"go.pinniped.dev/internal/testutil"
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/testutil"
)
var (

View File

@ -9,10 +9,10 @@ import (
"github.com/ory/fosite"
"go.pinniped.dev/internal/federationdomain/downstreamsession"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/downstreamsession"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/plog"
)

View File

@ -20,9 +20,10 @@ import (
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
"go.pinniped.dev/internal/authenticators"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/storage"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"
@ -978,7 +979,7 @@ func TestPostLoginEndpoint(t *testing.T) {
// Inject this into our test subject at the last second so we get a fresh storage for every test.
timeoutsConfiguration := oidc.DefaultOIDCTimeoutsConfiguration()
// Use lower minimum required bcrypt cost than we would use in production to keep unit the tests fast.
kubeOauthStore := oidc.NewKubeStorage(secretsClient, oidcClientsClient, timeoutsConfiguration, bcrypt.MinCost)
kubeOauthStore := storage.NewKubeStorage(secretsClient, oidcClientsClient, timeoutsConfiguration, bcrypt.MinCost)
hmacSecretFunc := func() []byte { return []byte("some secret - must have at least 32 bytes") }
require.GreaterOrEqual(t, len(hmacSecretFunc()), 32, "fosite requires that hmac secrets have at least 32 bytes")
jwksProviderIsUnused := jwks.NewDynamicJWKSProvider()

View File

@ -18,13 +18,13 @@ import (
"k8s.io/utils/strings/slices"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/federationdomain/downstreamsession"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/resolvedprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/downstreamsession"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/oidc/provider/resolvedprovider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/psession"
)

View File

@ -24,7 +24,7 @@ import (
"github.com/ory/fosite"
fositeoauth2 "github.com/ory/fosite/handler/oauth2"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/handler/pkce"
fositepkce "github.com/ory/fosite/handler/pkce"
"github.com/ory/fosite/token/jwt"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
@ -42,19 +42,20 @@ import (
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/storage"
"go.pinniped.dev/internal/fositestorage/accesstoken"
"go.pinniped.dev/internal/fositestorage/authorizationcode"
"go.pinniped.dev/internal/fositestorage/openidconnect"
storagepkce "go.pinniped.dev/internal/fositestorage/pkce"
"go.pinniped.dev/internal/fositestorage/pkce"
"go.pinniped.dev/internal/fositestorage/refreshtoken"
"go.pinniped.dev/internal/fositestoragei"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/oidcclientsecretstorage"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
@ -955,7 +956,7 @@ func TestTokenEndpointWhenAuthcodeIsUsedTwice(t *testing.T) {
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: openidconnect.TypeLabelValue}, 1)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: accesstoken.TypeLabelValue}, 0)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: refreshtoken.TypeLabelValue}, 0)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: storagepkce.TypeLabelValue}, 0)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: pkce.TypeLabelValue}, 0)
// Assert the number of all secrets, excluding any OIDCClient's storage secret, since those are not related to session storage.
testutil.RequireNumberOfSecretsExcludingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: oidcclientsecretstorage.TypeLabelValue}, 2)
})
@ -1005,7 +1006,7 @@ func TestTokenEndpointTokenExchange(t *testing.T) { // tests for grant_type "urn
authcodeExchange authcodeExchangeInputs
modifyRequestParams func(t *testing.T, params url.Values)
modifyRequestHeaders func(r *http.Request)
modifyStorage func(t *testing.T, storage *oidc.KubeStorage, secrets v1.SecretInterface, pendingRequest *http.Request)
modifyStorage func(t *testing.T, storage *storage.KubeStorage, secrets v1.SecretInterface, pendingRequest *http.Request)
requestedAudience string
kubeResources func(t *testing.T, supervisorClient *supervisorfake.Clientset, kubeClient *fake.Clientset)
@ -1452,7 +1453,7 @@ func TestTokenEndpointTokenExchange(t *testing.T) { // tests for grant_type "urn
name: "valid access token, but it was already deleted from storage",
authcodeExchange: doValidAuthCodeExchange,
requestedAudience: "some-workload-cluster",
modifyStorage: func(t *testing.T, storage *oidc.KubeStorage, secrets v1.SecretInterface, pendingRequest *http.Request) {
modifyStorage: func(t *testing.T, storage *storage.KubeStorage, secrets v1.SecretInterface, pendingRequest *http.Request) {
parts := strings.Split(pendingRequest.Form.Get("subject_token"), ".")
require.Len(t, parts, 2)
require.NoError(t, storage.DeleteAccessTokenSession(context.Background(), parts[1]))
@ -1465,7 +1466,7 @@ func TestTokenEndpointTokenExchange(t *testing.T) { // tests for grant_type "urn
name: "valid access token, but it has already expired",
authcodeExchange: doValidAuthCodeExchange,
requestedAudience: "some-workload-cluster",
modifyStorage: func(t *testing.T, storage *oidc.KubeStorage, secrets v1.SecretInterface, pendingRequest *http.Request) {
modifyStorage: func(t *testing.T, storage *storage.KubeStorage, secrets v1.SecretInterface, pendingRequest *http.Request) {
// The fosite storage APIs don't offer a way to update an access token, so we will instead find the underlying
// storage Secret and update it in a more manual way. First get the access token's signature.
parts := strings.Split(pendingRequest.Form.Get("subject_token"), ".")
@ -1955,7 +1956,7 @@ func TestRefreshGrant(t *testing.T) {
kubeResources func(t *testing.T, supervisorClient *supervisorfake.Clientset, kubeClient *fake.Clientset)
authcodeExchange authcodeExchangeInputs
refreshRequest refreshRequestInputs
modifyRefreshTokenStorage func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string)
modifyRefreshTokenStorage func(t *testing.T, oauthStore *storage.KubeStorage, secrets v1.SecretInterface, refreshToken string)
}{
{
name: "happy path refresh grant with openid scope granted (id token returned)",
@ -2869,7 +2870,7 @@ func TestRefreshGrant(t *testing.T) {
name: "when a valid refresh token is sent in the refresh request, but the token has already expired",
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
authcodeExchange: happyAuthcodeExchangeInputsForOIDCUpstream,
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *storage.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
// The fosite storage APIs don't offer a way to update a refresh token, so we will instead find the underlying
// storage Secret and update it in a more manual way. First get the refresh token's signature.
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
@ -3832,7 +3833,7 @@ func TestRefreshGrant(t *testing.T) {
Build(),
),
authcodeExchange: happyAuthcodeExchangeInputsForLDAPUpstream,
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *storage.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
require.NoError(t, err)
@ -3870,7 +3871,7 @@ func TestRefreshGrant(t *testing.T) {
happyLDAPCustomSessionData,
),
},
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *storage.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
require.NoError(t, err)
@ -3908,7 +3909,7 @@ func TestRefreshGrant(t *testing.T) {
happyLDAPCustomSessionData,
),
},
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *storage.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
require.NoError(t, err)
@ -3988,7 +3989,7 @@ func TestRefreshGrant(t *testing.T) {
Build(),
),
authcodeExchange: happyAuthcodeExchangeInputsForLDAPUpstream,
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *oidc.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
modifyRefreshTokenStorage: func(t *testing.T, oauthStore *storage.KubeStorage, secrets v1.SecretInterface, refreshToken string) {
refreshTokenSignature := getFositeDataSignature(t, refreshToken)
firstRequester, err := oauthStore.GetRefreshTokenSession(context.Background(), refreshTokenSignature, nil)
require.NoError(t, err)
@ -4178,7 +4179,7 @@ func exchangeAuthcodeForTokens(
authCode string,
jwtSigningKey *ecdsa.PrivateKey,
secrets v1.SecretInterface,
oauthStore *oidc.KubeStorage,
oauthStore *storage.KubeStorage,
) {
authRequest := deepCopyRequestForm(happyAuthRequest)
if test.modifyAuthRequest != nil {
@ -4196,7 +4197,7 @@ func exchangeAuthcodeForTokens(
var oauthHelper fosite.OAuth2Provider
// Use lower minimum required bcrypt cost than we would use in production to keep unit the tests fast.
oauthStore = oidc.NewKubeStorage(secrets, oidcClientsClient, oidc.DefaultOIDCTimeoutsConfiguration(), bcrypt.MinCost)
oauthStore = storage.NewKubeStorage(secrets, oidcClientsClient, oidc.DefaultOIDCTimeoutsConfiguration(), bcrypt.MinCost)
if test.makeJwksSigningKeyAndProvider == nil {
test.makeJwksSigningKeyAndProvider = generateJWTSigningKeyAndJWKSProvider
@ -4214,7 +4215,7 @@ func exchangeAuthcodeForTokens(
}
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: authorizationcode.TypeLabelValue}, 1)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: storagepkce.TypeLabelValue}, 1)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: pkce.TypeLabelValue}, 1)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: openidconnect.TypeLabelValue}, expectedNumberOfIDSessionsStored)
// Assert the number of all secrets, excluding any OIDCClient's storage secret, since those are not related to session storage.
testutil.RequireNumberOfSecretsExcludingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: oidcclientsecretstorage.TypeLabelValue}, 2+expectedNumberOfIDSessionsStored)
@ -4259,7 +4260,7 @@ func requireTokenEndpointBehavior(
wantNonceValueInIDToken bool,
tokenEndpointResponse *httptest.ResponseRecorder,
authCode string,
oauthStore *oidc.KubeStorage,
oauthStore *storage.KubeStorage,
jwtSigningKey *ecdsa.PrivateKey,
secrets v1.SecretInterface,
requestTime time.Time,
@ -4298,7 +4299,7 @@ func requireTokenEndpointBehavior(
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: authorizationcode.TypeLabelValue}, 1)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: accesstoken.TypeLabelValue}, 1)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: storagepkce.TypeLabelValue}, 0)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: pkce.TypeLabelValue}, 0)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: refreshtoken.TypeLabelValue}, expectedNumberOfRefreshTokenSessionsStored)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secrets, labels.Set{crud.SecretLabelKey: openidconnect.TypeLabelValue}, expectedNumberOfIDSessionsStored)
// Assert the number of all secrets, excluding any OIDCClient's storage secret, since those are not related to session storage.
@ -4650,7 +4651,7 @@ func requireInvalidAccessTokenStorage(
func requireInvalidPKCEStorage(
t *testing.T,
code string,
storage pkce.PKCERequestStorage,
storage fositepkce.PKCERequestStorage,
) {
t.Helper()

View File

@ -1,7 +1,7 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package tokenexchange
import (
"context"
@ -27,8 +27,8 @@ type stsParams struct {
requestedAudience string
}
func TokenExchangeFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} {
return &TokenExchangeHandler{
func HandlerFactory(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} {
return &tokenExchangeHandler{
idTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
accessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
accessTokenStorage: storage.(oauth2.AccessTokenStorage),
@ -36,23 +36,23 @@ func TokenExchangeFactory(config fosite.Configurator, storage interface{}, strat
}
}
type TokenExchangeHandler struct {
type tokenExchangeHandler struct {
idTokenStrategy openid.OpenIDConnectTokenStrategy
accessTokenStrategy oauth2.AccessTokenStrategy
accessTokenStorage oauth2.AccessTokenStorage
fositeConfig fosite.Configurator
}
var _ fosite.TokenEndpointHandler = (*TokenExchangeHandler)(nil)
var _ fosite.TokenEndpointHandler = (*tokenExchangeHandler)(nil)
func (t *TokenExchangeHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error {
func (t *tokenExchangeHandler) HandleTokenEndpointRequest(ctx context.Context, requester fosite.AccessRequester) error {
if !t.CanHandleTokenEndpointRequest(ctx, requester) {
return errors.WithStack(fosite.ErrUnknownRequest)
}
return nil
}
func (t *TokenExchangeHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
func (t *tokenExchangeHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
// Skip this request if it's for a different grant type.
if err := t.HandleTokenEndpointRequest(ctx, requester); err != nil {
return errors.WithStack(err)
@ -108,7 +108,7 @@ func (t *TokenExchangeHandler) PopulateTokenEndpointResponse(ctx context.Context
return nil
}
func (t *TokenExchangeHandler) mintJWT(ctx context.Context, requester fosite.Requester, audience string) (string, error) {
func (t *tokenExchangeHandler) mintJWT(ctx context.Context, requester fosite.Requester, audience string) (string, error) {
downscoped := fosite.NewAccessRequest(requester.GetSession())
downscoped.Client.(*fosite.DefaultClient).ID = audience
@ -119,7 +119,7 @@ func (t *TokenExchangeHandler) mintJWT(ctx context.Context, requester fosite.Req
return t.idTokenStrategy.GenerateIDToken(ctx, idTokenLifespan, downscoped)
}
func (t *TokenExchangeHandler) validateSession(requester fosite.Requester) error {
func (t *tokenExchangeHandler) validateSession(requester fosite.Requester) error {
pSession, ok := requester.GetSession().(*psession.PinnipedSession)
if !ok {
// This shouldn't really happen.
@ -135,7 +135,7 @@ func (t *TokenExchangeHandler) validateSession(requester fosite.Requester) error
return nil
}
func (t *TokenExchangeHandler) validateParams(params url.Values) (*stsParams, error) {
func (t *tokenExchangeHandler) validateParams(params url.Values) (*stsParams, error) {
var result stsParams
// Validate some required parameters.
@ -189,7 +189,7 @@ func (t *TokenExchangeHandler) validateParams(params url.Values) (*stsParams, er
return &result, nil
}
func (t *TokenExchangeHandler) validateAccessToken(ctx context.Context, requester fosite.AccessRequester, accessToken string) (fosite.Requester, error) {
func (t *tokenExchangeHandler) validateAccessToken(ctx context.Context, requester fosite.AccessRequester, accessToken string) (fosite.Requester, error) {
// Look up the access token's stored session data.
signature := t.accessTokenStrategy.AccessTokenSignature(ctx, accessToken)
originalRequester, err := t.accessTokenStorage.GetAccessTokenSession(ctx, signature, requester.GetSession())
@ -204,10 +204,10 @@ func (t *TokenExchangeHandler) validateAccessToken(ctx context.Context, requeste
return originalRequester, nil
}
func (t *TokenExchangeHandler) CanSkipClientAuth(_ context.Context, _ fosite.AccessRequester) bool {
func (t *tokenExchangeHandler) CanSkipClientAuth(_ context.Context, _ fosite.AccessRequester) bool {
return false
}
func (t *TokenExchangeHandler) CanHandleTokenEndpointRequest(_ context.Context, requester fosite.AccessRequester) bool {
func (t *tokenExchangeHandler) CanHandleTokenEndpointRequest(_ context.Context, requester fosite.AccessRequester) bool {
return requester.GetGrantTypes().ExactOne(oidcapi.GrantTypeTokenExchange)
}

View File

@ -1,9 +1,10 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package manager
package endpointsmanager
import (
"go.pinniped.dev/internal/httputil/requestutil"
"net/http"
"strings"
"sync"
@ -11,20 +12,20 @@ import (
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1"
"go.pinniped.dev/internal/httputil/requestutil"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/auth"
"go.pinniped.dev/internal/oidc/callback"
"go.pinniped.dev/internal/oidc/csrftoken"
"go.pinniped.dev/internal/oidc/discovery"
"go.pinniped.dev/internal/oidc/dynamiccodec"
"go.pinniped.dev/internal/oidc/idpdiscovery"
"go.pinniped.dev/internal/oidc/idplister"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/login"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/oidc/token"
"go.pinniped.dev/internal/federationdomain/csrftoken"
"go.pinniped.dev/internal/federationdomain/dynamiccodec"
"go.pinniped.dev/internal/federationdomain/endpoints/auth"
"go.pinniped.dev/internal/federationdomain/endpoints/callback"
"go.pinniped.dev/internal/federationdomain/endpoints/discovery"
"go.pinniped.dev/internal/federationdomain/endpoints/idpdiscovery"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/endpoints/login"
"go.pinniped.dev/internal/federationdomain/endpoints/token"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/idplister"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/storage"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/secret"
"go.pinniped.dev/pkg/oidcclient/nonce"
@ -101,7 +102,7 @@ func (m *Manager) SetFederationDomains(federationDomains ...*federationdomainpro
// Use NullStorage for the authorize endpoint because we do not actually want to store anything until
// the upstream callback endpoint is called later.
oauthHelperWithNullStorage := oidc.FositeOauth2Helper(
oidc.NewNullStorage(m.secretsClient, m.oidcClientsClient, oidcclientvalidator.DefaultMinBcryptCost),
storage.NewNullStorage(m.secretsClient, m.oidcClientsClient, oidcclientvalidator.DefaultMinBcryptCost),
issuerURL,
tokenHMACKeyGetter,
nil,
@ -110,7 +111,7 @@ func (m *Manager) SetFederationDomains(federationDomains ...*federationdomainpro
// For all the other endpoints, make another oauth helper with exactly the same settings except use real storage.
oauthHelperWithKubeStorage := oidc.FositeOauth2Helper(
oidc.NewKubeStorage(m.secretsClient, m.oidcClientsClient, timeoutsConfiguration, oidcclientvalidator.DefaultMinBcryptCost),
storage.NewKubeStorage(m.secretsClient, m.oidcClientsClient, timeoutsConfiguration, oidcclientvalidator.DefaultMinBcryptCost),
issuerURL,
tokenHMACKeyGetter,
m.dynamicJWKSProvider,

View File

@ -1,7 +1,7 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package manager
package endpointsmanager
import (
"crypto/ecdsa"
@ -20,12 +20,12 @@ import (
"k8s.io/client-go/kubernetes/fake"
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
"go.pinniped.dev/internal/federationdomain/endpoints/discovery"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/discovery"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/provider/federationdomainproviders"
"go.pinniped.dev/internal/secret"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"

View File

@ -9,9 +9,9 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"go.pinniped.dev/internal/federationdomain/idplister"
"go.pinniped.dev/internal/federationdomain/resolvedprovider"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc/idplister"
"go.pinniped.dev/internal/oidc/provider/resolvedprovider"
"go.pinniped.dev/internal/psession"
)

View File

@ -1,4 +1,4 @@
/* Copyright 2021 the Pinniped contributors. All Rights Reserved. */
/* Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. */
/* SPDX-License-Identifier: Apache-2.0 */
body {

View File

@ -1,5 +1,5 @@
<!--
Copyright 2021 the Pinniped contributors. All Rights Reserved.
Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
--><!DOCTYPE html>
<html lang="en">

View File

@ -1,4 +1,4 @@
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
window.onload = () => {

View File

@ -1,4 +1,4 @@
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package formposthtml defines HTML templates used by the Supervisor.
@ -11,7 +11,7 @@ import (
"github.com/tdewolff/minify/v2/minify"
"go.pinniped.dev/internal/oidc/provider/csp"
"go.pinniped.dev/internal/federationdomain/csp"
)
//nolint:gochecknoglobals // This package uses globals to ensure that all parsing and minifying happens at init.

View File

@ -1,4 +1,4 @@
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package formposthtml

View File

@ -4,7 +4,7 @@
package idplister
import (
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
)
type UpstreamOIDCIdentityProvidersLister interface {

View File

@ -1,7 +1,8 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package oidc contains common OIDC functionality needed by Pinniped.
// Package oidc contains common OIDC functionality needed by FederationDomains to implement
// downstream OIDC functionality.
package oidc
import (
@ -18,10 +19,13 @@ import (
errorsx "github.com/pkg/errors"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/federationdomain/csrftoken"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/endpoints/tokenexchange"
"go.pinniped.dev/internal/federationdomain/formposthtml"
"go.pinniped.dev/internal/federationdomain/strategy"
"go.pinniped.dev/internal/federationdomain/timeouts"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/oidc/csrftoken"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/provider/formposthtml"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/pkg/oidcclient/nonce"
@ -99,81 +103,13 @@ type UpstreamStateParamData struct {
FormatVersion string `json:"v"`
}
type TimeoutsConfiguration struct {
// The length of time that our state param that we encrypt and pass to the upstream OIDC IDP should be considered
// valid. If a state param generated by the authorize endpoint is sent to the callback endpoint after this much
// time has passed, then the callback endpoint should reject it. This allows us to set a limit on how long
// the end user has to finish their login with the upstream IDP, including the time that it takes to fumble
// with password manager and two-factor authenticator apps, and also accounting for taking a coffee break while
// the browser is sitting at the upstream IDP's login page.
UpstreamStateParamLifespan time.Duration
// How long an authcode issued by the callback endpoint is valid. This determines how much time the end user
// has to come back to exchange the authcode for tokens at the token endpoint.
AuthorizeCodeLifespan time.Duration
// The lifetime of an downstream access token issued by the token endpoint. Access tokens should generally
// be fairly short-lived.
AccessTokenLifespan time.Duration
// The lifetime of an downstream ID token issued by the token endpoint. This should generally be the same
// as the AccessTokenLifespan, or longer if it would be useful for the user's proof of identity to be valid
// for longer than their proof of authorization.
IDTokenLifespan time.Duration
// The lifetime of an downstream refresh token issued by the token endpoint. This should generally be
// significantly longer than the access token lifetime, so it can be used to refresh the access token
// multiple times. Once the refresh token expires, the user's session is over and they will need
// to start a new authorization request, which will require them to log in again with the upstream IDP
// in their web browser.
RefreshTokenLifespan time.Duration
// AuthorizationCodeSessionStorageLifetime is the length of time after which an authcode is allowed to be garbage
// collected from storage. Authcodes are kept in storage after they are redeemed to allow the system to mark the
// authcode as already used, so it can reject any future uses of the same authcode with special case handling which
// include revoking the access and refresh tokens associated with the session. Therefore, this should be
// significantly longer than the AuthorizeCodeLifespan, and there is probably no reason to make it longer than
// the sum of the AuthorizeCodeLifespan and the RefreshTokenLifespan.
AuthorizationCodeSessionStorageLifetime time.Duration
// PKCESessionStorageLifetime is the length of time after which PKCE data is allowed to be garbage collected from
// storage. PKCE sessions are closely related to authorization code sessions. After the authcode is successfully
// redeemed, the PKCE session is explicitly deleted. After the authcode expires, the PKCE session is no longer needed,
// but it is not explicitly deleted. Therefore, this can be just slightly longer than the AuthorizeCodeLifespan. We'll
// avoid making it exactly the same as AuthorizeCodeLifespan to avoid any chance of the garbage collector deleting it
// while it is being used.
PKCESessionStorageLifetime time.Duration
// OIDCSessionStorageLifetime is the length of time after which the OIDC session data related to an authcode
// is allowed to be garbage collected from storage. Due to a bug in an underlying library, these are not explicitly
// deleted. Similar to the PKCE session, they are not needed anymore after the corresponding authcode has expired.
// Therefore, this can be just slightly longer than the AuthorizeCodeLifespan. We'll avoid making it exactly the same
// as AuthorizeCodeLifespan to avoid any chance of the garbage collector deleting it while it is being used.
OIDCSessionStorageLifetime time.Duration
// AccessTokenSessionStorageLifetime is the length of time after which an access token's session data is allowed
// to be garbage collected from storage. These must exist in storage for as long as the refresh token is valid
// or else the refresh flow will not work properly. So this must be longer than RefreshTokenLifespan.
AccessTokenSessionStorageLifetime time.Duration
// RefreshTokenSessionStorageLifetime is the length of time after which a refresh token's session data is allowed
// to be garbage collected from storage. These must exist in storage for as long as the refresh token is valid.
// Therefore, this can be just slightly longer than the RefreshTokenLifespan. We'll avoid making it exactly the same
// as RefreshTokenLifespan to avoid any chance of the garbage collector deleting it while it is being used.
// If an expired token is still stored when the user tries to refresh it, then they will get a more specific
// error message telling them that the token is expired, rather than a more generic error that is returned
// when the token does not exist. If this is desirable, then the RefreshTokenSessionStorageLifetime can be made
// to be significantly larger than RefreshTokenLifespan, at the cost of slower cleanup.
RefreshTokenSessionStorageLifetime time.Duration
}
// Get the defaults for the Supervisor server.
func DefaultOIDCTimeoutsConfiguration() TimeoutsConfiguration {
func DefaultOIDCTimeoutsConfiguration() timeouts.Configuration {
accessTokenLifespan := 2 * time.Minute
authorizationCodeLifespan := 10 * time.Minute
refreshTokenLifespan := 9 * time.Hour
return TimeoutsConfiguration{
return timeouts.Configuration{
UpstreamStateParamLifespan: 90 * time.Minute,
AuthorizeCodeLifespan: authorizationCodeLifespan,
AccessTokenLifespan: accessTokenLifespan,
@ -192,7 +128,7 @@ func FositeOauth2Helper(
issuer string,
hmacSecretOfLengthAtLeast32Func func() []byte,
jwksProvider jwks.DynamicJWKSProvider,
timeoutsConfiguration TimeoutsConfiguration,
timeoutsConfiguration timeouts.Configuration,
) fosite.OAuth2Provider {
isRedirectURISecureStrict := func(_ context.Context, uri *url.URL) bool {
return fosite.IsRedirectURISecureStrict(uri)
@ -234,15 +170,15 @@ func FositeOauth2Helper(
oauthStore,
&compose.CommonStrategy{
// Note that Fosite requires the HMAC secret to be at least 32 bytes.
CoreStrategy: newDynamicOauth2HMACStrategy(oauthConfig, hmacSecretOfLengthAtLeast32Func),
OpenIDConnectTokenStrategy: newDynamicOpenIDConnectECDSAStrategy(oauthConfig, jwksProvider),
CoreStrategy: strategy.NewDynamicOauth2HMACStrategy(oauthConfig, hmacSecretOfLengthAtLeast32Func),
OpenIDConnectTokenStrategy: strategy.NewDynamicOpenIDConnectECDSAStrategy(oauthConfig, jwksProvider),
},
compose.OAuth2AuthorizeExplicitFactory,
compose.OAuth2RefreshTokenGrantFactory,
compose.OpenIDConnectExplicitFactory,
compose.OpenIDConnectRefreshFactory,
compose.OAuth2PKCEFactory,
TokenExchangeFactory, // handle the "urn:ietf:params:oauth:grant-type:token-exchange" grant type
tokenexchange.HandlerFactory, // handle the "urn:ietf:params:oauth:grant-type:token-exchange" grant type
)
return oAuth2Provider

View File

@ -1,8 +1,11 @@
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package resolvedprovider
import (
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/psession"
)

View File

@ -1,7 +1,7 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package storage
import (
"context"

View File

@ -1,7 +1,7 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package storage
import (
"context"
@ -14,13 +14,14 @@ import (
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/federationdomain/timeouts"
"go.pinniped.dev/internal/fositestorage/accesstoken"
"go.pinniped.dev/internal/fositestorage/authorizationcode"
"go.pinniped.dev/internal/fositestorage/openidconnect"
"go.pinniped.dev/internal/fositestorage/pkce"
"go.pinniped.dev/internal/fositestorage/refreshtoken"
"go.pinniped.dev/internal/fositestoragei"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/oidcclientsecretstorage"
)
@ -38,7 +39,7 @@ var _ fositestoragei.AllFositeStorage = &KubeStorage{}
func NewKubeStorage(
secrets corev1client.SecretInterface,
oidcClientsClient v1alpha1.OIDCClientInterface,
timeoutsConfiguration TimeoutsConfiguration,
timeoutsConfiguration timeouts.Configuration,
minBcryptCost int,
) *KubeStorage {
nowFunc := time.Now

View File

@ -1,7 +1,7 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package storage
import (
"context"
@ -11,8 +11,8 @@ import (
"go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1"
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestoragei"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/oidcclientsecretstorage"
)

View File

@ -1,7 +1,7 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package strategy
import (
"context"
@ -11,6 +11,8 @@ import (
"github.com/ory/fosite/compose"
"github.com/ory/fosite/handler/oauth2"
errorsx "github.com/pkg/errors"
"go.pinniped.dev/internal/federationdomain/storage"
)
const (
@ -24,7 +26,7 @@ const (
oryAuthcodePrefix = "ory_ac_"
)
// dynamicOauth2HMACStrategy is an oauth2.CoreStrategy that can dynamically load an HMAC key to sign
// DynamicOauth2HMACStrategy is an oauth2.CoreStrategy that can dynamically load an HMAC key to sign
// stuff (access tokens, refresh tokens, and auth codes). We want this dynamic capability since our
// controllers for loading FederationDomain's and signing keys run in parallel, and thus the signing key
// might not be ready when an FederationDomain is otherwise ready.
@ -37,18 +39,18 @@ const (
// out of context, such as when accidentally committed to a GitHub repo. After we implemented the
// custom prefix feature, fosite later added the same feature, but did not make the prefix customizable.
// Therefore, this code has been updated to replace the fosite prefix with our custom prefix.
type dynamicOauth2HMACStrategy struct {
type DynamicOauth2HMACStrategy struct {
fositeConfig *fosite.Config
keyFunc func() []byte
}
var _ oauth2.CoreStrategy = &dynamicOauth2HMACStrategy{}
var _ oauth2.CoreStrategy = &DynamicOauth2HMACStrategy{}
func newDynamicOauth2HMACStrategy(
func NewDynamicOauth2HMACStrategy(
fositeConfig *fosite.Config,
keyFunc func() []byte,
) *dynamicOauth2HMACStrategy {
return &dynamicOauth2HMACStrategy{
) *DynamicOauth2HMACStrategy {
return &DynamicOauth2HMACStrategy{
fositeConfig: fositeConfig,
keyFunc: keyFunc,
}
@ -58,11 +60,11 @@ func replacePrefix(s, prefixToReplace, newPrefix string) string {
return newPrefix + strings.TrimPrefix(s, prefixToReplace)
}
func (s *dynamicOauth2HMACStrategy) AccessTokenSignature(ctx context.Context, token string) string {
func (s *DynamicOauth2HMACStrategy) AccessTokenSignature(ctx context.Context, token string) string {
return s.delegate().AccessTokenSignature(ctx, token)
}
func (s *dynamicOauth2HMACStrategy) GenerateAccessToken(
func (s *DynamicOauth2HMACStrategy) GenerateAccessToken(
ctx context.Context,
requester fosite.Requester,
) (string, string, error) {
@ -78,7 +80,7 @@ func (s *dynamicOauth2HMACStrategy) GenerateAccessToken(
return token, sig, err
}
func (s *dynamicOauth2HMACStrategy) ValidateAccessToken(
func (s *DynamicOauth2HMACStrategy) ValidateAccessToken(
ctx context.Context,
requester fosite.Requester,
token string,
@ -90,11 +92,11 @@ func (s *dynamicOauth2HMACStrategy) ValidateAccessToken(
return s.delegate().ValidateAccessToken(ctx, requester, replacePrefix(token, pinAccessTokenPrefix, oryAccessTokenPrefix))
}
func (s *dynamicOauth2HMACStrategy) RefreshTokenSignature(ctx context.Context, token string) string {
func (s *DynamicOauth2HMACStrategy) RefreshTokenSignature(ctx context.Context, token string) string {
return s.delegate().RefreshTokenSignature(ctx, token)
}
func (s *dynamicOauth2HMACStrategy) GenerateRefreshToken(
func (s *DynamicOauth2HMACStrategy) GenerateRefreshToken(
ctx context.Context,
requester fosite.Requester,
) (string, string, error) {
@ -110,7 +112,7 @@ func (s *dynamicOauth2HMACStrategy) GenerateRefreshToken(
return token, sig, err
}
func (s *dynamicOauth2HMACStrategy) ValidateRefreshToken(
func (s *DynamicOauth2HMACStrategy) ValidateRefreshToken(
ctx context.Context,
requester fosite.Requester,
token string,
@ -122,11 +124,11 @@ func (s *dynamicOauth2HMACStrategy) ValidateRefreshToken(
return s.delegate().ValidateRefreshToken(ctx, requester, replacePrefix(token, pinRefreshTokenPrefix, oryRefreshTokenPrefix))
}
func (s *dynamicOauth2HMACStrategy) AuthorizeCodeSignature(ctx context.Context, token string) string {
func (s *DynamicOauth2HMACStrategy) AuthorizeCodeSignature(ctx context.Context, token string) string {
return s.delegate().AuthorizeCodeSignature(ctx, token)
}
func (s *dynamicOauth2HMACStrategy) GenerateAuthorizeCode(
func (s *DynamicOauth2HMACStrategy) GenerateAuthorizeCode(
ctx context.Context,
requester fosite.Requester,
) (string, string, error) {
@ -142,7 +144,7 @@ func (s *dynamicOauth2HMACStrategy) GenerateAuthorizeCode(
return authcode, sig, err
}
func (s *dynamicOauth2HMACStrategy) ValidateAuthorizeCode(
func (s *DynamicOauth2HMACStrategy) ValidateAuthorizeCode(
ctx context.Context,
requester fosite.Requester,
token string,
@ -154,6 +156,6 @@ func (s *dynamicOauth2HMACStrategy) ValidateAuthorizeCode(
return s.delegate().ValidateAuthorizeCode(ctx, requester, replacePrefix(token, pinAuthcodePrefix, oryAuthcodePrefix))
}
func (s *dynamicOauth2HMACStrategy) delegate() *oauth2.HMACSHAStrategy {
return compose.NewOAuth2HMACStrategy(NewDynamicGlobalSecretConfig(s.fositeConfig, s.keyFunc))
func (s *DynamicOauth2HMACStrategy) delegate() *oauth2.HMACSHAStrategy {
return compose.NewOAuth2HMACStrategy(storage.NewDynamicGlobalSecretConfig(s.fositeConfig, s.keyFunc))
}

View File

@ -1,7 +1,7 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package strategy
import (
"context"
@ -15,7 +15,7 @@ import (
)
func TestDynamicOauth2HMACStrategy_Signatures(t *testing.T) {
s := newDynamicOauth2HMACStrategy(
s := NewDynamicOauth2HMACStrategy(
&fosite.Config{}, // defaults are good enough for this unit test
func() []byte { return []byte("12345678901234567890123456789012") }, // 32 character secret key
)
@ -57,12 +57,12 @@ func TestDynamicOauth2HMACStrategy_Signatures(t *testing.T) {
}
func TestDynamicOauth2HMACStrategy_Generate(t *testing.T) {
s := newDynamicOauth2HMACStrategy(
s := NewDynamicOauth2HMACStrategy(
&fosite.Config{}, // defaults are good enough for this unit test
func() []byte { return []byte("12345678901234567890123456789012") }, // 32 character secret key
)
generateTokenErrorCausingStrategy := newDynamicOauth2HMACStrategy(
generateTokenErrorCausingStrategy := NewDynamicOauth2HMACStrategy(
&fosite.Config{},
func() []byte { return []byte("too_short_causes_error") }, // secret key is below required 32 characters
)
@ -134,7 +134,7 @@ func TestDynamicOauth2HMACStrategy_Generate(t *testing.T) {
}
func TestDynamicOauth2HMACStrategy_Validate(t *testing.T) {
s := newDynamicOauth2HMACStrategy(
s := NewDynamicOauth2HMACStrategy(
&fosite.Config{}, // defaults are good enough for this unit test
func() []byte { return []byte("12345678901234567890123456789012") }, // 32 character secret key
)

View File

@ -1,7 +1,7 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package strategy
import (
"context"
@ -14,11 +14,11 @@ import (
"github.com/ory/fosite/handler/openid"
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/plog"
)
// dynamicOpenIDConnectECDSAStrategy is an openid.OpenIDConnectTokenStrategy that can dynamically
// DynamicOpenIDConnectECDSAStrategy is an openid.OpenIDConnectTokenStrategy that can dynamically
// load a signing key to issue ID tokens. We want this dynamic capability since our controllers for
// loading FederationDomain's and signing keys run in parallel, and thus the signing key might not be
// ready when an FederationDomain is otherwise ready.
@ -26,24 +26,24 @@ import (
// If we ever update FederationDomain's to hold their signing key, we might not need this type, since we
// could have an invariant that routes to an FederationDomain's endpoints are only wired up if an
// FederationDomain has a valid signing key.
type dynamicOpenIDConnectECDSAStrategy struct {
type DynamicOpenIDConnectECDSAStrategy struct {
fositeConfig *fosite.Config
jwksProvider jwks.DynamicJWKSProvider
}
var _ openid.OpenIDConnectTokenStrategy = &dynamicOpenIDConnectECDSAStrategy{}
var _ openid.OpenIDConnectTokenStrategy = &DynamicOpenIDConnectECDSAStrategy{}
func newDynamicOpenIDConnectECDSAStrategy(
func NewDynamicOpenIDConnectECDSAStrategy(
fositeConfig *fosite.Config,
jwksProvider jwks.DynamicJWKSProvider,
) *dynamicOpenIDConnectECDSAStrategy {
return &dynamicOpenIDConnectECDSAStrategy{
) *DynamicOpenIDConnectECDSAStrategy {
return &DynamicOpenIDConnectECDSAStrategy{
fositeConfig: fositeConfig,
jwksProvider: jwksProvider,
}
}
func (s *dynamicOpenIDConnectECDSAStrategy) GenerateIDToken(
func (s *DynamicOpenIDConnectECDSAStrategy) GenerateIDToken(
ctx context.Context,
lifespan time.Duration,
requester fosite.Requester,

View File

@ -1,7 +1,7 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
package strategy
import (
"context"
@ -20,7 +20,7 @@ import (
"github.com/stretchr/testify/require"
"gopkg.in/square/go-jose.v2"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/testutil/oidctestutil"
)
@ -94,7 +94,7 @@ func TestDynamicOpenIDConnectECDSAStrategy(t *testing.T) {
if test.jwksProvider != nil {
test.jwksProvider(jwksProvider)
}
s := newDynamicOpenIDConnectECDSAStrategy(
s := NewDynamicOpenIDConnectECDSAStrategy(
&fosite.Config{IDTokenIssuer: test.issuer},
jwksProvider,
)

View File

@ -0,0 +1,74 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package timeouts
import "time"
type Configuration struct {
// The length of time that our state param that we encrypt and pass to the upstream OIDC IDP should be considered
// valid. If a state param generated by the authorize endpoint is sent to the callback endpoint after this much
// time has passed, then the callback endpoint should reject it. This allows us to set a limit on how long
// the end user has to finish their login with the upstream IDP, including the time that it takes to fumble
// with password manager and two-factor authenticator apps, and also accounting for taking a coffee break while
// the browser is sitting at the upstream IDP's login page.
UpstreamStateParamLifespan time.Duration
// How long an authcode issued by the callback endpoint is valid. This determines how much time the end user
// has to come back to exchange the authcode for tokens at the token endpoint.
AuthorizeCodeLifespan time.Duration
// The lifetime of an downstream access token issued by the token endpoint. Access tokens should generally
// be fairly short-lived.
AccessTokenLifespan time.Duration
// The lifetime of an downstream ID token issued by the token endpoint. This should generally be the same
// as the AccessTokenLifespan, or longer if it would be useful for the user's proof of identity to be valid
// for longer than their proof of authorization.
IDTokenLifespan time.Duration
// The lifetime of an downstream refresh token issued by the token endpoint. This should generally be
// significantly longer than the access token lifetime, so it can be used to refresh the access token
// multiple times. Once the refresh token expires, the user's session is over and they will need
// to start a new authorization request, which will require them to log in again with the upstream IDP
// in their web browser.
RefreshTokenLifespan time.Duration
// AuthorizationCodeSessionStorageLifetime is the length of time after which an authcode is allowed to be garbage
// collected from storage. Authcodes are kept in storage after they are redeemed to allow the system to mark the
// authcode as already used, so it can reject any future uses of the same authcode with special case handling which
// include revoking the access and refresh tokens associated with the session. Therefore, this should be
// significantly longer than the AuthorizeCodeLifespan, and there is probably no reason to make it longer than
// the sum of the AuthorizeCodeLifespan and the RefreshTokenLifespan.
AuthorizationCodeSessionStorageLifetime time.Duration
// PKCESessionStorageLifetime is the length of time after which PKCE data is allowed to be garbage collected from
// storage. PKCE sessions are closely related to authorization code sessions. After the authcode is successfully
// redeemed, the PKCE session is explicitly deleted. After the authcode expires, the PKCE session is no longer needed,
// but it is not explicitly deleted. Therefore, this can be just slightly longer than the AuthorizeCodeLifespan. We'll
// avoid making it exactly the same as AuthorizeCodeLifespan to avoid any chance of the garbage collector deleting it
// while it is being used.
PKCESessionStorageLifetime time.Duration
// OIDCSessionStorageLifetime is the length of time after which the OIDC session data related to an authcode
// is allowed to be garbage collected from storage. Due to a bug in an underlying library, these are not explicitly
// deleted. Similar to the PKCE session, they are not needed anymore after the corresponding authcode has expired.
// Therefore, this can be just slightly longer than the AuthorizeCodeLifespan. We'll avoid making it exactly the same
// as AuthorizeCodeLifespan to avoid any chance of the garbage collector deleting it while it is being used.
OIDCSessionStorageLifetime time.Duration
// AccessTokenSessionStorageLifetime is the length of time after which an access token's session data is allowed
// to be garbage collected from storage. These must exist in storage for as long as the refresh token is valid
// or else the refresh flow will not work properly. So this must be longer than RefreshTokenLifespan.
AccessTokenSessionStorageLifetime time.Duration
// RefreshTokenSessionStorageLifetime is the length of time after which a refresh token's session data is allowed
// to be garbage collected from storage. These must exist in storage for as long as the refresh token is valid.
// Therefore, this can be just slightly longer than the RefreshTokenLifespan. We'll avoid making it exactly the same
// as RefreshTokenLifespan to avoid any chance of the garbage collector deleting it while it is being used.
// If an expired token is still stored when the user tries to refresh it, then they will get a more specific
// error message telling them that the token is expired, rather than a more generic error that is returned
// when the token does not exist. If this is desirable, then the RefreshTokenSessionStorageLifetime can be made
// to be significantly larger than RefreshTokenLifespan, at the cost of slower cleanup.
RefreshTokenSessionStorageLifetime time.Duration
}

View File

@ -16,8 +16,8 @@ import (
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestorage"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/psession"
)

View File

@ -22,7 +22,7 @@ import (
coretesting "k8s.io/client-go/testing"
clocktesting "k8s.io/utils/clock/testing"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
)

View File

@ -17,8 +17,8 @@ import (
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestorage"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/psession"
)

View File

@ -34,8 +34,8 @@ import (
kubetesting "k8s.io/client-go/testing"
clocktesting "k8s.io/utils/clock/testing"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestorage"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
)

View File

@ -1,4 +1,4 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package fositestorage
@ -7,7 +7,7 @@ import (
"github.com/ory/fosite"
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/psession"
)

View File

@ -16,8 +16,8 @@ import (
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestorage"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/psession"
)

View File

@ -21,7 +21,7 @@ import (
coretesting "k8s.io/client-go/testing"
clocktesting "k8s.io/utils/clock/testing"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
)

View File

@ -15,8 +15,8 @@ import (
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestorage"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/psession"
)

View File

@ -21,7 +21,7 @@ import (
coretesting "k8s.io/client-go/testing"
clocktesting "k8s.io/utils/clock/testing"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
)

View File

@ -16,8 +16,8 @@ import (
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestorage"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/psession"
)

View File

@ -22,7 +22,7 @@ import (
coretesting "k8s.io/client-go/testing"
clocktesting "k8s.io/utils/clock/testing"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
)

View File

@ -1,6 +1,6 @@
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package issuermocks
//go:generate go run -v github.com/golang/mock/mockgen -destination=issuermocks.go -package=issuermocks -copyright_file=../../../hack/header.txt go.pinniped.dev/internal/issuer ClientCertIssuer
//go:generate go run -v github.com/golang/mock/mockgen -destination=issuermocks.go -package=issuermocks -copyright_file=../../../hack/header.txt go.pinniped.dev/internal/clientcertissuer ClientCertIssuer

View File

@ -3,7 +3,7 @@
//
// Code generated by MockGen. DO NOT EDIT.
// Source: go.pinniped.dev/internal/issuer (interfaces: ClientCertIssuer)
// Source: go.pinniped.dev/internal/clientcertissuer (interfaces: ClientCertIssuer)
// Package issuermocks is a generated GoMock package.
package issuermocks

View File

@ -3,4 +3,4 @@
package mockupstreamoidcidentityprovider
//go:generate go run -v github.com/golang/mock/mockgen -destination=mockupstreamoidcidentityprovider.go -package=mockupstreamoidcidentityprovider -copyright_file=../../../hack/header.txt go.pinniped.dev/internal/oidc/provider/upstreamprovider UpstreamOIDCIdentityProviderI
//go:generate go run -v github.com/golang/mock/mockgen -destination=mockupstreamoidcidentityprovider.go -package=mockupstreamoidcidentityprovider -copyright_file=../../../hack/header.txt go.pinniped.dev/internal/federationdomain/upstreamprovider UpstreamOIDCIdentityProviderI

View File

@ -3,7 +3,7 @@
//
// Code generated by MockGen. DO NOT EDIT.
// Source: go.pinniped.dev/internal/oidc/provider/upstreamprovider (interfaces: UpstreamOIDCIdentityProviderI)
// Source: go.pinniped.dev/internal/federationdomain/upstreamprovider (interfaces: UpstreamOIDCIdentityProviderI)
// Package mockupstreamoidcidentityprovider is a generated GoMock package.
package mockupstreamoidcidentityprovider
@ -14,7 +14,7 @@ import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
upstreamprovider "go.pinniped.dev/internal/oidc/provider/upstreamprovider"
upstreamprovider "go.pinniped.dev/internal/federationdomain/upstreamprovider"
nonce "go.pinniped.dev/pkg/oidcclient/nonce"
oidctypes "go.pinniped.dev/pkg/oidcclient/oidctypes"
pkce "go.pinniped.dev/pkg/oidcclient/pkce"

View File

@ -58,12 +58,13 @@ import (
"go.pinniped.dev/internal/deploymentref"
"go.pinniped.dev/internal/downward"
"go.pinniped.dev/internal/dynamiccert"
"go.pinniped.dev/internal/federationdomain/dynamictlscertprovider"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/endpoints/jwks"
"go.pinniped.dev/internal/federationdomain/endpointsmanager"
"go.pinniped.dev/internal/groupsuffix"
"go.pinniped.dev/internal/kubeclient"
"go.pinniped.dev/internal/leaderelection"
"go.pinniped.dev/internal/oidc/jwks"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/manager"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/pversion"
"go.pinniped.dev/internal/secret"
@ -129,10 +130,10 @@ func signalCtx() context.Context {
//nolint:funlen
func prepareControllers(
cfg *supervisor.Config,
issuerManager *manager.Manager,
issuerManager *endpointsmanager.Manager,
dynamicJWKSProvider jwks.DynamicJWKSProvider,
dynamicTLSCertProvider provider.DynamicTLSCertProvider,
dynamicUpstreamIDPProvider provider.DynamicUpstreamIDPProvider,
dynamicTLSCertProvider dynamictlscertprovider.DynamicTLSCertProvider,
dynamicUpstreamIDPProvider dynamicupstreamprovider.DynamicUpstreamIDPProvider,
dynamicServingCertProvider dynamiccert.Private,
secretCache *secret.Cache,
supervisorDeployment *appsv1.Deployment,
@ -436,12 +437,12 @@ func runSupervisor(ctx context.Context, podInfo *downward.PodInfo, cfg *supervis
dynamicServingCertProvider := dynamiccert.NewServingCert("supervisor-serving-cert")
dynamicJWKSProvider := jwks.NewDynamicJWKSProvider()
dynamicTLSCertProvider := provider.NewDynamicTLSCertProvider()
dynamicUpstreamIDPProvider := provider.NewDynamicUpstreamIDPProvider()
dynamicTLSCertProvider := dynamictlscertprovider.NewDynamicTLSCertProvider()
dynamicUpstreamIDPProvider := dynamicupstreamprovider.NewDynamicUpstreamIDPProvider()
secretCache := secret.Cache{}
// OIDC endpoints will be served by the oidProvidersManager, and any non-OIDC paths will fallback to the healthMux.
oidProvidersManager := manager.NewManager(
oidProvidersManager := endpointsmanager.NewManager(
healthMux,
dynamicJWKSProvider,
dynamicUpstreamIDPProvider,

View File

@ -1,4 +1,4 @@
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package testutil
@ -6,10 +6,10 @@ package testutil
import (
"testing"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
)
func TestBcryptConstants(t *testing.T) {

View File

@ -30,19 +30,19 @@ import (
"go.pinniped.dev/internal/authenticators"
"go.pinniped.dev/internal/crud"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/resolvedprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/fositestorage/authorizationcode"
"go.pinniped.dev/internal/fositestorage/openidconnect"
pkce2 "go.pinniped.dev/internal/fositestorage/pkce"
"go.pinniped.dev/internal/fositestorage/pkce"
"go.pinniped.dev/internal/fositestoragei"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/resolvedprovider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/pkg/oidcclient/nonce"
"go.pinniped.dev/pkg/oidcclient/oidctypes"
"go.pinniped.dev/pkg/oidcclient/pkce"
oidcpkce "go.pinniped.dev/pkg/oidcclient/pkce"
)
// Test helpers for the OIDC package.
@ -52,7 +52,7 @@ import (
type ExchangeAuthcodeAndValidateTokenArgs struct {
Ctx context.Context
Authcode string
PKCECodeVerifier pkce.Code
PKCECodeVerifier oidcpkce.Code
ExpectedIDTokenNonce nonce.Nonce
RedirectURI string
}
@ -267,7 +267,7 @@ type TestUpstreamOIDCIdentityProvider struct {
ExchangeAuthcodeAndValidateTokensFunc func(
ctx context.Context,
authcode string,
pkceCodeVerifier pkce.Code,
pkceCodeVerifier oidcpkce.Code,
expectedIDTokenNonce nonce.Nonce,
) (*oidctypes.Token, error)
@ -358,7 +358,7 @@ func (u *TestUpstreamOIDCIdentityProvider) PasswordCredentialsGrantAndValidateTo
func (u *TestUpstreamOIDCIdentityProvider) ExchangeAuthcodeAndValidateTokens(
ctx context.Context,
authcode string,
pkceCodeVerifier pkce.Code,
pkceCodeVerifier oidcpkce.Code,
expectedIDTokenNonce nonce.Nonce,
redirectURI string,
) (*oidctypes.Token, error) {
@ -595,8 +595,8 @@ func (b *UpstreamIDPListerBuilder) BuildFederationDomainIdentityProvidersListerF
}
}
func (b *UpstreamIDPListerBuilder) BuildDynamicUpstreamIDPProvider() provider.DynamicUpstreamIDPProvider {
idpProvider := provider.NewDynamicUpstreamIDPProvider()
func (b *UpstreamIDPListerBuilder) BuildDynamicUpstreamIDPProvider() dynamicupstreamprovider.DynamicUpstreamIDPProvider {
idpProvider := dynamicupstreamprovider.NewDynamicUpstreamIDPProvider()
oidcUpstreams := make([]upstreamprovider.UpstreamOIDCIdentityProviderI, len(b.upstreamOIDCIdentityProviders))
for i := range b.upstreamOIDCIdentityProviders {
@ -1038,7 +1038,7 @@ func (u *TestUpstreamOIDCIdentityProviderBuilder) Build() *TestUpstreamOIDCIdent
AdditionalClaimMappings: u.additionalClaimMappings,
DisplayNameForFederationDomain: u.displayNameForFederationDomain,
TransformsForFederationDomain: u.transformsForFederationDomain,
ExchangeAuthcodeAndValidateTokensFunc: func(ctx context.Context, authcode string, pkceCodeVerifier pkce.Code, expectedIDTokenNonce nonce.Nonce) (*oidctypes.Token, error) {
ExchangeAuthcodeAndValidateTokensFunc: func(ctx context.Context, authcode string, pkceCodeVerifier oidcpkce.Code, expectedIDTokenNonce nonce.Nonce) (*oidctypes.Token, error) {
if u.authcodeExchangeErr != nil {
return nil, u.authcodeExchangeErr
}
@ -1223,7 +1223,7 @@ func RequireAuthCodeRegexpMatch(
)
// One PKCE should have been stored.
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secretsClient, labels.Set{crud.SecretLabelKey: pkce2.TypeLabelValue}, 1)
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secretsClient, labels.Set{crud.SecretLabelKey: pkce.TypeLabelValue}, 1)
validatePKCEStorage(
t,

View File

@ -27,8 +27,8 @@ import (
"go.pinniped.dev/internal/authenticators"
"go.pinniped.dev/internal/crypto/ptls"
"go.pinniped.dev/internal/endpointaddr"
"go.pinniped.dev/internal/oidc/downstreamsession"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/federationdomain/downstreamsession"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/plog"
)

View File

@ -25,8 +25,8 @@ import (
"go.pinniped.dev/internal/certauthority"
"go.pinniped.dev/internal/crypto/ptls"
"go.pinniped.dev/internal/endpointaddr"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/mocks/mockldapconn"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/tlsassertions"
"go.pinniped.dev/internal/testutil/tlsserver"

View File

@ -21,9 +21,9 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/pkg/oidcclient/nonce"
"go.pinniped.dev/pkg/oidcclient/oidctypes"
@ -221,7 +221,7 @@ func (p *ProviderConfig) tryRevokeToken(
if err != nil {
// Couldn't connect to the server or some similar error.
// Could be a temporary network problem, so it might be worth retrying.
return false, provider.NewRetryableRevocationError(err)
return false, dynamicupstreamprovider.NewRetryableRevocationError(err)
}
defer resp.Body.Close()
@ -271,7 +271,7 @@ func (p *ProviderConfig) tryRevokeToken(
// be caused by an underlying problem which could potentially become resolved in the near future. We'll be
// optimistic and call all 5xx errors retryable.
plog.Trace("RevokeToken() got unexpected error response from provider's revocation endpoint", "providerName", p.Name, "usedBasicAuth", useBasicAuth, "statusCode", status)
return false, provider.NewRetryableRevocationError(fmt.Errorf("server responded with status %d", status))
return false, dynamicupstreamprovider.NewRetryableRevocationError(fmt.Errorf("server responded with status %d", status))
default:
// Any other error is probably not due to failed client auth, and is probably not worth retrying later.
plog.Trace("RevokeToken() got unexpected error response from provider's revocation endpoint", "providerName", p.Name, "usedBasicAuth", useBasicAuth, "statusCode", status)

View File

@ -23,9 +23,9 @@ import (
"gopkg.in/square/go-jose.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"go.pinniped.dev/internal/federationdomain/dynamicupstreamprovider"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/mocks/mockkeyset"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/pkg/oidcclient/nonce"
"go.pinniped.dev/pkg/oidcclient/oidctypes"
@ -715,8 +715,8 @@ func TestProviderConfig(t *testing.T) {
testutil.RequireErrorStringFromErr(t, err, tt.wantErr)
if tt.wantRetryableErrType {
require.ErrorAs(t, err, &provider.RetryableRevocationError{})
} else if errors.As(err, &provider.RetryableRevocationError{}) {
require.ErrorAs(t, err, &dynamicupstreamprovider.RetryableRevocationError{})
} else if errors.As(err, &dynamicupstreamprovider.RetryableRevocationError{}) {
// There is no NotErrorAs() assertion available in the current version of testify, so do the equivalent.
require.Fail(t, "error should not be As RetryableRevocationError")
}

View File

@ -30,10 +30,10 @@ import (
"k8s.io/utils/strings/slices"
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/httputil/securityheader"
"go.pinniped.dev/internal/net/phttp"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamoidc"
"go.pinniped.dev/pkg/oidcclient/nonce"

View File

@ -28,11 +28,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
"go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/httputil/roundtripper"
"go.pinniped.dev/internal/mocks/mockupstreamoidcidentityprovider"
"go.pinniped.dev/internal/net/phttp"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/testlogger"

View File

@ -160,7 +160,7 @@ Once dynamic clients are implemented:
#### New Dependencies
This should be kept to a very simple HTML page with minimal, clean CSS styling.
Javascript should be avoided.
The styling should match the [form post html page](https://github.com/vmware-tanzu/pinniped/tree/main/internal/oidc/provider/formposthtml)
The styling should match the [form post html page](https://github.com/vmware-tanzu/pinniped/tree/main/internal/federationdomain/formposthtml)
as much as possible, we should reuse some of the existing css and add to it to keep the style consistent.
#### Observability Considerations

View File

@ -192,28 +192,28 @@ The Supervisor's endpoints are:
Each FederationDomain's endpoints are mounted under the path of the FederationDomain's `spec.issuer`,
if the `spec.issuer` URL has a path component specified. If the issuer has no path, then they are mounted under `/`.
These per-FederationDomain endpoint are all mounted by the code in
[internal/oidc/provider/manager/manager.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/provider/manager/manager.go).
[internal/federationdomain/endpointsmanager/manager.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpointsmanager/manager.go).
The per-FederationDomain endpoints are:
- `<issuer_path>/.well-known/openid-configuration` is the standard OIDC discovery endpoint, which can be used to discover all the other endpoints listed here.
See [internal/oidc/discovery/discovery_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/discovery/discovery_handler.go).
See [internal/federationdomain/endpoints/discovery/discovery_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/discovery/discovery_handler.go).
- `<issuer_path>/jwks.json` is the standard OIDC JWKS discovery endpoint.
See [internal/oidc/jwks/jwks_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/jwks/jwks_handler.go).
See [internal/federationdomain/endpoints/jwks/jwks_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/jwks/jwks_handler.go).
- `<issuer_path>/oauth2/authorize` is the standard OIDC authorize endpoint.
See [internal/oidc/auth/auth_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/auth/auth_handler.go).
See [internal/federationdomain/endpoints/auth/auth_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/auth/auth_handler.go).
- `<issuer_path>/oauth2/token` is the standard OIDC token endpoint.
See [internal/oidc/token/token_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/token/token_handler.go).
See [internal/federationdomain/endpoints/token/token_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/token/token_handler.go).
The token endpoint can handle the standard OIDC `authorization_code` and `refresh_token` grant types, and has also been
extended in [internal/oidc/token_exchange.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/token_exchange.go)
extended in [internal/federationdomain/endpoints/tokenexchange/token_exchange.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/tokenexchange/token_exchange.go)
to handle an additional grant type for [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchanges to
reduce the applicable scope (technically, the `aud` claim) of ID tokens.
- `<issuer_path>/callback` is a special endpoint that is used as the redirect URL when performing an OIDC authcode flow against an upstream OIDC identity provider as configured by an OIDCIdentityProvider custom resource.
See [internal/oidc/callback/callback_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/callback/callback_handler.go).
See [internal/federationdomain/endpoints/callback/callback_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/callback/callback_handler.go).
- `<issuer_path>/v1alpha1/pinniped_identity_providers` is a custom discovery endpoint for clients to learn about available upstream identity providers.
See [internal/oidc/idpdiscovery/idp_discovery_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/idpdiscovery/idp_discovery_handler.go).
See [internal/federationdomain/endpoints/idpdiscovery/idp_discovery_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/idpdiscovery/idp_discovery_handler.go).
- `<issuer_path>/login` is a login UI page to support the optional browser-based login flow for LDAP and Active Directory identity providers.
See [internal/oidc/login/login_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/oidc/login/login_handler.go).
See [internal/federationdomain/endpoints/login/login_handler.go](https://github.com/vmware-tanzu/pinniped/blob/main/internal/federationdomain/endpoints/login/login_handler.go).
The OIDC specifications implemented by the Supervisor can be found at [openid.net](https://openid.net/connect).

View File

@ -19,8 +19,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/federationdomain/formposthtml"
"go.pinniped.dev/internal/httputil/securityheader"
"go.pinniped.dev/internal/oidc/provider/formposthtml"
"go.pinniped.dev/test/testlib"
"go.pinniped.dev/test/testlib/browsertest"
)

View File

@ -31,8 +31,9 @@ import (
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
"go.pinniped.dev/internal/certauthority"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/oidc"
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
"go.pinniped.dev/internal/federationdomain/storage"
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/pkg/oidcclient/nonce"
@ -2240,7 +2241,7 @@ func testSupervisorLogin(
// First use the latest downstream refresh token to look up the corresponding session in the Supervisor's storage.
supervisorSecretsClient := testlib.NewKubernetesClientset(t).CoreV1().Secrets(env.SupervisorNamespace)
supervisorOIDCClientsClient := testlib.NewSupervisorClientset(t).ConfigV1alpha1().OIDCClients(env.SupervisorNamespace)
oauthStore := oidc.NewKubeStorage(supervisorSecretsClient, supervisorOIDCClientsClient, oidc.DefaultOIDCTimeoutsConfiguration(), oidcclientvalidator.DefaultMinBcryptCost)
oauthStore := storage.NewKubeStorage(supervisorSecretsClient, supervisorOIDCClientsClient, oidc.DefaultOIDCTimeoutsConfiguration(), oidcclientvalidator.DefaultMinBcryptCost)
storedRefreshSession, err := oauthStore.GetRefreshTokenSession(ctx, signatureOfLatestRefreshToken, nil)
require.NoError(t, err)
@ -2302,7 +2303,7 @@ func testSupervisorLogin(
// First use the latest downstream refresh token to look up the corresponding session in the Supervisor's storage.
supervisorSecretsClient := testlib.NewKubernetesClientset(t).CoreV1().Secrets(env.SupervisorNamespace)
supervisorOIDCClientsClient := testlib.NewSupervisorClientset(t).ConfigV1alpha1().OIDCClients(env.SupervisorNamespace)
oauthStore := oidc.NewKubeStorage(supervisorSecretsClient, supervisorOIDCClientsClient, oidc.DefaultOIDCTimeoutsConfiguration(), oidcclientvalidator.DefaultMinBcryptCost)
oauthStore := storage.NewKubeStorage(supervisorSecretsClient, supervisorOIDCClientsClient, oidc.DefaultOIDCTimeoutsConfiguration(), oidcclientvalidator.DefaultMinBcryptCost)
storedRefreshSession, err := oauthStore.GetRefreshTokenSession(ctx, signatureOfLatestRefreshToken, nil)
require.NoError(t, err)

View File

@ -1,4 +1,4 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration
@ -17,8 +17,8 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"go.pinniped.dev/internal/federationdomain/clientregistry"
"go.pinniped.dev/internal/fositestorage/authorizationcode"
"go.pinniped.dev/internal/oidc/clientregistry"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/test/testlib"
)

Some files were not shown because too many files have changed in this diff Show More