First draft of implementation of multiple IDPs support

This commit is contained in:
Ryan Richard
2023-09-11 11:09:49 -07:00
parent 1a53b4daea
commit 7af75dfe3c
44 changed files with 1465 additions and 626 deletions
@@ -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"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamldap"
)
@@ -225,7 +225,7 @@ func (s *activeDirectoryUpstreamGenericLDAPStatus) Conditions() []metav1.Conditi
// UpstreamActiveDirectoryIdentityProviderICache is a thread safe cache that holds a list of validated upstream LDAP IDP configurations.
type UpstreamActiveDirectoryIdentityProviderICache interface {
SetActiveDirectoryIdentityProviders([]provider.UpstreamLDAPIdentityProviderI)
SetActiveDirectoryIdentityProviders([]upstreamprovider.UpstreamLDAPIdentityProviderI)
}
type activeDirectoryWatcherController struct {
@@ -299,7 +299,7 @@ func (c *activeDirectoryWatcherController) Sync(ctx controllerlib.Context) error
}
requeue := false
validatedUpstreams := make([]provider.UpstreamLDAPIdentityProviderI, 0, len(actualUpstreams))
validatedUpstreams := make([]upstreamprovider.UpstreamLDAPIdentityProviderI, 0, len(actualUpstreams))
for _, upstream := range actualUpstreams {
valid, requestedRequeue := c.validateUpstream(ctx.Context, upstream)
if valid != nil {
@@ -318,7 +318,7 @@ func (c *activeDirectoryWatcherController) Sync(ctx controllerlib.Context) error
return nil
}
func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context, upstream *v1alpha1.ActiveDirectoryIdentityProvider) (p provider.UpstreamLDAPIdentityProviderI, requeue bool) {
func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context, upstream *v1alpha1.ActiveDirectoryIdentityProvider) (p upstreamprovider.UpstreamLDAPIdentityProviderI, requeue bool) {
spec := upstream.Spec
adUpstreamImpl := &activeDirectoryUpstreamGenericLDAPImpl{activeDirectoryIdentityProvider: *upstream}
@@ -344,7 +344,7 @@ func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context,
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){
"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID"),
},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
pwdLastSetAttribute: attributeUnchangedSinceLogin(pwdLastSetAttribute),
userAccountControlAttribute: validUserAccountControl,
userAccountControlComputedAttribute: validComputedUserAccountControl,
@@ -445,7 +445,7 @@ func getDomainFromDistinguishedName(distinguishedName string) (string, error) {
}
//nolint:gochecknoglobals // this needs to be a global variable so that tests can check pointer equality
var validUserAccountControl = func(entry *ldap.Entry, _ provider.RefreshAttributes) error {
var validUserAccountControl = func(entry *ldap.Entry, _ upstreamprovider.RefreshAttributes) error {
userAccountControl, err := strconv.Atoi(entry.GetAttributeValue(userAccountControlAttribute))
if err != nil {
return err
@@ -459,7 +459,7 @@ var validUserAccountControl = func(entry *ldap.Entry, _ provider.RefreshAttribut
}
//nolint:gochecknoglobals // this needs to be a global variable so that tests can check pointer equality
var validComputedUserAccountControl = func(entry *ldap.Entry, _ provider.RefreshAttributes) error {
var validComputedUserAccountControl = func(entry *ldap.Entry, _ upstreamprovider.RefreshAttributes) error {
userAccountControl, err := strconv.Atoi(entry.GetAttributeValue(userAccountControlComputedAttribute))
if err != nil {
return err
@@ -473,8 +473,8 @@ var validComputedUserAccountControl = func(entry *ldap.Entry, _ provider.Refresh
}
//nolint:gochecknoglobals // this needs to be a global variable so that tests can check pointer equality
var attributeUnchangedSinceLogin = func(attribute string) func(*ldap.Entry, provider.RefreshAttributes) error {
return func(entry *ldap.Entry, storedAttributes provider.RefreshAttributes) error {
var attributeUnchangedSinceLogin = func(attribute string) func(*ldap.Entry, upstreamprovider.RefreshAttributes) error {
return func(entry *ldap.Entry, storedAttributes upstreamprovider.RefreshAttributes) error {
prevAttributeValue := storedAttributes.AdditionalAttributes[attribute]
newValues := entry.GetRawAttributeValues(attribute)
@@ -31,6 +31,7 @@ import (
"go.pinniped.dev/internal/endpointaddr"
"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"
)
@@ -229,7 +230,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -572,7 +573,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -642,7 +643,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: "sAMAccountName",
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -715,7 +716,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -795,7 +796,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -859,7 +860,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1010,7 +1011,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1160,7 +1161,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1232,7 +1233,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1499,7 +1500,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
GroupAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"sAMAccountName": groupSAMAccountNameWithDomainSuffix},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1559,7 +1560,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1623,7 +1624,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1687,7 +1688,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1899,7 +1900,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
GroupNameAttribute: testGroupSearchNameAttrName,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -1962,7 +1963,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
SkipGroupRefresh: true,
},
UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")},
RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{
RefreshAttributeChecks: map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{
"pwdLastSet": attributeUnchangedSinceLogin("pwdLastSet"),
"userAccountControl": validUserAccountControl,
"msDS-User-Account-Control-Computed": validComputedUserAccountControl,
@@ -2010,7 +2011,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
fakeKubeClient := fake.NewSimpleClientset(tt.inputSecrets...)
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
cache := provider.NewDynamicUpstreamIDPProvider()
cache.SetActiveDirectoryIdentityProviders([]provider.UpstreamLDAPIdentityProviderI{
cache.SetActiveDirectoryIdentityProviders([]upstreamprovider.UpstreamLDAPIdentityProviderI{
upstreamldap.New(upstreamldap.ProviderConfig{Name: "initial-entry"}),
})
@@ -2104,8 +2105,8 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
expectedRefreshAttributeChecks := copyOfExpectedValueForResultingCache.RefreshAttributeChecks
actualRefreshAttributeChecks := actualConfig.RefreshAttributeChecks
copyOfExpectedValueForResultingCache.RefreshAttributeChecks = map[string]func(*ldap.Entry, provider.RefreshAttributes) error{}
actualConfig.RefreshAttributeChecks = map[string]func(*ldap.Entry, provider.RefreshAttributes) error{}
copyOfExpectedValueForResultingCache.RefreshAttributeChecks = map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{}
actualConfig.RefreshAttributeChecks = map[string]func(*ldap.Entry, upstreamprovider.RefreshAttributes) error{}
require.Equal(t, len(expectedRefreshAttributeChecks), len(actualRefreshAttributeChecks))
for k, v := range expectedRefreshAttributeChecks {
require.NotNil(t, actualRefreshAttributeChecks[k])
@@ -2354,7 +2355,7 @@ func TestValidUserAccountControl(t *testing.T) {
for _, test := range tests {
tt := test
t.Run(tt.name, func(t *testing.T) {
err := validUserAccountControl(tt.entry, provider.RefreshAttributes{})
err := validUserAccountControl(tt.entry, upstreamprovider.RefreshAttributes{})
if tt.wantErr != "" {
require.Error(t, err)
@@ -2415,7 +2416,7 @@ func TestValidComputedUserAccountControl(t *testing.T) {
for _, test := range tests {
tt := test
t.Run(tt.name, func(t *testing.T) {
err := validComputedUserAccountControl(tt.entry, provider.RefreshAttributes{})
err := validComputedUserAccountControl(tt.entry, upstreamprovider.RefreshAttributes{})
if tt.wantErr != "" {
require.Error(t, err)
@@ -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 supervisorconfig
@@ -8,9 +8,11 @@ import (
"fmt"
"net/url"
"strings"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/util/retry"
"k8s.io/klog/v2"
@@ -19,8 +21,11 @@ import (
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
pinnipedclientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned"
configinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions/config/v1alpha1"
idpinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions/idp/v1alpha1"
"go.pinniped.dev/internal/celtransformer"
pinnipedcontroller "go.pinniped.dev/internal/controller"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/idtransform"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/plog"
)
@@ -33,10 +38,14 @@ type ProvidersSetter interface {
}
type federationDomainWatcherController struct {
providerSetter ProvidersSetter
clock clock.Clock
client pinnipedclientset.Interface
federationDomainInformer configinformers.FederationDomainInformer
providerSetter ProvidersSetter
clock clock.Clock
client pinnipedclientset.Interface
federationDomainInformer configinformers.FederationDomainInformer
oidcIdentityProviderInformer idpinformers.OIDCIdentityProviderInformer
ldapIdentityProviderInformer idpinformers.LDAPIdentityProviderInformer
activeDirectoryIdentityProviderInformer idpinformers.ActiveDirectoryIdentityProviderInformer
}
// NewFederationDomainWatcherController creates a controllerlib.Controller that watches
@@ -46,16 +55,22 @@ func NewFederationDomainWatcherController(
clock clock.Clock,
client pinnipedclientset.Interface,
federationDomainInformer configinformers.FederationDomainInformer,
oidcIdentityProviderInformer idpinformers.OIDCIdentityProviderInformer,
ldapIdentityProviderInformer idpinformers.LDAPIdentityProviderInformer,
activeDirectoryIdentityProviderInformer idpinformers.ActiveDirectoryIdentityProviderInformer,
withInformer pinnipedcontroller.WithInformerOptionFunc,
) controllerlib.Controller {
return controllerlib.New(
controllerlib.Config{
Name: "FederationDomainWatcherController",
Syncer: &federationDomainWatcherController{
providerSetter: providerSetter,
clock: clock,
client: client,
federationDomainInformer: federationDomainInformer,
providerSetter: providerSetter,
clock: clock,
client: client,
federationDomainInformer: federationDomainInformer,
oidcIdentityProviderInformer: oidcIdentityProviderInformer,
ldapIdentityProviderInformer: ldapIdentityProviderInformer,
activeDirectoryIdentityProviderInformer: activeDirectoryIdentityProviderInformer,
},
},
withInformer(
@@ -63,6 +78,27 @@ func NewFederationDomainWatcherController(
pinnipedcontroller.MatchAnythingFilter(pinnipedcontroller.SingletonQueue()),
controllerlib.InformerOption{},
),
withInformer(
oidcIdentityProviderInformer,
// Since this controller only cares about IDP metadata names and UIDs (immutable fields),
// we only need to trigger Sync on creates and deletes.
pinnipedcontroller.MatchAnythingIgnoringUpdatesFilter(pinnipedcontroller.SingletonQueue()),
controllerlib.InformerOption{},
),
withInformer(
ldapIdentityProviderInformer,
// Since this controller only cares about IDP metadata names and UIDs (immutable fields),
// we only need to trigger Sync on creates and deletes.
pinnipedcontroller.MatchAnythingIgnoringUpdatesFilter(pinnipedcontroller.SingletonQueue()),
controllerlib.InformerOption{},
),
withInformer(
activeDirectoryIdentityProviderInformer,
// Since this controller only cares about IDP metadata names and UIDs (immutable fields),
// we only need to trigger Sync on creates and deletes.
pinnipedcontroller.MatchAnythingIgnoringUpdatesFilter(pinnipedcontroller.SingletonQueue()),
controllerlib.InformerOption{},
),
)
}
@@ -143,8 +179,239 @@ func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) erro
continue
}
federationDomainIssuer, err := provider.NewFederationDomainIssuer(federationDomain.Spec.Issuer) // This validates the Issuer URL.
// TODO: Move all this identity provider stuff into helper functions. This is just a sketch of how the code would
// work in the sense that this is not doing error handling, is not validating everything that it should, and
// is not updating the status of the FederationDomain with anything related to these identity providers.
// This code may crash on invalid inputs since it is not handling any errors. However, when given valid inputs,
// this correctly implements the multiple IDPs features.
// Create the list of IDPs for this FederationDomain.
// Don't worry if the IDP CRs themselves is phase=Ready because those which are not ready will not be loaded
// into the provider cache, so they cannot actually be used to authenticate.
federationDomainIdentityProviders := []*provider.FederationDomainIdentityProvider{}
var defaultFederationDomainIdentityProvider *provider.FederationDomainIdentityProvider
if len(federationDomain.Spec.IdentityProviders) == 0 {
// When the FederationDomain does not list any IDPs, then we might be in backwards compatibility mode.
oidcIdentityProviders, _ := c.oidcIdentityProviderInformer.Lister().List(labels.Everything())
ldapIdentityProviders, _ := c.ldapIdentityProviderInformer.Lister().List(labels.Everything())
activeDirectoryIdentityProviders, _ := c.activeDirectoryIdentityProviderInformer.Lister().List(labels.Everything())
// TODO handle err return value for each of the above three lines
// Check if that there is exactly one IDP defined in the Supervisor namespace of any IDP CRD type.
idpCRsCount := len(oidcIdentityProviders) + len(ldapIdentityProviders) + len(activeDirectoryIdentityProviders)
if idpCRsCount == 1 {
// If so, default that IDP's DisplayName to be the same as its resource Name.
defaultFederationDomainIdentityProvider = &provider.FederationDomainIdentityProvider{}
switch {
case len(oidcIdentityProviders) == 1:
defaultFederationDomainIdentityProvider.DisplayName = oidcIdentityProviders[0].Name
defaultFederationDomainIdentityProvider.UID = oidcIdentityProviders[0].UID
case len(ldapIdentityProviders) == 1:
defaultFederationDomainIdentityProvider.DisplayName = ldapIdentityProviders[0].Name
defaultFederationDomainIdentityProvider.UID = ldapIdentityProviders[0].UID
case len(activeDirectoryIdentityProviders) == 1:
defaultFederationDomainIdentityProvider.DisplayName = activeDirectoryIdentityProviders[0].Name
defaultFederationDomainIdentityProvider.UID = activeDirectoryIdentityProviders[0].UID
}
// Backwards compatibility mode always uses an empty identity transformation pipline since no
// transformations are defined on the FederationDomain.
defaultFederationDomainIdentityProvider.Transforms = idtransform.NewTransformationPipeline()
plog.Warning("detected FederationDomain identity provider backwards compatibility mode: using the one existing identity provider for authentication",
"federationDomain", federationDomain.Name)
} else {
// There are no IDP CRs or there is more than one IDP CR. Either way, we are not in the backwards
// compatibility mode because there is not exactly one IDP CR in the namespace, despite the fact that no
// IDPs are listed on the FederationDomain. Create a FederationDomain which has no IDPs and therefore
// cannot actually be used to log in, but still serves endpoints.
// TODO: Write something into the FederationDomain's status to explain what's happening and how to fix it.
plog.Warning("FederationDomain has no identity providers listed and there is not exactly one identity provider defined in the namespace: authentication disabled",
"federationDomain", federationDomain.Name,
"namespace", federationDomain.Namespace,
"identityProvidersCustomResourcesCount", idpCRsCount,
)
}
}
// If there is an explicit list of IDPs on the FederationDomain, then process the list.
celTransformer, _ := celtransformer.NewCELTransformer(time.Second) // TODO: what is a good duration limit here?
// TODO: handle err
for _, idp := range federationDomain.Spec.IdentityProviders {
var idpResourceUID types.UID
var idpResourceName string
// TODO: Validate that all displayNames are unique within this FederationDomain's spec's list of identity providers.
// TODO: Validate that idp.ObjectRef.APIGroup is the expected APIGroup for IDP CRs "idp.supervisor.pinniped.dev"
// Validate that each objectRef resolves to an existing IDP. It does not matter if the IDP itself
// is phase=Ready, because it will not be loaded into the cache if not ready. For each objectRef
// that does not resolve, put an error on the FederationDomain status.
switch idp.ObjectRef.Kind {
case "LDAPIdentityProvider":
ldapIDP, _ := c.ldapIdentityProviderInformer.Lister().LDAPIdentityProviders(federationDomain.Namespace).Get(idp.ObjectRef.Name)
// TODO: handle notfound err and also unexpected errors
idpResourceName = ldapIDP.Name
idpResourceUID = ldapIDP.UID
case "ActiveDirectoryIdentityProvider":
adIDP, _ := c.activeDirectoryIdentityProviderInformer.Lister().ActiveDirectoryIdentityProviders(federationDomain.Namespace).Get(idp.ObjectRef.Name)
// TODO: handle notfound err and also unexpected errors
idpResourceName = adIDP.Name
idpResourceUID = adIDP.UID
case "OIDCIdentityProvider":
oidcIDP, _ := c.oidcIdentityProviderInformer.Lister().OIDCIdentityProviders(federationDomain.Namespace).Get(idp.ObjectRef.Name)
// TODO: handle notfound err and also unexpected errors
idpResourceName = oidcIDP.Name
idpResourceUID = oidcIDP.UID
default:
// TODO: handle bad user input
}
plog.Debug("resolved identity provider object reference",
"kind", idp.ObjectRef.Kind,
"name", idp.ObjectRef.Name,
"foundResourceName", idpResourceName,
"foundResourceUID", idpResourceUID,
)
// Prepare the transformations.
pipeline := idtransform.NewTransformationPipeline()
consts := &celtransformer.TransformationConstants{
StringConstants: map[string]string{},
StringListConstants: map[string][]string{},
}
// Read all the declared constants.
for _, c := range idp.Transforms.Constants {
switch c.Type {
case "string":
consts.StringConstants[c.Name] = c.StringValue
case "stringList":
consts.StringListConstants[c.Name] = c.StringListValue
default:
// TODO: this shouldn't really happen since the CRD validates it, but handle it as an error
}
}
// Compile all the expressions and add them to the pipeline.
for idx, e := range idp.Transforms.Expressions {
var rawTransform celtransformer.CELTransformation
switch e.Type {
case "username/v1":
rawTransform = &celtransformer.UsernameTransformation{Expression: e.Expression}
case "groups/v1":
rawTransform = &celtransformer.GroupsTransformation{Expression: e.Expression}
case "policy/v1":
rawTransform = &celtransformer.AllowAuthenticationPolicy{
Expression: e.Expression,
RejectedAuthenticationMessage: e.Message,
}
default:
// TODO: this shouldn't really happen since the CRD validates it, but handle it as an error
}
compiledTransform, err := celTransformer.CompileTransformation(rawTransform, consts)
if err != nil {
// TODO: handle compile err
plog.Error("error compiling identity transformation", err,
"federationDomain", federationDomain.Name,
"idpDisplayName", idp.DisplayName,
"transformationIndex", idx,
"transformationType", e.Type,
"transformationExpression", e.Expression,
)
}
pipeline.AppendTransformation(compiledTransform)
plog.Debug("successfully compiled identity transformation expression",
"type", e.Type,
"expr", e.Expression,
"policyMessage", e.Message,
)
}
// Run all the provided transform examples. If any fail, put errors on the FederationDomain status.
for idx, e := range idp.Transforms.Examples {
// TODO: use a real context param below
result, _ := pipeline.Evaluate(context.TODO(), e.Username, e.Groups)
// TODO: handle err
resultWasAuthRejected := !result.AuthenticationAllowed
if e.Expects.Rejected && !resultWasAuthRejected {
// TODO: handle this failed example
plog.Warning("FederationDomain identity provider transformations example failed: expected authentication to be rejected but it was not",
"federationDomain", federationDomain.Name,
"idpDisplayName", idp.DisplayName,
"exampleIndex", idx,
"expectedRejected", e.Expects.Rejected,
"actualRejectedResult", resultWasAuthRejected,
"expectedMessage", e.Expects.Message,
"actualMessageResult", result.RejectedAuthenticationMessage,
)
} else if !e.Expects.Rejected && resultWasAuthRejected {
// TODO: handle this failed example
plog.Warning("FederationDomain identity provider transformations example failed: expected authentication not to be rejected but it was rejected",
"federationDomain", federationDomain.Name,
"idpDisplayName", idp.DisplayName,
"exampleIndex", idx,
"expectedRejected", e.Expects.Rejected,
"actualRejectedResult", resultWasAuthRejected,
"expectedMessage", e.Expects.Message,
"actualMessageResult", result.RejectedAuthenticationMessage,
)
} else if e.Expects.Rejected && resultWasAuthRejected && e.Expects.Message != result.RejectedAuthenticationMessage {
// TODO: when expected message is blank, then treat it like it expects the default message
// TODO: handle this failed example
plog.Warning("FederationDomain identity provider transformations example failed: expected a different authentication rejection message",
"federationDomain", federationDomain.Name,
"idpDisplayName", idp.DisplayName,
"exampleIndex", idx,
"expectedRejected", e.Expects.Rejected,
"actualRejectedResult", resultWasAuthRejected,
"expectedMessage", e.Expects.Message,
"actualMessageResult", result.RejectedAuthenticationMessage,
)
} else if result.AuthenticationAllowed {
// In the case where the user expected the auth to be allowed and it was allowed, then compare
// the expected username and group names to the actual username and group names.
// TODO: when both of these fail, put both errors onto the status (not just the first one)
if e.Expects.Username != result.Username {
// TODO: handle this failed example
plog.Warning("FederationDomain identity provider transformations example failed: expected a different transformed username",
"federationDomain", federationDomain.Name,
"idpDisplayName", idp.DisplayName,
"exampleIndex", idx,
"expectedUsername", e.Expects.Username,
"actualUsernameResult", result.Username,
)
}
if !stringSlicesEqual(e.Expects.Groups, result.Groups) {
// TODO: Do we need to make this insensitive to ordering, or should the transformations evaluator be changed to always return sorted group names at the end of the pipeline?
// TODO: What happens if the user did not write any group expectation? Treat it like expecting any empty list of groups?
// TODO: handle this failed example
plog.Warning("FederationDomain identity provider transformations example failed: expected a different transformed groups list",
"federationDomain", federationDomain.Name,
"idpDisplayName", idp.DisplayName,
"exampleIndex", idx,
"expectedGroups", e.Expects.Groups,
"actualGroupsResult", result.Groups,
)
}
}
}
// For each valid IDP (unique displayName, valid objectRef + valid transforms), add it to the list.
federationDomainIdentityProviders = append(federationDomainIdentityProviders, &provider.FederationDomainIdentityProvider{
DisplayName: idp.DisplayName,
UID: idpResourceUID,
Transforms: pipeline,
})
plog.Debug("loaded FederationDomain identity provider",
"federationDomain", federationDomain.Name,
"identityProviderDisplayName", idp.DisplayName,
"identityProviderResourceUID", idpResourceUID,
)
}
// Now that we have the list of IDPs for this FederationDomain, create the issuer.
var federationDomainIssuer *provider.FederationDomainIssuer
err = nil
if defaultFederationDomainIdentityProvider != nil {
// This is the constructor for the backwards compatibility mode.
federationDomainIssuer, err = provider.NewFederationDomainIssuerWithDefaultIDP(federationDomain.Spec.Issuer, defaultFederationDomainIdentityProvider)
} else {
// This is the constructor for any other case, including when there is an empty list of IDPs.
federationDomainIssuer, err = provider.NewFederationDomainIssuer(federationDomain.Spec.Issuer, federationDomainIdentityProviders)
}
if err != nil {
// Note that the FederationDomainIssuer constructors validate the Issuer URL.
if err := c.updateStatus(
ctx.Context,
federationDomain.Namespace,
@@ -176,6 +443,18 @@ func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) erro
return errors.NewAggregate(errs)
}
func stringSlicesEqual(a []string, b []string) bool {
if len(a) != len(b) {
return false
}
for i, itemFromA := range a {
if b[i] != itemFromA {
return false
}
}
return true
}
func (c *federationDomainWatcherController) updateStatus(
ctx context.Context,
namespace, name string,
@@ -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"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamldap"
)
@@ -133,7 +133,7 @@ func (s *ldapUpstreamGenericLDAPStatus) Conditions() []metav1.Condition {
// UpstreamLDAPIdentityProviderICache is a thread safe cache that holds a list of validated upstream LDAP IDP configurations.
type UpstreamLDAPIdentityProviderICache interface {
SetLDAPIdentityProviders([]provider.UpstreamLDAPIdentityProviderI)
SetLDAPIdentityProviders([]upstreamprovider.UpstreamLDAPIdentityProviderI)
}
type ldapWatcherController struct {
@@ -207,7 +207,7 @@ func (c *ldapWatcherController) Sync(ctx controllerlib.Context) error {
}
requeue := false
validatedUpstreams := make([]provider.UpstreamLDAPIdentityProviderI, 0, len(actualUpstreams))
validatedUpstreams := make([]upstreamprovider.UpstreamLDAPIdentityProviderI, 0, len(actualUpstreams))
for _, upstream := range actualUpstreams {
valid, requestedRequeue := c.validateUpstream(ctx.Context, upstream)
if valid != nil {
@@ -226,7 +226,7 @@ func (c *ldapWatcherController) Sync(ctx controllerlib.Context) error {
return nil
}
func (c *ldapWatcherController) validateUpstream(ctx context.Context, upstream *v1alpha1.LDAPIdentityProvider) (p provider.UpstreamLDAPIdentityProviderI, requeue bool) {
func (c *ldapWatcherController) validateUpstream(ctx context.Context, upstream *v1alpha1.LDAPIdentityProvider) (p upstreamprovider.UpstreamLDAPIdentityProviderI, requeue bool) {
spec := upstream.Spec
config := &upstreamldap.ProviderConfig{
@@ -30,6 +30,7 @@ import (
"go.pinniped.dev/internal/endpointaddr"
"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 +1140,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
fakeKubeClient := fake.NewSimpleClientset(tt.inputSecrets...)
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
cache := provider.NewDynamicUpstreamIDPProvider()
cache.SetLDAPIdentityProviders([]provider.UpstreamLDAPIdentityProviderI{
cache.SetLDAPIdentityProviders([]upstreamprovider.UpstreamLDAPIdentityProviderI{
upstreamldap.New(upstreamldap.ProviderConfig{Name: "initial-entry"}),
})
@@ -35,7 +35,7 @@ import (
"go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/net/phttp"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamoidc"
)
@@ -91,7 +91,7 @@ var (
// UpstreamOIDCIdentityProviderICache is a thread safe cache that holds a list of validated upstream OIDC IDP configurations.
type UpstreamOIDCIdentityProviderICache interface {
SetOIDCIdentityProviders([]provider.UpstreamOIDCIdentityProviderI)
SetOIDCIdentityProviders([]upstreamprovider.UpstreamOIDCIdentityProviderI)
}
// lruValidatorCache caches the *oidc.Provider associated with a particular issuer/TLS configuration.
@@ -175,13 +175,13 @@ func (c *oidcWatcherController) Sync(ctx controllerlib.Context) error {
}
requeue := false
validatedUpstreams := make([]provider.UpstreamOIDCIdentityProviderI, 0, len(actualUpstreams))
validatedUpstreams := make([]upstreamprovider.UpstreamOIDCIdentityProviderI, 0, len(actualUpstreams))
for _, upstream := range actualUpstreams {
valid := c.validateUpstream(ctx, upstream)
if valid == nil {
requeue = true
} else {
validatedUpstreams = append(validatedUpstreams, provider.UpstreamOIDCIdentityProviderI(valid))
validatedUpstreams = append(validatedUpstreams, upstreamprovider.UpstreamOIDCIdentityProviderI(valid))
}
}
c.cache.SetOIDCIdentityProviders(validatedUpstreams)
@@ -29,6 +29,7 @@ import (
"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/plog"
"go.pinniped.dev/internal/testutil"
"go.pinniped.dev/internal/testutil/oidctestutil"
@@ -81,7 +82,7 @@ func TestOIDCUpstreamWatcherControllerFilterSecret(t *testing.T) {
fakeKubeClient := fake.NewSimpleClientset()
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
cache := provider.NewDynamicUpstreamIDPProvider()
cache.SetOIDCIdentityProviders([]provider.UpstreamOIDCIdentityProviderI{
cache.SetOIDCIdentityProviders([]upstreamprovider.UpstreamOIDCIdentityProviderI{
&upstreamoidc.ProviderConfig{Name: "initial-entry"},
})
secretInformer := kubeInformers.Core().V1().Secrets()
@@ -1416,7 +1417,7 @@ oidc: issuer did not match the issuer returned by provider, expected "` + testIs
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
testLog := testlogger.NewLegacy(t) //nolint:staticcheck // old test with lots of log statements
cache := provider.NewDynamicUpstreamIDPProvider()
cache.SetOIDCIdentityProviders([]provider.UpstreamOIDCIdentityProviderI{
cache.SetOIDCIdentityProviders([]upstreamprovider.UpstreamOIDCIdentityProviderI{
&upstreamoidc.ProviderConfig{Name: "initial-entry"},
})
@@ -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"
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/upstreamldap"
)
@@ -365,7 +365,7 @@ func validateAndSetLDAPServerConnectivityAndSearchBase(
return ldapConnectionValidCondition, searchBaseFoundCondition
}
func EvaluateConditions(conditions GradatedConditions, config *upstreamldap.ProviderConfig) (provider.UpstreamLDAPIdentityProviderI, bool) {
func EvaluateConditions(conditions GradatedConditions, config *upstreamldap.ProviderConfig) (upstreamprovider.UpstreamLDAPIdentityProviderI, bool) {
for _, gradatedCondition := range conditions.gradatedConditions {
if gradatedCondition.condition.Status != metav1.ConditionTrue && gradatedCondition.isFatal {
// Invalid provider, so do not load it into the cache.
@@ -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 supervisorstorage
@@ -27,6 +27,7 @@ import (
"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"
)
@@ -43,7 +44,7 @@ type garbageCollectorController struct {
// UpstreamOIDCIdentityProviderICache is a thread safe cache that holds a list of validated upstream OIDC IDP configurations.
type UpstreamOIDCIdentityProviderICache interface {
GetOIDCIdentityProviders() []provider.UpstreamOIDCIdentityProviderI
GetOIDCIdentityProviders() []upstreamprovider.UpstreamOIDCIdentityProviderI
}
func GarbageCollectorController(
@@ -244,7 +245,7 @@ func (c *garbageCollectorController) tryRevokeUpstreamOIDCToken(ctx context.Cont
}
// Try to find the provider that was originally used to create the stored session.
var foundOIDCIdentityProviderI provider.UpstreamOIDCIdentityProviderI
var foundOIDCIdentityProviderI upstreamprovider.UpstreamOIDCIdentityProviderI
for _, p := range c.idpCache.GetOIDCIdentityProviders() {
if p.GetName() == customSessionData.ProviderName && p.GetResourceUID() == customSessionData.ProviderUID {
foundOIDCIdentityProviderI = p
@@ -260,7 +261,7 @@ func (c *garbageCollectorController) tryRevokeUpstreamOIDCToken(ctx context.Cont
upstreamAccessToken := customSessionData.OIDC.UpstreamAccessToken
if upstreamRefreshToken != "" {
err := foundOIDCIdentityProviderI.RevokeToken(ctx, upstreamRefreshToken, provider.RefreshTokenType)
err := foundOIDCIdentityProviderI.RevokeToken(ctx, upstreamRefreshToken, upstreamprovider.RefreshTokenType)
if err != nil {
return err
}
@@ -268,7 +269,7 @@ func (c *garbageCollectorController) tryRevokeUpstreamOIDCToken(ctx context.Cont
}
if upstreamAccessToken != "" {
err := foundOIDCIdentityProviderI.RevokeToken(ctx, upstreamAccessToken, provider.AccessTokenType)
err := foundOIDCIdentityProviderI.RevokeToken(ctx, upstreamAccessToken, upstreamprovider.AccessTokenType)
if err != nil {
return err
}
@@ -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 supervisorstorage
@@ -30,6 +30,7 @@ import (
"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"
@@ -369,7 +370,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-refresh-token",
TokenType: provider.RefreshTokenType,
TokenType: upstreamprovider.RefreshTokenType,
},
)
@@ -493,7 +494,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-access-token",
TokenType: provider.AccessTokenType,
TokenType: upstreamprovider.AccessTokenType,
},
)
@@ -785,7 +786,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-refresh-token",
TokenType: provider.RefreshTokenType,
TokenType: upstreamprovider.RefreshTokenType,
},
)
@@ -810,7 +811,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-refresh-token",
TokenType: provider.RefreshTokenType,
TokenType: upstreamprovider.RefreshTokenType,
},
)
@@ -889,7 +890,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-refresh-token",
TokenType: provider.RefreshTokenType,
TokenType: upstreamprovider.RefreshTokenType,
},
)
@@ -1012,7 +1013,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-refresh-token",
TokenType: provider.RefreshTokenType,
TokenType: upstreamprovider.RefreshTokenType,
},
)
@@ -1136,7 +1137,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-access-token",
TokenType: provider.AccessTokenType,
TokenType: upstreamprovider.AccessTokenType,
},
)
@@ -1214,7 +1215,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-refresh-token",
TokenType: provider.RefreshTokenType,
TokenType: upstreamprovider.RefreshTokenType,
},
)
@@ -1291,7 +1292,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
&oidctestutil.RevokeTokenArgs{
Ctx: syncContext.Context,
Token: "fake-upstream-access-token",
TokenType: provider.AccessTokenType,
TokenType: upstreamprovider.AccessTokenType,
},
)
+11 -1
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 controller
@@ -18,6 +18,16 @@ func NameAndNamespaceExactMatchFilterFactory(name, namespace string) controllerl
}, nil)
}
// MatchAnythingIgnoringUpdatesFilter returns a controllerlib.Filter that allows all objects but ignores updates.
func MatchAnythingIgnoringUpdatesFilter(parentFunc controllerlib.ParentFunc) controllerlib.Filter {
return controllerlib.FilterFuncs{
AddFunc: func(object metav1.Object) bool { return true },
UpdateFunc: func(oldObj, newObj metav1.Object) bool { return false },
DeleteFunc: func(object metav1.Object) bool { return true },
ParentFunc: parentFunc,
}
}
// MatchAnythingFilter returns a controllerlib.Filter that allows all objects.
func MatchAnythingFilter(parentFunc controllerlib.ParentFunc) controllerlib.Filter {
return SimpleFilter(func(object metav1.Object) bool { return true }, parentFunc)