2023-06-05 21:40:39 +00:00
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
2020-10-09 00:40:58 +00:00
// SPDX-License-Identifier: Apache-2.0
package supervisorconfig
import (
"context"
2020-10-09 14:39:17 +00:00
"errors"
2021-02-05 17:56:05 +00:00
"fmt"
2020-10-23 23:25:44 +00:00
"net/url"
2023-07-07 21:10:07 +00:00
"sort"
2020-10-09 00:40:58 +00:00
"testing"
"time"
"github.com/stretchr/testify/require"
2023-07-05 20:33:21 +00:00
corev1 "k8s.io/api/core/v1"
2020-10-09 00:40:58 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020-10-09 14:39:17 +00:00
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
coretesting "k8s.io/client-go/testing"
2021-12-10 22:22:36 +00:00
clocktesting "k8s.io/utils/clock/testing"
2023-07-10 21:09:19 +00:00
"k8s.io/utils/pointer"
2020-10-09 00:40:58 +00:00
2023-07-05 20:33:21 +00:00
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
2021-02-16 19:00:08 +00:00
pinnipedfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
pinnipedinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions"
2020-10-09 00:40:58 +00:00
"go.pinniped.dev/internal/controllerlib"
2023-06-22 22:12:33 +00:00
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
2023-07-07 21:10:07 +00:00
"go.pinniped.dev/internal/idtransform"
2020-10-09 00:40:58 +00:00
"go.pinniped.dev/internal/testutil"
)
2023-07-05 20:33:21 +00:00
func TestFederationDomainWatcherControllerInformerFilters ( t * testing . T ) {
t . Parallel ( )
federationDomainInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . Config ( ) . V1alpha1 ( ) . FederationDomains ( )
oidcIdentityProviderInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . IDP ( ) . V1alpha1 ( ) . OIDCIdentityProviders ( )
ldapIdentityProviderInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . IDP ( ) . V1alpha1 ( ) . LDAPIdentityProviders ( )
adIdentityProviderInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . IDP ( ) . V1alpha1 ( ) . ActiveDirectoryIdentityProviders ( )
tests := [ ] struct {
name string
obj metav1 . Object
informer controllerlib . InformerGetter
wantAdd bool
wantUpdate bool
wantDelete bool
} {
{
name : "any FederationDomain changes" ,
obj : & configv1alpha1 . FederationDomain { } ,
informer : federationDomainInformer ,
wantAdd : true ,
wantUpdate : true ,
wantDelete : true ,
} ,
{
name : "any OIDCIdentityProvider adds or deletes, but updates are ignored" ,
obj : & idpv1alpha1 . OIDCIdentityProvider { } ,
informer : oidcIdentityProviderInformer ,
wantAdd : true ,
wantUpdate : false ,
wantDelete : true ,
} ,
{
name : "any LDAPIdentityProvider adds or deletes, but updates are ignored" ,
obj : & idpv1alpha1 . LDAPIdentityProvider { } ,
informer : ldapIdentityProviderInformer ,
wantAdd : true ,
wantUpdate : false ,
wantDelete : true ,
} ,
{
name : "any ActiveDirectoryIdentityProvider adds or deletes, but updates are ignored" ,
obj : & idpv1alpha1 . ActiveDirectoryIdentityProvider { } ,
informer : adIdentityProviderInformer ,
wantAdd : true ,
wantUpdate : false ,
wantDelete : true ,
} ,
}
for _ , test := range tests {
test := test
t . Run ( test . name , func ( t * testing . T ) {
t . Parallel ( )
withInformer := testutil . NewObservableWithInformerOption ( )
NewFederationDomainWatcherController (
2020-10-09 00:40:58 +00:00
nil ,
nil ,
nil ,
2020-12-17 19:34:49 +00:00
federationDomainInformer ,
2023-06-05 21:40:39 +00:00
oidcIdentityProviderInformer ,
ldapIdentityProviderInformer ,
adIdentityProviderInformer ,
2023-07-05 20:33:21 +00:00
withInformer . WithInformer , // make it possible to observe the behavior of the Filters
2020-10-09 00:40:58 +00:00
)
2023-07-05 20:33:21 +00:00
unrelatedObj := corev1 . Secret { }
filter := withInformer . GetFilterForInformer ( test . informer )
require . Equal ( t , test . wantAdd , filter . Add ( test . obj ) )
require . Equal ( t , test . wantUpdate , filter . Update ( & unrelatedObj , test . obj ) )
require . Equal ( t , test . wantUpdate , filter . Update ( test . obj , & unrelatedObj ) )
require . Equal ( t , test . wantDelete , filter . Delete ( test . obj ) )
2020-10-09 00:40:58 +00:00
} )
2023-07-05 20:33:21 +00:00
}
2020-10-09 00:40:58 +00:00
}
2023-06-13 21:20:39 +00:00
type fakeFederationDomainsSetter struct {
SetFederationDomainsWasCalled bool
2023-06-22 20:12:50 +00:00
FederationDomainsReceived [ ] * federationdomainproviders . FederationDomainIssuer
2020-10-09 00:40:58 +00:00
}
2023-06-22 20:12:50 +00:00
func ( f * fakeFederationDomainsSetter ) SetFederationDomains ( federationDomains ... * federationdomainproviders . FederationDomainIssuer ) {
2023-06-13 21:20:39 +00:00
f . SetFederationDomainsWasCalled = true
2020-12-16 22:27:09 +00:00
f . FederationDomainsReceived = federationDomains
2020-10-09 00:40:58 +00:00
}
2023-07-10 22:41:48 +00:00
var federationDomainGVR = schema . GroupVersionResource {
Group : configv1alpha1 . SchemeGroupVersion . Group ,
Version : configv1alpha1 . SchemeGroupVersion . Version ,
Resource : "federationdomains" ,
}
2023-07-05 20:33:21 +00:00
func TestTestFederationDomainWatcherControllerSync ( t * testing . T ) {
2023-07-06 00:41:27 +00:00
t . Parallel ( )
2020-10-09 00:40:58 +00:00
2023-07-06 00:41:27 +00:00
const namespace = "some-namespace"
2023-07-10 21:09:19 +00:00
const apiGroupSupervisor = "idp.supervisor.pinniped.dev"
2020-10-09 00:40:58 +00:00
2023-07-06 00:41:27 +00:00
frozenNow := time . Date ( 2020 , time . September , 23 , 7 , 42 , 0 , 0 , time . Local )
frozenMetav1Now := metav1 . NewTime ( frozenNow )
2020-10-09 00:40:58 +00:00
2023-07-11 16:42:20 +00:00
oidcIdentityProvider := & idpv1alpha1 . OIDCIdentityProvider {
2023-07-07 21:10:07 +00:00
ObjectMeta : metav1 . ObjectMeta {
2023-07-11 16:42:20 +00:00
Name : "some-oidc-idp" ,
2023-07-10 22:41:48 +00:00
Namespace : namespace ,
2023-07-11 16:42:20 +00:00
UID : "some-oidc-uid" ,
2023-07-10 21:09:19 +00:00
} ,
}
2023-07-11 16:42:20 +00:00
ldapIdentityProvider := & idpv1alpha1 . LDAPIdentityProvider {
ObjectMeta : metav1 . ObjectMeta {
Name : "some-ldap-idp" ,
Namespace : namespace ,
UID : "some-ldap-uid" ,
} ,
}
adIdentityProvider := & idpv1alpha1 . ActiveDirectoryIdentityProvider {
2023-07-10 21:09:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2023-07-11 16:42:20 +00:00
Name : "some-ad-idp" ,
2023-07-10 22:41:48 +00:00
Namespace : namespace ,
2023-07-11 16:42:20 +00:00
UID : "some-ad-uid" ,
2023-07-07 21:10:07 +00:00
} ,
}
2023-07-06 00:41:27 +00:00
federationDomain1 := & configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer1.com" } ,
}
2020-10-09 00:40:58 +00:00
2023-07-06 00:41:27 +00:00
federationDomain2 := & configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config2" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer2.com" } ,
}
2020-10-09 14:39:17 +00:00
2023-07-10 22:41:48 +00:00
invalidIssuerURLFederationDomain := & configv1alpha1 . FederationDomain {
2023-07-06 00:41:27 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "invalid-config" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://invalid-issuer.com?some=query" } ,
}
2023-06-30 20:43:40 +00:00
2023-07-10 22:41:48 +00:00
federationDomainIssuerWithIDPs := func ( t * testing . T , fedDomainIssuer string , fdIDPs [ ] * federationdomainproviders . FederationDomainIdentityProvider ) * federationdomainproviders . FederationDomainIssuer {
fdIssuer , err := federationdomainproviders . NewFederationDomainIssuer ( fedDomainIssuer , fdIDPs )
require . NoError ( t , err )
return fdIssuer
}
2023-07-07 21:10:07 +00:00
federationDomainIssuerWithDefaultIDP := func ( t * testing . T , fedDomainIssuer string , idpObjectMeta metav1 . ObjectMeta ) * federationdomainproviders . FederationDomainIssuer {
fdIDP := & federationdomainproviders . FederationDomainIdentityProvider {
DisplayName : idpObjectMeta . Name ,
UID : idpObjectMeta . UID ,
Transforms : idtransform . NewTransformationPipeline ( ) ,
}
fdIssuer , err := federationdomainproviders . NewFederationDomainIssuerWithDefaultIDP ( fedDomainIssuer , fdIDP )
require . NoError ( t , err )
return fdIssuer
}
2023-07-06 00:41:27 +00:00
happyReadyCondition := func ( issuer string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "Ready" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : fmt . Sprintf ( "the FederationDomain is ready and its endpoints are available: " +
"the discovery endpoint is %s/.well-known/openid-configuration" , issuer ) ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadReadyCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "Ready" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "NotReady" ,
Message : "the FederationDomain is not ready: see other conditions for details" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
happyIssuerIsUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerIsUnique" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "spec.issuer is unique among all FederationDomains" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
unknownIssuerIsUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerIsUnique" ,
Status : "Unknown" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "UnableToValidate" ,
Message : "unable to check if spec.issuer is unique among all FederationDomains because URL cannot be parsed" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadIssuerIsUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerIsUnique" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "DuplicateIssuer" ,
Message : "multiple FederationDomains have the same spec.issuer URL: these URLs must be unique (can use different hosts or paths)" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
happyOneTLSSecretPerIssuerHostnameCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "OneTLSSecretPerIssuerHostname" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
unknownOneTLSSecretPerIssuerHostnameCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "OneTLSSecretPerIssuerHostname" ,
Status : "Unknown" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "UnableToValidate" ,
Message : "unable to check if all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL because URL cannot be parsed" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadOneTLSSecretPerIssuerHostnameCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "OneTLSSecretPerIssuerHostname" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "DifferentSecretRefsFound" ,
Message : "when different FederationDomains are using the same hostname in the spec.issuer URL then they must also use the same TLS secretRef: different secretRefs found" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
happyIssuerURLValidCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerURLValid" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "spec.issuer is a valid URL" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadIssuerURLValidConditionCannotHaveQuery := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerURLValid" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "InvalidIssuerURL" ,
Message : "issuer must not have query" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadIssuerURLValidConditionCannotParse := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerURLValid" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "InvalidIssuerURL" ,
Message : ` could not parse issuer as URL: parse ":/host//path": missing protocol scheme ` ,
}
}
2020-10-09 00:40:58 +00:00
2023-07-07 21:10:07 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess := func ( idpName string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "LegacyConfigurationSuccess" ,
Message : fmt . Sprintf ( "no resources were specified by .spec.identityProviders[].objectRef but exactly one " +
"identity provider resource has been found: using %q as " +
"identity provider: please explicitly list identity providers in .spec.identityProviders " +
"(this legacy configuration mode may be removed in a future version of Pinniped)" , idpName ) ,
}
}
2023-07-10 22:41:48 +00:00
happyIdentityProvidersFoundConditionSuccess := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the resources specified by .spec.identityProviders[].objectRef were found" ,
}
}
2023-07-10 21:09:19 +00:00
sadIdentityProvidersFoundConditionLegacyConfigurationIdentityProviderNotFound := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "LegacyConfigurationIdentityProviderNotFound" ,
Message : "no resources were specified by .spec.identityProviders[].objectRef and no identity provider " +
"resources have been found: please create an identity provider resource" ,
}
}
sadIdentityProvidersFoundConditionIdentityProviderNotSpecified := func ( idpCRsCount int , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "IdentityProviderNotSpecified" ,
Message : fmt . Sprintf ( "no resources were specified by .spec.identityProviders[].objectRef " +
"and %q identity provider resources have been found: " +
"please update .spec.identityProviders to specify which identity providers " +
"this federation domain should use" , idpCRsCount ) ,
}
}
sadIdentityProvidersFoundConditionIdentityProvidersObjectRefsNotFound := func ( msg string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "IdentityProvidersObjectRefsNotFound" ,
Message : msg ,
}
}
2023-07-07 21:10:07 +00:00
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "DisplayNamesUnique" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the names specified by .spec.identityProviders[].displayName are unique" ,
}
}
sadDisplayNamesUniqueCondition := func ( duplicateNames string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "DisplayNamesUnique" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "DuplicateDisplayNames" ,
Message : fmt . Sprintf ( "the names specified by .spec.identityProviders[].displayName contain duplicates: %s" , duplicateNames ) ,
}
}
2023-07-10 22:41:48 +00:00
allHappyConditionsLegacyConfigurationSuccess := func ( issuer string , idpName string , time metav1 . Time , observedGeneration int64 ) [ ] configv1alpha1 . Condition {
2023-07-06 00:41:27 +00:00
return [ ] configv1alpha1 . Condition {
2023-07-10 22:41:48 +00:00
// expect them to be sorted alphabetically by type
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-07 21:10:07 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( idpName , time , observedGeneration ) ,
2023-07-06 00:41:27 +00:00
happyIssuerIsUniqueCondition ( time , observedGeneration ) ,
happyIssuerURLValidCondition ( time , observedGeneration ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( time , observedGeneration ) ,
happyReadyCondition ( issuer , time , observedGeneration ) ,
}
}
2020-10-09 00:40:58 +00:00
2023-07-10 22:41:48 +00:00
allHappyConditionsSuccess := func ( issuer string , time metav1 . Time , observedGeneration int64 ) [ ] configv1alpha1 . Condition {
return [ ] configv1alpha1 . Condition {
// expect them to be sorted alphabetically by type
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
happyIdentityProvidersFoundConditionSuccess ( frozenMetav1Now , 123 ) ,
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
happyReadyCondition ( issuer , frozenMetav1Now , 123 ) ,
}
}
2023-07-06 00:41:27 +00:00
invalidIssuerURL := ":/host//path"
2023-07-07 21:10:07 +00:00
_ , err := url . Parse ( invalidIssuerURL ) //nolint:staticcheck // Yes, this URL is intentionally invalid.
2023-07-06 00:41:27 +00:00
require . Error ( t , err )
tests := [ ] struct {
2023-07-11 16:42:20 +00:00
name string
inputObjects [ ] runtime . Object
configClient func ( * pinnipedfake . Clientset )
wantErr string
wantStatusUpdates [ ] * configv1alpha1 . FederationDomain
wantFDIssuers [ ] * federationdomainproviders . FederationDomainIssuer
2023-07-06 00:41:27 +00:00
} {
{
2023-07-11 16:42:20 +00:00
name : "when there are no FederationDomains, no update actions happen and the list of FederationDomainIssuers is set to the empty list" ,
inputObjects : [ ] runtime . Object { } ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-06 00:41:27 +00:00
} ,
{
2023-07-07 21:10:07 +00:00
name : "legacy config: when no identity provider is specified on federation domains, but exactly one identity " +
"provider resource exists on cluster, the controller will set a default IDP on each federation domain " +
"matching the only identity provider found" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are two valid FederationDomains, but one is already up to date, the sync loop only updates " +
"the out-of-date FederationDomain" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-10 22:41:48 +00:00
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : federationDomain1 . Name , Namespace : federationDomain1 . Namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : federationDomain1 . Spec . Issuer } ,
Status : configv1alpha1 . FederationDomainStatus {
Phase : configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
Conditions : allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
} ,
} ,
2023-07-06 00:41:27 +00:00
federationDomain2 ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
// only one update, because the other FederationDomain already had the right status
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are two valid FederationDomains, but updating one fails, the status on the FederationDomain will not change" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
configClient : func ( client * pinnipedfake . Clientset ) {
2023-07-06 00:41:27 +00:00
client . PrependReactor (
"update" ,
"federationdomains" ,
func ( action coretesting . Action ) ( bool , runtime . Object , error ) {
fd := action . ( coretesting . UpdateAction ) . GetObject ( ) . ( * configv1alpha1 . FederationDomain )
if fd . Name == federationDomain1 . Name {
return true , nil , errors . New ( "some update error" )
}
return false , nil , nil
2020-10-09 14:39:17 +00:00
} ,
)
2023-07-06 00:41:27 +00:00
} ,
wantErr : "could not update status: some update error" ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-11 17:57:11 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-11 16:42:20 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are both valid and invalid FederationDomains, the status will be correctly set on each " +
"FederationDomain individually" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
2023-07-10 22:41:48 +00:00
invalidIssuerURLFederationDomain ,
2023-07-06 00:41:27 +00:00
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-10 22:41:48 +00:00
// only the valid FederationDomain
2023-07-11 16:42:20 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( invalidIssuerURLFederationDomain ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadIssuerURLValidConditionCannotHaveQuery ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are both valid and invalid FederationDomains, but updating the invalid one fails, the " +
"existing status will be unchanged" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
2023-07-10 22:41:48 +00:00
invalidIssuerURLFederationDomain ,
2023-07-06 00:41:27 +00:00
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
configClient : func ( client * pinnipedfake . Clientset ) {
2023-07-06 00:41:27 +00:00
client . PrependReactor (
"update" ,
"federationdomains" ,
func ( action coretesting . Action ) ( bool , runtime . Object , error ) {
fd := action . ( coretesting . UpdateAction ) . GetObject ( ) . ( * configv1alpha1 . FederationDomain )
2023-07-10 22:41:48 +00:00
if fd . Name == invalidIssuerURLFederationDomain . Name {
2020-10-09 14:39:17 +00:00
return true , nil , errors . New ( "some update error" )
2023-07-06 00:41:27 +00:00
}
return false , nil , nil
2020-10-09 14:39:17 +00:00
} ,
)
2023-07-06 00:41:27 +00:00
} ,
wantErr : "could not update status: some update error" ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-10 22:41:48 +00:00
// only the valid FederationDomain
2023-07-11 16:42:20 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( invalidIssuerURLFederationDomain ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadIssuerURLValidConditionCannotHaveQuery ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are FederationDomains with duplicate issuer strings these particular FederationDomains " +
"will report error on IssuerUnique conditions" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate1" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://iSSueR-duPlicAte.cOm/a" } ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate2" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer-duplicate.com/a" } ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "not-duplicate" , Namespace : namespace , Generation : 123 } ,
2023-07-06 00:41:27 +00:00
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer-duplicate.com/A" } , // different path (paths are case-sensitive)
} ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , "https://issuer-duplicate.com/A" , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
sadIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate2" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
sadIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "not-duplicate" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( "https://issuer-duplicate.com/A" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are FederationDomains with the same issuer DNS hostname using different secretNames these " +
"particular FederationDomains will report errors on OneTLSSecretPerIssuerHostname conditions" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "fd1" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-11-02 22:55:29 +00:00
Issuer : "https://iSSueR-duPlicAte-adDress.cOm/path1" ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret1" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "fd2" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-10-27 00:03:26 +00:00
// Validation treats these as the same DNS hostname even though they have different port numbers,
// because SNI information on the incoming requests is not going to include port numbers.
2020-11-02 22:55:29 +00:00
Issuer : "https://issuer-duplicate-address.com:1234/path2" ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret2" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "differentIssuerAddressFederationDomain" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-11-02 22:55:29 +00:00
Issuer : "https://issuer-not-duplicate.com" ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret1" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "invalidIssuerURLFederationDomain" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-11-02 22:55:29 +00:00
Issuer : invalidIssuerURL ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret1" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , "https://issuer-not-duplicate.com" , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "fd1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
sadOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "fd2" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
sadOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "invalidIssuerURLFederationDomain" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
unknownIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadIssuerURLValidConditionCannotParse ( frozenMetav1Now , 123 ) ,
unknownOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "differentIssuerAddressFederationDomain" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( "https://issuer-not-duplicate.com" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-10 21:09:19 +00:00
} ,
} ,
{
name : "legacy config: no identity provider specified in federation domain and no identity providers found results in not found status" ,
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-10 22:41:48 +00:00
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
sadIdentityProvidersFoundConditionLegacyConfigurationIdentityProviderNotFound ( frozenMetav1Now , 123 ) ,
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
sadIdentityProvidersFoundConditionLegacyConfigurationIdentityProviderNotFound ( frozenMetav1Now , 123 ) ,
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
2023-07-10 21:09:19 +00:00
} ,
} ,
{
name : "legacy config: no identity provider specified in federation domain and multiple identity providers found results in not specified status" ,
inputObjects : [ ] runtime . Object {
federationDomain1 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
2023-07-10 21:09:19 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-10 22:41:48 +00:00
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-11 16:42:20 +00:00
sadIdentityProvidersFoundConditionIdentityProviderNotSpecified ( 3 , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
2023-07-10 21:09:19 +00:00
} ,
} ,
{
name : "the federation domain specifies identity providers that cannot be found" ,
inputObjects : [ ] runtime . Object {
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "cant-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
2023-07-11 16:42:20 +00:00
Name : "cant-find-me-name" ,
2023-07-10 21:09:19 +00:00
} ,
} ,
2023-07-10 22:41:48 +00:00
{
DisplayName : "cant-find-me-either" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
2023-07-11 16:42:20 +00:00
Name : "cant-find-me-either-name" ,
} ,
} ,
{
DisplayName : "cant-find-me-still" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : "cant-find-me-still-name" ,
2023-07-10 22:41:48 +00:00
} ,
} ,
2023-07-10 21:09:19 +00:00
} ,
} ,
} ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-10 22:41:48 +00:00
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
sadIdentityProvidersFoundConditionIdentityProvidersObjectRefsNotFound (
` .spec.identityProviders[].objectRef identifies resource(s) that cannot be found: ` +
2023-07-11 16:42:20 +00:00
` .spec.identityProviders[0] with displayName "cant-find-me", ` +
` .spec.identityProviders[1] with displayName "cant-find-me-either", ` +
` .spec.identityProviders[2] with displayName "cant-find-me-still" ` ,
2023-07-10 22:41:48 +00:00
frozenMetav1Now , 123 ) ,
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ,
) ,
} ,
} ,
{
name : "the federation domain specifies identity providers that all exist" ,
inputObjects : [ ] runtime . Object {
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
2023-07-10 22:41:48 +00:00
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
2023-07-11 16:42:20 +00:00
Name : oidcIdentityProvider . Name ,
2023-07-10 21:09:19 +00:00
} ,
} ,
2023-07-10 22:41:48 +00:00
{
DisplayName : "can-find-me-too" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
2023-07-11 16:42:20 +00:00
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "can-find-me-three" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : adIdentityProvider . Name ,
2023-07-10 22:41:48 +00:00
} ,
2023-07-10 21:09:19 +00:00
} ,
2023-07-10 22:41:48 +00:00
} ,
} ,
} ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-10 22:41:48 +00:00
federationDomainIssuerWithIDPs ( t , "https://issuer1.com" ,
[ ] * federationdomainproviders . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
2023-07-11 16:42:20 +00:00
UID : oidcIdentityProvider . UID ,
2023-07-10 22:41:48 +00:00
Transforms : idtransform . NewTransformationPipeline ( ) ,
} ,
{
DisplayName : "can-find-me-too" ,
2023-07-11 16:42:20 +00:00
UID : ldapIdentityProvider . UID ,
Transforms : idtransform . NewTransformationPipeline ( ) ,
} ,
{
DisplayName : "can-find-me-three" ,
UID : adIdentityProvider . UID ,
2023-07-10 22:41:48 +00:00
Transforms : idtransform . NewTransformationPipeline ( ) ,
} ,
} ) ,
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
) ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-12 16:43:33 +00:00
} ,
{
name : "the federation domain has duplicate display names for IDPs" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "duplicate1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "duplicate1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "unique" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : adIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "duplicate2" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "duplicate2" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : adIdentityProvider . Name ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
[ ] configv1alpha1 . Condition {
sadDisplayNamesUniqueCondition ( "duplicate1, duplicate2" , frozenMetav1Now , 123 ) ,
happyIdentityProvidersFoundConditionSuccess ( frozenMetav1Now , 123 ) ,
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
} ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 22:42:34 +00:00
{
name : "the federation domain specifies illegal const type, which shouldn't really happen since the CRD validates it" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Constants : [ ] configv1alpha1 . FederationDomainTransformsConstant {
{
Type : "this is illegal" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantErr : ` one of spec.identityProvider[].transforms.constants[].type is invalid: "this is illegal" ` ,
} ,
{
name : "the federation domain specifies illegal expression type, which shouldn't really happen since the CRD validates it" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{
Type : "this is illegal" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantErr : ` one of spec.identityProvider[].transforms.expressions[].type is invalid: "this is illegal" ` ,
} ,
2023-07-06 00:41:27 +00:00
}
2020-10-23 23:25:44 +00:00
2023-07-06 00:41:27 +00:00
for _ , tt := range tests {
tt := tt
t . Run ( tt . name , func ( t * testing . T ) {
t . Parallel ( )
federationDomainsSetter := & fakeFederationDomainsSetter { }
pinnipedAPIClient := pinnipedfake . NewSimpleClientset ( )
pinnipedInformerClient := pinnipedfake . NewSimpleClientset ( )
for _ , o := range tt . inputObjects {
require . NoError ( t , pinnipedAPIClient . Tracker ( ) . Add ( o ) )
require . NoError ( t , pinnipedInformerClient . Tracker ( ) . Add ( o ) )
}
2023-07-11 16:42:20 +00:00
if tt . configClient != nil {
tt . configClient ( pinnipedAPIClient )
2023-07-06 00:41:27 +00:00
}
pinnipedInformers := pinnipedinformers . NewSharedInformerFactory ( pinnipedInformerClient , 0 )
controller := NewFederationDomainWatcherController (
federationDomainsSetter ,
clocktesting . NewFakeClock ( frozenNow ) ,
pinnipedAPIClient ,
pinnipedInformers . Config ( ) . V1alpha1 ( ) . FederationDomains ( ) ,
pinnipedInformers . IDP ( ) . V1alpha1 ( ) . OIDCIdentityProviders ( ) ,
pinnipedInformers . IDP ( ) . V1alpha1 ( ) . LDAPIdentityProviders ( ) ,
pinnipedInformers . IDP ( ) . V1alpha1 ( ) . ActiveDirectoryIdentityProviders ( ) ,
controllerlib . WithInformer ,
)
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
pinnipedInformers . Start ( ctx . Done ( ) )
controllerlib . TestRunSynchronously ( t , controller )
syncCtx := controllerlib . Context { Context : ctx , Key : controllerlib . Key { Namespace : namespace , Name : "config-name" } }
if err := controllerlib . TestSync ( t , controller , syncCtx ) ; tt . wantErr != "" {
require . EqualError ( t , err , tt . wantErr )
} else {
require . NoError ( t , err )
}
2023-07-11 16:42:20 +00:00
if tt . wantFDIssuers != nil {
2023-07-06 00:41:27 +00:00
require . True ( t , federationDomainsSetter . SetFederationDomainsWasCalled )
2023-07-11 16:42:20 +00:00
require . ElementsMatch ( t , tt . wantFDIssuers , federationDomainsSetter . FederationDomainsReceived )
2023-07-06 00:41:27 +00:00
} else {
require . False ( t , federationDomainsSetter . SetFederationDomainsWasCalled )
}
2023-07-07 21:10:07 +00:00
2023-07-10 22:41:48 +00:00
if tt . wantStatusUpdates != nil {
// This controller should only perform updates to FederationDomain statuses.
// In this controller we don't actually care about the order of the actions, since the FederationDomains
// statuses can be updated in any order. Therefore, we are sorting here so we can use require.Equal
// to make the test output easier to read. Unfortunately the timezone nested in the condition can still
// make the test failure diffs ugly sometimes, but we do want to assert about timestamps so there's not
// much we can do about those.
actualFederationDomainUpdates := getFederationDomainStatusUpdates ( t , pinnipedAPIClient . Actions ( ) )
sortFederationDomainsByName ( actualFederationDomainUpdates )
sortFederationDomainsByName ( tt . wantStatusUpdates )
// Use require.Equal instead of require.ElementsMatch because require.Equal prints a nice diff.
require . Equal ( t , tt . wantStatusUpdates , actualFederationDomainUpdates )
2023-07-07 21:10:07 +00:00
} else {
require . Empty ( t , pinnipedAPIClient . Actions ( ) )
}
2020-10-09 00:40:58 +00:00
} )
2023-07-06 00:41:27 +00:00
}
2020-10-09 00:40:58 +00:00
}
2023-07-07 21:10:07 +00:00
2023-07-10 22:41:48 +00:00
func expectedFederationDomainStatusUpdate (
fd * configv1alpha1 . FederationDomain ,
phase configv1alpha1 . FederationDomainPhase ,
conditions [ ] configv1alpha1 . Condition ,
) * configv1alpha1 . FederationDomain {
fdCopy := fd . DeepCopy ( )
// We don't care about the spec of a FederationDomain in an update status action,
// so clear it out to make it easier to write expected values.
fdCopy . Spec = configv1alpha1 . FederationDomainSpec { }
2023-07-07 21:10:07 +00:00
2023-07-10 22:41:48 +00:00
fdCopy . Status . Phase = phase
fdCopy . Status . Conditions = conditions
return fdCopy
}
func getFederationDomainStatusUpdates ( t * testing . T , actions [ ] coretesting . Action ) [ ] * configv1alpha1 . FederationDomain {
federationDomains := [ ] * configv1alpha1 . FederationDomain { }
for _ , action := range actions {
updateAction , ok := action . ( coretesting . UpdateAction )
require . True ( t , ok , "failed to cast an action as an coretesting.UpdateAction: %#v" , action )
require . Equal ( t , federationDomainGVR , updateAction . GetResource ( ) , "an update action should have updated a FederationDomain but updated something else" )
require . Equal ( t , "status" , updateAction . GetSubresource ( ) , "an update action should have updated the status subresource but updated something else" )
fd , ok := updateAction . GetObject ( ) . ( * configv1alpha1 . FederationDomain )
require . True ( t , ok , "failed to cast an action's object as a FederationDomain: %#v" , updateAction . GetObject ( ) )
require . Equal ( t , fd . Namespace , updateAction . GetNamespace ( ) , "an update action might have been called on the wrong namespace for a FederationDomain" )
// We don't care about the spec of a FederationDomain in an update status action,
// so clear it out to make it easier to write expected values.
copyOfFD := fd . DeepCopy ( )
copyOfFD . Spec = configv1alpha1 . FederationDomainSpec { }
federationDomains = append ( federationDomains , copyOfFD )
}
return federationDomains
}
2023-07-07 21:10:07 +00:00
2023-07-10 22:41:48 +00:00
func sortFederationDomainsByName ( federationDomains [ ] * configv1alpha1 . FederationDomain ) {
sort . SliceStable ( federationDomains , func ( a , b int ) bool {
return federationDomains [ a ] . GetName ( ) < federationDomains [ b ] . GetName ( )
2023-07-07 21:10:07 +00:00
} )
}