mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-20 06:54:20 +00:00
committed by
Ryan Richard
parent
fbe1a202c2
commit
196e43aa48
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
opKind = "OIDCProvider"
|
||||
opKind = "FederationDomain"
|
||||
)
|
||||
|
||||
func generateSymmetricKey() ([]byte, error) {
|
||||
|
||||
@@ -24,29 +24,29 @@ import (
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
type oidcProviderSecretsController struct {
|
||||
type federationDomainSecretsController struct {
|
||||
secretHelper SecretHelper
|
||||
kubeClient kubernetes.Interface
|
||||
pinnipedClient pinnipedclientset.Interface
|
||||
opcInformer configinformers.OIDCProviderInformer
|
||||
opcInformer configinformers.FederationDomainInformer
|
||||
secretInformer corev1informers.SecretInformer
|
||||
}
|
||||
|
||||
// NewOIDCProviderSecretsController returns a controllerlib.Controller that ensures a child Secret
|
||||
// always exists for a parent OIDCProvider. It does this using the provided secretHelper, which
|
||||
// NewFederationDomainSecretsController returns a controllerlib.Controller that ensures a child Secret
|
||||
// always exists for a parent FederationDomain. It does this using the provided secretHelper, which
|
||||
// provides the parent/child mapping logic.
|
||||
func NewOIDCProviderSecretsController(
|
||||
func NewFederationDomainSecretsController(
|
||||
secretHelper SecretHelper,
|
||||
kubeClient kubernetes.Interface,
|
||||
pinnipedClient pinnipedclientset.Interface,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
opcInformer configinformers.OIDCProviderInformer,
|
||||
opcInformer configinformers.FederationDomainInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: fmt.Sprintf("%s%s", secretHelper.NamePrefix(), "controller"),
|
||||
Syncer: &oidcProviderSecretsController{
|
||||
Syncer: &federationDomainSecretsController{
|
||||
secretHelper: secretHelper,
|
||||
kubeClient: kubeClient,
|
||||
pinnipedClient: pinnipedClient,
|
||||
@@ -79,12 +79,12 @@ func NewOIDCProviderSecretsController(
|
||||
)
|
||||
}
|
||||
|
||||
func (c *oidcProviderSecretsController) Sync(ctx controllerlib.Context) error {
|
||||
op, err := c.opcInformer.Lister().OIDCProviders(ctx.Key.Namespace).Get(ctx.Key.Name)
|
||||
func (c *federationDomainSecretsController) Sync(ctx controllerlib.Context) error {
|
||||
op, err := c.opcInformer.Lister().FederationDomains(ctx.Key.Namespace).Get(ctx.Key.Name)
|
||||
notFound := k8serrors.IsNotFound(err)
|
||||
if err != nil && !notFound {
|
||||
return fmt.Errorf(
|
||||
"failed to get %s/%s OIDCProvider: %w",
|
||||
"failed to get %s/%s FederationDomain: %w",
|
||||
ctx.Key.Namespace,
|
||||
ctx.Key.Name,
|
||||
err,
|
||||
@@ -95,8 +95,8 @@ func (c *oidcProviderSecretsController) Sync(ctx controllerlib.Context) error {
|
||||
// The corresponding secret to this OP should have been garbage collected since it should have
|
||||
// had this OP as its owner.
|
||||
plog.Debug(
|
||||
"oidcprovider deleted",
|
||||
"oidcprovider",
|
||||
"federationdomain deleted",
|
||||
"federationdomain",
|
||||
klog.KRef(ctx.Key.Namespace, ctx.Key.Name),
|
||||
)
|
||||
return nil
|
||||
@@ -115,17 +115,17 @@ func (c *oidcProviderSecretsController) Sync(ctx controllerlib.Context) error {
|
||||
// Secret is up to date - we are good to go.
|
||||
plog.Debug(
|
||||
"secret is up to date",
|
||||
"oidcprovider",
|
||||
"federationdomain",
|
||||
klog.KObj(op),
|
||||
"secret",
|
||||
klog.KObj(existingSecret),
|
||||
)
|
||||
|
||||
op = c.secretHelper.ObserveActiveSecretAndUpdateParentOIDCProvider(op, existingSecret)
|
||||
if err := c.updateOIDCProvider(ctx.Context, op); err != nil {
|
||||
return fmt.Errorf("failed to update oidcprovider: %w", err)
|
||||
op = c.secretHelper.ObserveActiveSecretAndUpdateParentFederationDomain(op, existingSecret)
|
||||
if err := c.updateFederationDomain(ctx.Context, op); err != nil {
|
||||
return fmt.Errorf("failed to update federationdomain: %w", err)
|
||||
}
|
||||
plog.Debug("updated oidcprovider", "oidcprovider", klog.KObj(op), "secret", klog.KObj(newSecret))
|
||||
plog.Debug("updated federationdomain", "federationdomain", klog.KObj(op), "secret", klog.KObj(newSecret))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -135,21 +135,21 @@ func (c *oidcProviderSecretsController) Sync(ctx controllerlib.Context) error {
|
||||
if err := c.createOrUpdateSecret(ctx.Context, op, &newSecret); err != nil {
|
||||
return fmt.Errorf("failed to create or update secret: %w", err)
|
||||
}
|
||||
plog.Debug("created/updated secret", "oidcprovider", klog.KObj(op), "secret", klog.KObj(newSecret))
|
||||
plog.Debug("created/updated secret", "federationdomain", klog.KObj(op), "secret", klog.KObj(newSecret))
|
||||
|
||||
op = c.secretHelper.ObserveActiveSecretAndUpdateParentOIDCProvider(op, newSecret)
|
||||
if err := c.updateOIDCProvider(ctx.Context, op); err != nil {
|
||||
return fmt.Errorf("failed to update oidcprovider: %w", err)
|
||||
op = c.secretHelper.ObserveActiveSecretAndUpdateParentFederationDomain(op, newSecret)
|
||||
if err := c.updateFederationDomain(ctx.Context, op); err != nil {
|
||||
return fmt.Errorf("failed to update federationdomain: %w", err)
|
||||
}
|
||||
plog.Debug("updated oidcprovider", "oidcprovider", klog.KObj(op), "secret", klog.KObj(newSecret))
|
||||
plog.Debug("updated federationdomain", "federationdomain", klog.KObj(op), "secret", klog.KObj(newSecret))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// secretNeedsUpdate returns whether or not the Secret, with name secretName, for OIDCProvider op
|
||||
// secretNeedsUpdate returns whether or not the Secret, with name secretName, for FederationDomain op
|
||||
// needs to be updated. It returns the existing secret as its second argument.
|
||||
func (c *oidcProviderSecretsController) secretNeedsUpdate(
|
||||
op *configv1alpha1.OIDCProvider,
|
||||
func (c *federationDomainSecretsController) secretNeedsUpdate(
|
||||
op *configv1alpha1.FederationDomain,
|
||||
secretName string,
|
||||
) (bool, *corev1.Secret, error) {
|
||||
// This OPC says it has a secret associated with it. Let's try to get it from the cache.
|
||||
@@ -171,9 +171,9 @@ func (c *oidcProviderSecretsController) secretNeedsUpdate(
|
||||
return false, secret, nil
|
||||
}
|
||||
|
||||
func (c *oidcProviderSecretsController) createOrUpdateSecret(
|
||||
func (c *federationDomainSecretsController) createOrUpdateSecret(
|
||||
ctx context.Context,
|
||||
op *configv1alpha1.OIDCProvider,
|
||||
op *configv1alpha1.FederationDomain,
|
||||
newSecret **corev1.Secret,
|
||||
) error {
|
||||
secretClient := c.kubeClient.CoreV1().Secrets((*newSecret).Namespace)
|
||||
@@ -210,15 +210,15 @@ func (c *oidcProviderSecretsController) createOrUpdateSecret(
|
||||
})
|
||||
}
|
||||
|
||||
func (c *oidcProviderSecretsController) updateOIDCProvider(
|
||||
func (c *federationDomainSecretsController) updateFederationDomain(
|
||||
ctx context.Context,
|
||||
newOP *configv1alpha1.OIDCProvider,
|
||||
newOP *configv1alpha1.FederationDomain,
|
||||
) error {
|
||||
opcClient := c.pinnipedClient.ConfigV1alpha1().OIDCProviders(newOP.Namespace)
|
||||
opcClient := c.pinnipedClient.ConfigV1alpha1().FederationDomains(newOP.Namespace)
|
||||
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
oldOP, err := opcClient.Get(ctx, newOP.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get oidcprovider %s/%s: %w", newOP.Namespace, newOP.Name, err)
|
||||
return fmt.Errorf("failed to get federationdomain %s/%s: %w", newOP.Namespace, newOP.Name, err)
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(newOP.Status.Secrets, oldOP.Status.Secrets) {
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
func TestOIDCProviderControllerFilterSecret(t *testing.T) {
|
||||
func TestFederationDomainControllerFilterSecret(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
@@ -54,7 +54,7 @@ func TestOIDCProviderControllerFilterSecret(t *testing.T) {
|
||||
Namespace: "some-namespace",
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
Controller: boolPtr(true),
|
||||
},
|
||||
@@ -85,7 +85,7 @@ func TestOIDCProviderControllerFilterSecret(t *testing.T) {
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
},
|
||||
},
|
||||
@@ -100,7 +100,7 @@ func TestOIDCProviderControllerFilterSecret(t *testing.T) {
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
Controller: boolPtr(true),
|
||||
},
|
||||
@@ -123,7 +123,7 @@ func TestOIDCProviderControllerFilterSecret(t *testing.T) {
|
||||
},
|
||||
{
|
||||
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
Controller: boolPtr(true),
|
||||
},
|
||||
@@ -153,9 +153,9 @@ func TestOIDCProviderControllerFilterSecret(t *testing.T) {
|
||||
opcInformer := pinnipedinformers.NewSharedInformerFactory(
|
||||
pinnipedfake.NewSimpleClientset(),
|
||||
0,
|
||||
).Config().V1alpha1().OIDCProviders()
|
||||
).Config().V1alpha1().FederationDomains()
|
||||
withInformer := testutil.NewObservableWithInformerOption()
|
||||
_ = NewOIDCProviderSecretsController(
|
||||
_ = NewFederationDomainSecretsController(
|
||||
secretHelper,
|
||||
nil, // kubeClient, not needed
|
||||
nil, // pinnipedClient, not needed
|
||||
@@ -175,12 +175,12 @@ func TestOIDCProviderControllerFilterSecret(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOIDCProviderSecretsControllerFilterOPC(t *testing.T) {
|
||||
func TestNewFederationDomainSecretsControllerFilterOPC(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
opc configv1alpha1.OIDCProvider
|
||||
opc configv1alpha1.FederationDomain
|
||||
wantAdd bool
|
||||
wantUpdate bool
|
||||
wantDelete bool
|
||||
@@ -188,7 +188,7 @@ func TestNewOIDCProviderSecretsControllerFilterOPC(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "anything goes",
|
||||
opc: configv1alpha1.OIDCProvider{},
|
||||
opc: configv1alpha1.FederationDomain{},
|
||||
wantAdd: true,
|
||||
wantUpdate: true,
|
||||
wantDelete: true,
|
||||
@@ -212,9 +212,9 @@ func TestNewOIDCProviderSecretsControllerFilterOPC(t *testing.T) {
|
||||
opcInformer := pinnipedinformers.NewSharedInformerFactory(
|
||||
pinnipedfake.NewSimpleClientset(),
|
||||
0,
|
||||
).Config().V1alpha1().OIDCProviders()
|
||||
).Config().V1alpha1().FederationDomains()
|
||||
withInformer := testutil.NewObservableWithInformerOption()
|
||||
_ = NewOIDCProviderSecretsController(
|
||||
_ = NewFederationDomainSecretsController(
|
||||
secretHelper,
|
||||
nil, // kubeClient, not needed
|
||||
nil, // pinnipedClient, not needed
|
||||
@@ -223,7 +223,7 @@ func TestNewOIDCProviderSecretsControllerFilterOPC(t *testing.T) {
|
||||
withInformer.WithInformer,
|
||||
)
|
||||
|
||||
unrelated := configv1alpha1.OIDCProvider{}
|
||||
unrelated := configv1alpha1.FederationDomain{}
|
||||
filter := withInformer.GetFilterForInformer(opcInformer)
|
||||
require.Equal(t, test.wantAdd, filter.Add(&test.opc))
|
||||
require.Equal(t, test.wantUpdate, filter.Update(&unrelated, &test.opc))
|
||||
@@ -234,7 +234,7 @@ func TestNewOIDCProviderSecretsControllerFilterOPC(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
func TestFederationDomainSecretsControllerSync(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
@@ -250,7 +250,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
opGVR := schema.GroupVersionResource{
|
||||
Group: configv1alpha1.SchemeGroupVersion.Group,
|
||||
Version: configv1alpha1.SchemeGroupVersion.Version,
|
||||
Resource: "oidcproviders",
|
||||
Resource: "federationdomains",
|
||||
}
|
||||
|
||||
secretGVR := schema.GroupVersionResource{
|
||||
@@ -259,7 +259,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
Resource: "secrets",
|
||||
}
|
||||
|
||||
goodOP := &configv1alpha1.OIDCProvider{
|
||||
goodOP := &configv1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: opName,
|
||||
Namespace: namespace,
|
||||
@@ -275,7 +275,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: opGVR.GroupVersion().String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: opName,
|
||||
UID: opUID,
|
||||
BlockOwnerDeletion: boolPtr(true),
|
||||
@@ -304,7 +304,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: opGVR.GroupVersion().String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: opName,
|
||||
UID: opUID,
|
||||
BlockOwnerDeletion: boolPtr(true),
|
||||
@@ -316,7 +316,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
storage func(**configv1alpha1.OIDCProvider, **corev1.Secret)
|
||||
storage func(**configv1alpha1.FederationDomain, **corev1.Secret)
|
||||
client func(*pinnipedfake.Clientset, *kubernetesfake.Clientset)
|
||||
secretHelper func(*mocksecrethelper.MockSecretHelper)
|
||||
wantOPActions []kubetesting.Action
|
||||
@@ -324,26 +324,26 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
wantError string
|
||||
}{
|
||||
{
|
||||
name: "OIDCProvider does not exist and secret does not exist",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain does not exist and secret does not exist",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*op = nil
|
||||
*s = nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider does not exist and secret exists",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain does not exist and secret exists",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*op = nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and secret does not exist",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain exists and secret does not exist",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*s = nil
|
||||
},
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(goodSecret, nil)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentOIDCProvider(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentFederationDomain(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
},
|
||||
wantOPActions: []kubetesting.Action{
|
||||
kubetesting.NewGetAction(opGVR, namespace, goodOP.Name),
|
||||
@@ -355,14 +355,14 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and invalid secret exists",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain exists and invalid secret exists",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*s = invalidSecret.DeepCopy()
|
||||
},
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(goodSecret, nil)
|
||||
secretHelper.EXPECT().IsValid(goodOP, invalidSecret).Times(2).Return(false)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentOIDCProvider(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentFederationDomain(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
},
|
||||
wantOPActions: []kubetesting.Action{
|
||||
kubetesting.NewGetAction(opGVR, namespace, goodOP.Name),
|
||||
@@ -374,14 +374,14 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and generating a secret fails",
|
||||
name: "FederationDomain exists and generating a secret fails",
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(nil, errors.New("some generate error"))
|
||||
},
|
||||
wantError: "failed to generate secret: some generate error",
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and invalid secret exists and upon update we learn of a valid secret",
|
||||
name: "FederationDomain exists and invalid secret exists and upon update we learn of a valid secret",
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
otherSecret := goodSecret.DeepCopy()
|
||||
otherSecret.UID = "other-secret-uid"
|
||||
@@ -389,7 +389,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(otherSecret, nil)
|
||||
secretHelper.EXPECT().IsValid(goodOP, goodSecret).Times(1).Return(false)
|
||||
secretHelper.EXPECT().IsValid(goodOP, goodSecret).Times(1).Return(true)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentOIDCProvider(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentFederationDomain(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
},
|
||||
wantOPActions: []kubetesting.Action{
|
||||
kubetesting.NewGetAction(opGVR, namespace, goodOP.Name),
|
||||
@@ -400,7 +400,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and invalid secret exists and getting secret fails",
|
||||
name: "FederationDomain exists and invalid secret exists and getting secret fails",
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(goodSecret, nil)
|
||||
secretHelper.EXPECT().IsValid(goodOP, goodSecret).Times(1).Return(false)
|
||||
@@ -416,8 +416,8 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
wantError: fmt.Sprintf("failed to create or update secret: failed to get secret %s/%s: some get error", namespace, goodSecret.Name),
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and secret does not exist and creating secret fails",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain exists and secret does not exist and creating secret fails",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*s = nil
|
||||
},
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
@@ -435,7 +435,7 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
wantError: fmt.Sprintf("failed to create or update secret: failed to create secret %s/%s: some create error", namespace, goodSecret.Name),
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and invalid secret exists and updating secret fails",
|
||||
name: "FederationDomain exists and invalid secret exists and updating secret fails",
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(goodSecret, nil)
|
||||
secretHelper.EXPECT().IsValid(goodOP, goodSecret).Times(2).Return(false)
|
||||
@@ -452,14 +452,14 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
wantError: "failed to create or update secret: some update error",
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and invalid secret exists and updating secret fails due to conflict",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain exists and invalid secret exists and updating secret fails due to conflict",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*s = invalidSecret.DeepCopy()
|
||||
},
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(goodSecret, nil)
|
||||
secretHelper.EXPECT().IsValid(goodOP, invalidSecret).Times(3).Return(false)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentOIDCProvider(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentFederationDomain(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
},
|
||||
client: func(_ *pinnipedfake.Clientset, c *kubernetesfake.Clientset) {
|
||||
once := sync.Once{}
|
||||
@@ -481,17 +481,17 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and invalid secret exists and getting OIDCProvider fails",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain exists and invalid secret exists and getting FederationDomain fails",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*s = invalidSecret.DeepCopy()
|
||||
},
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(goodSecret, nil)
|
||||
secretHelper.EXPECT().IsValid(goodOP, invalidSecret).Times(2).Return(false)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentOIDCProvider(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentFederationDomain(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
},
|
||||
client: func(c *pinnipedfake.Clientset, _ *kubernetesfake.Clientset) {
|
||||
c.PrependReactor("get", "oidcproviders", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
c.PrependReactor("get", "federationdomains", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, errors.New("some get error")
|
||||
})
|
||||
},
|
||||
@@ -502,21 +502,21 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
kubetesting.NewGetAction(secretGVR, namespace, goodSecret.Name),
|
||||
kubetesting.NewUpdateAction(secretGVR, namespace, goodSecret),
|
||||
},
|
||||
wantError: fmt.Sprintf("failed to update oidcprovider: failed to get oidcprovider %s/%s: some get error", goodOPWithStatus.Namespace, goodOPWithStatus.Name),
|
||||
wantError: fmt.Sprintf("failed to update federationdomain: failed to get federationdomain %s/%s: some get error", goodOPWithStatus.Namespace, goodOPWithStatus.Name),
|
||||
},
|
||||
{
|
||||
name: "OIDCProvider exists and invalid secret exists and updating OIDCProvider fails due to conflict",
|
||||
storage: func(op **configv1alpha1.OIDCProvider, s **corev1.Secret) {
|
||||
name: "FederationDomain exists and invalid secret exists and updating FederationDomain fails due to conflict",
|
||||
storage: func(op **configv1alpha1.FederationDomain, s **corev1.Secret) {
|
||||
*s = invalidSecret.DeepCopy()
|
||||
},
|
||||
secretHelper: func(secretHelper *mocksecrethelper.MockSecretHelper) {
|
||||
secretHelper.EXPECT().Generate(goodOP).Times(1).Return(goodSecret, nil)
|
||||
secretHelper.EXPECT().IsValid(goodOP, invalidSecret).Times(2).Return(false)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentOIDCProvider(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
secretHelper.EXPECT().ObserveActiveSecretAndUpdateParentFederationDomain(goodOP, goodSecret).Times(1).Return(goodOPWithStatus)
|
||||
},
|
||||
client: func(c *pinnipedfake.Clientset, _ *kubernetesfake.Clientset) {
|
||||
once := sync.Once{}
|
||||
c.PrependReactor("update", "oidcproviders", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
c.PrependReactor("update", "federationdomains", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
var err error
|
||||
once.Do(func() { err = k8serrors.NewConflict(secretGVR.GroupResource(), namespace, errors.New("some error")) })
|
||||
return true, nil, err
|
||||
@@ -583,12 +583,12 @@ func TestOIDCProviderSecretsControllerSync(t *testing.T) {
|
||||
test.secretHelper(secretHelper)
|
||||
}
|
||||
|
||||
c := NewOIDCProviderSecretsController(
|
||||
c := NewFederationDomainSecretsController(
|
||||
secretHelper,
|
||||
kubeAPIClient,
|
||||
pinnipedAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
pinnipedInformers.Config().V1alpha1().OIDCProviders(),
|
||||
pinnipedInformers.Config().V1alpha1().FederationDomains(),
|
||||
controllerlib.WithInformer,
|
||||
)
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
// A SecretHelper has a NamePrefix() that can be used to identify it from other SecretHelper instances.
|
||||
type SecretHelper interface {
|
||||
NamePrefix() string
|
||||
Generate(*configv1alpha1.OIDCProvider) (*corev1.Secret, error)
|
||||
IsValid(*configv1alpha1.OIDCProvider, *corev1.Secret) bool
|
||||
ObserveActiveSecretAndUpdateParentOIDCProvider(*configv1alpha1.OIDCProvider, *corev1.Secret) *configv1alpha1.OIDCProvider
|
||||
Generate(*configv1alpha1.FederationDomain) (*corev1.Secret, error)
|
||||
IsValid(*configv1alpha1.FederationDomain, *corev1.Secret) bool
|
||||
ObserveActiveSecretAndUpdateParentFederationDomain(*configv1alpha1.FederationDomain, *corev1.Secret) *configv1alpha1.FederationDomain
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -39,7 +39,7 @@ const (
|
||||
)
|
||||
|
||||
// SecretUsage describes how a cryptographic secret is going to be used. It is currently used to
|
||||
// indicate to a SecretHelper which status field to set on the parent OIDCProvider for a Secret.
|
||||
// indicate to a SecretHelper which status field to set on the parent FederationDomain for a Secret.
|
||||
type SecretUsage int
|
||||
|
||||
const (
|
||||
@@ -77,7 +77,7 @@ type symmetricSecretHelper struct {
|
||||
func (s *symmetricSecretHelper) NamePrefix() string { return s.namePrefix }
|
||||
|
||||
// Generate implements SecretHelper.Generate().
|
||||
func (s *symmetricSecretHelper) Generate(parent *configv1alpha1.OIDCProvider) (*corev1.Secret, error) {
|
||||
func (s *symmetricSecretHelper) Generate(parent *configv1alpha1.FederationDomain) (*corev1.Secret, error) {
|
||||
key := make([]byte, symmetricKeySize)
|
||||
if _, err := s.rand.Read(key); err != nil {
|
||||
return nil, err
|
||||
@@ -92,7 +92,7 @@ func (s *symmetricSecretHelper) Generate(parent *configv1alpha1.OIDCProvider) (*
|
||||
*metav1.NewControllerRef(parent, schema.GroupVersionKind{
|
||||
Group: configv1alpha1.SchemeGroupVersion.Group,
|
||||
Version: configv1alpha1.SchemeGroupVersion.Version,
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -104,7 +104,7 @@ func (s *symmetricSecretHelper) Generate(parent *configv1alpha1.OIDCProvider) (*
|
||||
}
|
||||
|
||||
// IsValid implements SecretHelper.IsValid().
|
||||
func (s *symmetricSecretHelper) IsValid(parent *configv1alpha1.OIDCProvider, secret *corev1.Secret) bool {
|
||||
func (s *symmetricSecretHelper) IsValid(parent *configv1alpha1.FederationDomain, secret *corev1.Secret) bool {
|
||||
if !metav1.IsControlledBy(secret, parent) {
|
||||
return false
|
||||
}
|
||||
@@ -124,11 +124,11 @@ func (s *symmetricSecretHelper) IsValid(parent *configv1alpha1.OIDCProvider, sec
|
||||
return true
|
||||
}
|
||||
|
||||
// ObserveActiveSecretAndUpdateParentOIDCProvider implements SecretHelper.ObserveActiveSecretAndUpdateParentOIDCProvider().
|
||||
func (s *symmetricSecretHelper) ObserveActiveSecretAndUpdateParentOIDCProvider(
|
||||
op *configv1alpha1.OIDCProvider,
|
||||
// ObserveActiveSecretAndUpdateParentFederationDomain implements SecretHelper.ObserveActiveSecretAndUpdateParentFederationDomain().
|
||||
func (s *symmetricSecretHelper) ObserveActiveSecretAndUpdateParentFederationDomain(
|
||||
op *configv1alpha1.FederationDomain,
|
||||
secret *corev1.Secret,
|
||||
) *configv1alpha1.OIDCProvider {
|
||||
) *configv1alpha1.FederationDomain {
|
||||
var cacheKey string
|
||||
if op != nil {
|
||||
cacheKey = op.Spec.Issuer
|
||||
|
||||
@@ -21,28 +21,28 @@ func TestSymmetricSecretHelper(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
secretUsage SecretUsage
|
||||
wantSetOIDCProviderField func(*configv1alpha1.OIDCProvider) string
|
||||
name string
|
||||
secretUsage SecretUsage
|
||||
wantSetFederationDomainField func(*configv1alpha1.FederationDomain) string
|
||||
}{
|
||||
{
|
||||
name: "token signing key",
|
||||
secretUsage: SecretUsageTokenSigningKey,
|
||||
wantSetOIDCProviderField: func(op *configv1alpha1.OIDCProvider) string {
|
||||
wantSetFederationDomainField: func(op *configv1alpha1.FederationDomain) string {
|
||||
return op.Status.Secrets.TokenSigningKey.Name
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "state signing key",
|
||||
secretUsage: SecretUsageStateSigningKey,
|
||||
wantSetOIDCProviderField: func(op *configv1alpha1.OIDCProvider) string {
|
||||
wantSetFederationDomainField: func(op *configv1alpha1.FederationDomain) string {
|
||||
return op.Status.Secrets.StateSigningKey.Name
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "state encryption key",
|
||||
secretUsage: SecretUsageStateEncryptionKey,
|
||||
wantSetOIDCProviderField: func(op *configv1alpha1.OIDCProvider) string {
|
||||
wantSetFederationDomainField: func(op *configv1alpha1.FederationDomain) string {
|
||||
return op.Status.Secrets.StateEncryptionKey.Name
|
||||
},
|
||||
},
|
||||
@@ -57,21 +57,21 @@ func TestSymmetricSecretHelper(t *testing.T) {
|
||||
"some-label-key-2": "some-label-value-2",
|
||||
}
|
||||
randSource := strings.NewReader(keyWith32Bytes)
|
||||
var oidcProviderIssuerValue string
|
||||
var federationDomainIssuerValue string
|
||||
var symmetricKeyValue []byte
|
||||
h := NewSymmetricSecretHelper(
|
||||
"some-name-prefix-",
|
||||
labels,
|
||||
randSource,
|
||||
test.secretUsage,
|
||||
func(oidcProviderIssuer string, symmetricKey []byte) {
|
||||
require.True(t, oidcProviderIssuer == "" && symmetricKeyValue == nil, "expected notify func not to have been called yet")
|
||||
oidcProviderIssuerValue = oidcProviderIssuer
|
||||
func(federationDomainIssuer string, symmetricKey []byte) {
|
||||
require.True(t, federationDomainIssuer == "" && symmetricKeyValue == nil, "expected notify func not to have been called yet")
|
||||
federationDomainIssuerValue = federationDomainIssuer
|
||||
symmetricKeyValue = symmetricKey
|
||||
},
|
||||
)
|
||||
|
||||
parent := &configv1alpha1.OIDCProvider{
|
||||
parent := &configv1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "some-uid",
|
||||
Namespace: "some-namespace",
|
||||
@@ -88,7 +88,7 @@ func TestSymmetricSecretHelper(t *testing.T) {
|
||||
*metav1.NewControllerRef(parent, schema.GroupVersionKind{
|
||||
Group: configv1alpha1.SchemeGroupVersion.Group,
|
||||
Version: configv1alpha1.SchemeGroupVersion.Version,
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -100,9 +100,9 @@ func TestSymmetricSecretHelper(t *testing.T) {
|
||||
|
||||
require.True(t, h.IsValid(parent, child))
|
||||
|
||||
h.ObserveActiveSecretAndUpdateParentOIDCProvider(parent, child)
|
||||
require.Equal(t, parent.Spec.Issuer, oidcProviderIssuerValue)
|
||||
require.Equal(t, child.Name, test.wantSetOIDCProviderField(parent))
|
||||
h.ObserveActiveSecretAndUpdateParentFederationDomain(parent, child)
|
||||
require.Equal(t, parent.Spec.Issuer, federationDomainIssuerValue)
|
||||
require.Equal(t, child.Name, test.wantSetFederationDomainField(parent))
|
||||
require.Equal(t, child.Data["key"], symmetricKeyValue)
|
||||
})
|
||||
}
|
||||
@@ -112,7 +112,7 @@ func TestSymmetricSecretHelperIsValid(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
child func(*corev1.Secret)
|
||||
parent func(*configv1alpha1.OIDCProvider)
|
||||
parent func(*configv1alpha1.FederationDomain)
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
@@ -145,7 +145,7 @@ func TestSymmetricSecretHelperIsValid(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "child not owned by parent",
|
||||
parent: func(op *configv1alpha1.OIDCProvider) {
|
||||
parent: func(op *configv1alpha1.FederationDomain) {
|
||||
op.UID = "wrong"
|
||||
},
|
||||
want: false,
|
||||
@@ -160,7 +160,7 @@ func TestSymmetricSecretHelperIsValid(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
h := NewSymmetricSecretHelper("none of these args matter", nil, nil, SecretUsageTokenSigningKey, nil)
|
||||
|
||||
parent := &configv1alpha1.OIDCProvider{
|
||||
parent := &configv1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "some-parent-name",
|
||||
Namespace: "some-namespace",
|
||||
@@ -175,7 +175,7 @@ func TestSymmetricSecretHelperIsValid(t *testing.T) {
|
||||
*metav1.NewControllerRef(parent, schema.GroupVersionKind{
|
||||
Group: configv1alpha1.SchemeGroupVersion.Group,
|
||||
Version: configv1alpha1.SchemeGroupVersion.Version,
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,9 +18,9 @@ import (
|
||||
)
|
||||
|
||||
type jwksObserverController struct {
|
||||
issuerToJWKSSetter IssuerToJWKSMapSetter
|
||||
oidcProviderInformer v1alpha1.OIDCProviderInformer
|
||||
secretInformer corev1informers.SecretInformer
|
||||
issuerToJWKSSetter IssuerToJWKSMapSetter
|
||||
federationDomainInformer v1alpha1.FederationDomainInformer
|
||||
secretInformer corev1informers.SecretInformer
|
||||
}
|
||||
|
||||
type IssuerToJWKSMapSetter interface {
|
||||
@@ -30,7 +30,7 @@ type IssuerToJWKSMapSetter interface {
|
||||
)
|
||||
}
|
||||
|
||||
// Returns a controller which watches all of the OIDCProviders and their corresponding Secrets
|
||||
// Returns a controller which watches all of the FederationDomains and their corresponding Secrets
|
||||
// and fills an in-memory cache of the JWKS info for each currently configured issuer.
|
||||
// This controller assumes that the informers passed to it are already scoped down to the
|
||||
// appropriate namespace. It also assumes that the IssuerToJWKSMapSetter passed to it has an
|
||||
@@ -38,16 +38,16 @@ type IssuerToJWKSMapSetter interface {
|
||||
func NewJWKSObserverController(
|
||||
issuerToJWKSSetter IssuerToJWKSMapSetter,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
oidcProviderInformer v1alpha1.OIDCProviderInformer,
|
||||
federationDomainInformer v1alpha1.FederationDomainInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: "jwks-observer-controller",
|
||||
Syncer: &jwksObserverController{
|
||||
issuerToJWKSSetter: issuerToJWKSSetter,
|
||||
oidcProviderInformer: oidcProviderInformer,
|
||||
secretInformer: secretInformer,
|
||||
issuerToJWKSSetter: issuerToJWKSSetter,
|
||||
federationDomainInformer: federationDomainInformer,
|
||||
secretInformer: secretInformer,
|
||||
},
|
||||
},
|
||||
withInformer(
|
||||
@@ -56,7 +56,7 @@ func NewJWKSObserverController(
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
withInformer(
|
||||
oidcProviderInformer,
|
||||
federationDomainInformer,
|
||||
pinnipedcontroller.MatchAnythingFilter(nil),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
@@ -65,12 +65,12 @@ func NewJWKSObserverController(
|
||||
|
||||
func (c *jwksObserverController) Sync(ctx controllerlib.Context) error {
|
||||
ns := ctx.Key.Namespace
|
||||
allProviders, err := c.oidcProviderInformer.Lister().OIDCProviders(ns).List(labels.Everything())
|
||||
allProviders, err := c.federationDomainInformer.Lister().FederationDomains(ns).List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list OIDCProviders: %w", err)
|
||||
return fmt.Errorf("failed to list FederationDomains: %w", err)
|
||||
}
|
||||
|
||||
// Rebuild the whole map on any change to any Secret or OIDCProvider, because either can have changes that
|
||||
// Rebuild the whole map on any change to any Secret or FederationDomain, because either can have changes that
|
||||
// can cause the map to need to be updated.
|
||||
issuerToJWKSMap := map[string]*jose.JSONWebKeySet{}
|
||||
issuerToActiveJWKMap := map[string]*jose.JSONWebKey{}
|
||||
|
||||
@@ -28,25 +28,25 @@ import (
|
||||
func TestJWKSObserverControllerInformerFilters(t *testing.T) {
|
||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||
var (
|
||||
r *require.Assertions
|
||||
observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||
secretsInformerFilter controllerlib.Filter
|
||||
oidcProviderInformerFilter controllerlib.Filter
|
||||
r *require.Assertions
|
||||
observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||
secretsInformerFilter controllerlib.Filter
|
||||
federationDomainInformerFilter controllerlib.Filter
|
||||
)
|
||||
|
||||
it.Before(func() {
|
||||
r = require.New(t)
|
||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
oidcProviderInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Config().V1alpha1().OIDCProviders()
|
||||
federationDomainInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Config().V1alpha1().FederationDomains()
|
||||
_ = NewJWKSObserverController(
|
||||
nil,
|
||||
secretsInformer,
|
||||
oidcProviderInformer,
|
||||
federationDomainInformer,
|
||||
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
||||
)
|
||||
secretsInformerFilter = observableWithInformerOption.GetFilterForInformer(secretsInformer)
|
||||
oidcProviderInformerFilter = observableWithInformerOption.GetFilterForInformer(oidcProviderInformer)
|
||||
federationDomainInformerFilter = observableWithInformerOption.GetFilterForInformer(federationDomainInformer)
|
||||
})
|
||||
|
||||
when("watching Secret objects", func() {
|
||||
@@ -71,19 +71,19 @@ func TestJWKSObserverControllerInformerFilters(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
when("watching OIDCProvider objects", func() {
|
||||
when("watching FederationDomain objects", func() {
|
||||
var (
|
||||
subject controllerlib.Filter
|
||||
provider, otherProvider *v1alpha1.OIDCProvider
|
||||
provider, otherProvider *v1alpha1.FederationDomain
|
||||
)
|
||||
|
||||
it.Before(func() {
|
||||
subject = oidcProviderInformerFilter
|
||||
provider = &v1alpha1.OIDCProvider{ObjectMeta: metav1.ObjectMeta{Name: "any-name", Namespace: "any-namespace"}}
|
||||
otherProvider = &v1alpha1.OIDCProvider{ObjectMeta: metav1.ObjectMeta{Name: "any-other-name", Namespace: "any-other-namespace"}}
|
||||
subject = federationDomainInformerFilter
|
||||
provider = &v1alpha1.FederationDomain{ObjectMeta: metav1.ObjectMeta{Name: "any-name", Namespace: "any-namespace"}}
|
||||
otherProvider = &v1alpha1.FederationDomain{ObjectMeta: metav1.ObjectMeta{Name: "any-other-name", Namespace: "any-other-namespace"}}
|
||||
})
|
||||
|
||||
when("any OIDCProvider changes", func() {
|
||||
when("any FederationDomain changes", func() {
|
||||
it("returns true to trigger the sync method", func() {
|
||||
r.True(subject.Add(provider))
|
||||
r.True(subject.Update(provider, otherProvider))
|
||||
@@ -134,7 +134,7 @@ func TestJWKSObserverControllerSync(t *testing.T) {
|
||||
subject = NewJWKSObserverController(
|
||||
issuerToJWKSSetter,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
pinnipedInformers.Config().V1alpha1().OIDCProviders(),
|
||||
pinnipedInformers.Config().V1alpha1().FederationDomains(),
|
||||
controllerlib.WithInformer,
|
||||
)
|
||||
|
||||
@@ -178,7 +178,7 @@ func TestJWKSObserverControllerSync(t *testing.T) {
|
||||
timeoutContextCancel()
|
||||
})
|
||||
|
||||
when("there are no OIDCProviders and no JWKS Secrets yet", func() {
|
||||
when("there are no FederationDomains and no JWKS Secrets yet", func() {
|
||||
it("sets the issuerToJWKSSetter's map to be empty", func() {
|
||||
startInformersAndController()
|
||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||
@@ -190,84 +190,84 @@ func TestJWKSObserverControllerSync(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
when("there are OIDCProviders where some have corresponding JWKS Secrets and some don't", func() {
|
||||
when("there are FederationDomains where some have corresponding JWKS Secrets and some don't", func() {
|
||||
var (
|
||||
expectedJWK1, expectedJWK2 string
|
||||
)
|
||||
|
||||
it.Before(func() {
|
||||
oidcProviderWithoutSecret1 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithoutSecret1 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "no-secret-oidcprovider1",
|
||||
Name: "no-secret-federationdomain1",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://no-secret-issuer1.com"},
|
||||
Status: v1alpha1.OIDCProviderStatus{}, // no Secrets.JWKS field
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://no-secret-issuer1.com"},
|
||||
Status: v1alpha1.FederationDomainStatus{}, // no Secrets.JWKS field
|
||||
}
|
||||
oidcProviderWithoutSecret2 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithoutSecret2 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "no-secret-oidcprovider2",
|
||||
Name: "no-secret-federationdomain2",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://no-secret-issuer2.com"},
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://no-secret-issuer2.com"},
|
||||
// no Status field
|
||||
}
|
||||
oidcProviderWithBadSecret := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithBadSecret := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bad-secret-oidcprovider",
|
||||
Name: "bad-secret-federationdomain",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://bad-secret-issuer.com"},
|
||||
Status: v1alpha1.OIDCProviderStatus{
|
||||
Secrets: v1alpha1.OIDCProviderSecrets{
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://bad-secret-issuer.com"},
|
||||
Status: v1alpha1.FederationDomainStatus{
|
||||
Secrets: v1alpha1.FederationDomainSecrets{
|
||||
JWKS: corev1.LocalObjectReference{Name: "bad-secret-name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
oidcProviderWithBadJWKSSecret := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithBadJWKSSecret := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bad-jwks-secret-oidcprovider",
|
||||
Name: "bad-jwks-secret-federationdomain",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://bad-jwks-secret-issuer.com"},
|
||||
Status: v1alpha1.OIDCProviderStatus{
|
||||
Secrets: v1alpha1.OIDCProviderSecrets{
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://bad-jwks-secret-issuer.com"},
|
||||
Status: v1alpha1.FederationDomainStatus{
|
||||
Secrets: v1alpha1.FederationDomainSecrets{
|
||||
JWKS: corev1.LocalObjectReference{Name: "bad-jwks-secret-name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
oidcProviderWithBadActiveJWKSecret := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithBadActiveJWKSecret := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bad-active-jwk-secret-oidcprovider",
|
||||
Name: "bad-active-jwk-secret-federationdomain",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://bad-active-jwk-secret-issuer.com"},
|
||||
Status: v1alpha1.OIDCProviderStatus{
|
||||
Secrets: v1alpha1.OIDCProviderSecrets{
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://bad-active-jwk-secret-issuer.com"},
|
||||
Status: v1alpha1.FederationDomainStatus{
|
||||
Secrets: v1alpha1.FederationDomainSecrets{
|
||||
JWKS: corev1.LocalObjectReference{Name: "bad-active-jwk-secret-name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
oidcProviderWithGoodSecret1 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithGoodSecret1 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "good-secret-oidcprovider1",
|
||||
Name: "good-secret-federationdomain1",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://issuer-with-good-secret1.com"},
|
||||
Status: v1alpha1.OIDCProviderStatus{
|
||||
Secrets: v1alpha1.OIDCProviderSecrets{
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer-with-good-secret1.com"},
|
||||
Status: v1alpha1.FederationDomainStatus{
|
||||
Secrets: v1alpha1.FederationDomainSecrets{
|
||||
JWKS: corev1.LocalObjectReference{Name: "good-jwks-secret-name1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
oidcProviderWithGoodSecret2 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithGoodSecret2 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "good-secret-oidcprovider2",
|
||||
Name: "good-secret-federationdomain2",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://issuer-with-good-secret2.com"},
|
||||
Status: v1alpha1.OIDCProviderStatus{
|
||||
Secrets: v1alpha1.OIDCProviderSecrets{
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer-with-good-secret2.com"},
|
||||
Status: v1alpha1.FederationDomainStatus{
|
||||
Secrets: v1alpha1.FederationDomainSecrets{
|
||||
JWKS: corev1.LocalObjectReference{Name: "good-jwks-secret-name2"},
|
||||
},
|
||||
},
|
||||
@@ -323,13 +323,13 @@ func TestJWKSObserverControllerSync(t *testing.T) {
|
||||
"jwks": []byte(`{"keys": [` + expectedJWK2 + `]}`),
|
||||
},
|
||||
}
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithoutSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithoutSecret2))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithBadSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithBadJWKSSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithBadActiveJWKSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithGoodSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithGoodSecret2))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithoutSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithoutSecret2))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithBadSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithBadJWKSSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithBadActiveJWKSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithGoodSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithGoodSecret2))
|
||||
r.NoError(kubeInformerClient.Tracker().Add(goodJWKSSecret1))
|
||||
r.NoError(kubeInformerClient.Tracker().Add(goodJWKSSecret2))
|
||||
r.NoError(kubeInformerClient.Tracker().Add(badSecret))
|
||||
|
||||
@@ -43,7 +43,7 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
opcKind = "OIDCProvider"
|
||||
opcKind = "FederationDomain"
|
||||
)
|
||||
|
||||
// generateKey is stubbed out for the purpose of testing. The default behavior is to generate an EC key.
|
||||
@@ -60,7 +60,7 @@ type jwksWriterController struct {
|
||||
jwksSecretLabels map[string]string
|
||||
pinnipedClient pinnipedclientset.Interface
|
||||
kubeClient kubernetes.Interface
|
||||
opcInformer configinformers.OIDCProviderInformer
|
||||
opcInformer configinformers.FederationDomainInformer
|
||||
secretInformer corev1informers.SecretInformer
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func NewJWKSWriterController(
|
||||
kubeClient kubernetes.Interface,
|
||||
pinnipedClient pinnipedclientset.Interface,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
opcInformer configinformers.OIDCProviderInformer,
|
||||
opcInformer configinformers.FederationDomainInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
@@ -119,11 +119,11 @@ func NewJWKSWriterController(
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
func (c *jwksWriterController) Sync(ctx controllerlib.Context) error {
|
||||
opc, err := c.opcInformer.Lister().OIDCProviders(ctx.Key.Namespace).Get(ctx.Key.Name)
|
||||
opc, err := c.opcInformer.Lister().FederationDomains(ctx.Key.Namespace).Get(ctx.Key.Name)
|
||||
notFound := k8serrors.IsNotFound(err)
|
||||
if err != nil && !notFound {
|
||||
return fmt.Errorf(
|
||||
"failed to get %s/%s OIDCProvider: %w",
|
||||
"failed to get %s/%s FederationDomain: %w",
|
||||
ctx.Key.Namespace,
|
||||
ctx.Key.Name,
|
||||
err,
|
||||
@@ -134,8 +134,8 @@ func (c *jwksWriterController) Sync(ctx controllerlib.Context) error {
|
||||
// The corresponding secret to this OPC should have been garbage collected since it should have
|
||||
// had this OPC as its owner.
|
||||
plog.Debug(
|
||||
"oidcprovider deleted",
|
||||
"oidcprovider",
|
||||
"federationdomain deleted",
|
||||
"federationdomain",
|
||||
klog.KRef(ctx.Key.Namespace, ctx.Key.Name),
|
||||
)
|
||||
return nil
|
||||
@@ -149,7 +149,7 @@ func (c *jwksWriterController) Sync(ctx controllerlib.Context) error {
|
||||
// Secret is up to date - we are good to go.
|
||||
plog.Debug(
|
||||
"secret is up to date",
|
||||
"oidcprovider",
|
||||
"federationdomain",
|
||||
klog.KRef(ctx.Key.Namespace, ctx.Key.Name),
|
||||
)
|
||||
return nil
|
||||
@@ -173,12 +173,12 @@ func (c *jwksWriterController) Sync(ctx controllerlib.Context) error {
|
||||
if err := c.updateOPC(ctx.Context, newOPC); err != nil {
|
||||
return fmt.Errorf("cannot update opc: %w", err)
|
||||
}
|
||||
plog.Debug("updated oidcprovider", "oidcprovider", klog.KObj(newOPC))
|
||||
plog.Debug("updated federationdomain", "federationdomain", klog.KObj(newOPC))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *jwksWriterController) secretNeedsUpdate(opc *configv1alpha1.OIDCProvider) (bool, error) {
|
||||
func (c *jwksWriterController) secretNeedsUpdate(opc *configv1alpha1.FederationDomain) (bool, error) {
|
||||
if opc.Status.Secrets.JWKS.Name == "" {
|
||||
// If the OPC says it doesn't have a secret associated with it, then let's create one.
|
||||
return true, nil
|
||||
@@ -203,7 +203,7 @@ func (c *jwksWriterController) secretNeedsUpdate(opc *configv1alpha1.OIDCProvide
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *jwksWriterController) generateSecret(opc *configv1alpha1.OIDCProvider) (*corev1.Secret, error) {
|
||||
func (c *jwksWriterController) generateSecret(opc *configv1alpha1.FederationDomain) (*corev1.Secret, error) {
|
||||
// Note! This is where we could potentially add more handling of OPC spec fields which tell us how
|
||||
// this OIDC provider should sign and verify ID tokens (e.g., hardcoded token secret, gRPC
|
||||
// connection to KMS, etc).
|
||||
@@ -292,9 +292,9 @@ func (c *jwksWriterController) createOrUpdateSecret(
|
||||
|
||||
func (c *jwksWriterController) updateOPC(
|
||||
ctx context.Context,
|
||||
newOPC *configv1alpha1.OIDCProvider,
|
||||
newOPC *configv1alpha1.FederationDomain,
|
||||
) error {
|
||||
opcClient := c.pinnipedClient.ConfigV1alpha1().OIDCProviders(newOPC.Namespace)
|
||||
opcClient := c.pinnipedClient.ConfigV1alpha1().FederationDomains(newOPC.Namespace)
|
||||
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
oldOPC, err := opcClient.Get(ctx, newOPC.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
|
||||
@@ -54,7 +54,7 @@ func TestJWKSWriterControllerFilterSecret(t *testing.T) {
|
||||
Namespace: "some-namespace",
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
Controller: boolPtr(true),
|
||||
},
|
||||
@@ -85,7 +85,7 @@ func TestJWKSWriterControllerFilterSecret(t *testing.T) {
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
},
|
||||
},
|
||||
@@ -100,7 +100,7 @@ func TestJWKSWriterControllerFilterSecret(t *testing.T) {
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
Controller: boolPtr(true),
|
||||
},
|
||||
@@ -123,7 +123,7 @@ func TestJWKSWriterControllerFilterSecret(t *testing.T) {
|
||||
},
|
||||
{
|
||||
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: "some-name",
|
||||
Controller: boolPtr(true),
|
||||
},
|
||||
@@ -148,7 +148,7 @@ func TestJWKSWriterControllerFilterSecret(t *testing.T) {
|
||||
opcInformer := pinnipedinformers.NewSharedInformerFactory(
|
||||
pinnipedfake.NewSimpleClientset(),
|
||||
0,
|
||||
).Config().V1alpha1().OIDCProviders()
|
||||
).Config().V1alpha1().FederationDomains()
|
||||
withInformer := testutil.NewObservableWithInformerOption()
|
||||
_ = NewJWKSWriterController(
|
||||
nil, // labels, not needed
|
||||
@@ -175,7 +175,7 @@ func TestJWKSWriterControllerFilterOPC(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
opc configv1alpha1.OIDCProvider
|
||||
opc configv1alpha1.FederationDomain
|
||||
wantAdd bool
|
||||
wantUpdate bool
|
||||
wantDelete bool
|
||||
@@ -183,7 +183,7 @@ func TestJWKSWriterControllerFilterOPC(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "anything goes",
|
||||
opc: configv1alpha1.OIDCProvider{},
|
||||
opc: configv1alpha1.FederationDomain{},
|
||||
wantAdd: true,
|
||||
wantUpdate: true,
|
||||
wantDelete: true,
|
||||
@@ -202,7 +202,7 @@ func TestJWKSWriterControllerFilterOPC(t *testing.T) {
|
||||
opcInformer := pinnipedinformers.NewSharedInformerFactory(
|
||||
pinnipedfake.NewSimpleClientset(),
|
||||
0,
|
||||
).Config().V1alpha1().OIDCProviders()
|
||||
).Config().V1alpha1().FederationDomains()
|
||||
withInformer := testutil.NewObservableWithInformerOption()
|
||||
_ = NewJWKSWriterController(
|
||||
nil, // labels, not needed
|
||||
@@ -213,7 +213,7 @@ func TestJWKSWriterControllerFilterOPC(t *testing.T) {
|
||||
withInformer.WithInformer,
|
||||
)
|
||||
|
||||
unrelated := configv1alpha1.OIDCProvider{}
|
||||
unrelated := configv1alpha1.FederationDomain{}
|
||||
filter := withInformer.GetFilterForInformer(opcInformer)
|
||||
require.Equal(t, test.wantAdd, filter.Add(&test.opc))
|
||||
require.Equal(t, test.wantUpdate, filter.Update(&unrelated, &test.opc))
|
||||
@@ -239,16 +239,16 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
opcGVR := schema.GroupVersionResource{
|
||||
Group: configv1alpha1.SchemeGroupVersion.Group,
|
||||
Version: configv1alpha1.SchemeGroupVersion.Version,
|
||||
Resource: "oidcproviders",
|
||||
Resource: "federationdomains",
|
||||
}
|
||||
|
||||
goodOPC := &configv1alpha1.OIDCProvider{
|
||||
goodOPC := &configv1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "good-opc",
|
||||
Namespace: namespace,
|
||||
UID: "good-opc-uid",
|
||||
},
|
||||
Spec: configv1alpha1.OIDCProviderSpec{
|
||||
Spec: configv1alpha1.FederationDomainSpec{
|
||||
Issuer: "https://some-issuer.com",
|
||||
},
|
||||
}
|
||||
@@ -273,7 +273,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: opcGVR.GroupVersion().String(),
|
||||
Kind: "OIDCProvider",
|
||||
Kind: "FederationDomain",
|
||||
Name: goodOPC.Name,
|
||||
UID: goodOPC.UID,
|
||||
BlockOwnerDeletion: boolPtr(true),
|
||||
@@ -300,7 +300,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
secrets []*corev1.Secret
|
||||
configKubeClient func(*kubernetesfake.Clientset)
|
||||
configPinnipedClient func(*pinnipedfake.Clientset)
|
||||
opcs []*configv1alpha1.OIDCProvider
|
||||
opcs []*configv1alpha1.FederationDomain
|
||||
generateKeyErr error
|
||||
wantGenerateKeyCount int
|
||||
wantSecretActions []kubetesting.Action
|
||||
@@ -310,7 +310,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "new opc with no secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPC,
|
||||
},
|
||||
wantGenerateKeyCount: 1,
|
||||
@@ -326,7 +326,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "opc without status with existing secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPC,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -344,7 +344,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "existing opc with no secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
wantGenerateKeyCount: 1,
|
||||
@@ -359,7 +359,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "existing opc with existing secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -374,7 +374,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "missing jwk in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -392,7 +392,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "missing jwks in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -410,7 +410,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "invalid jwk JSON in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -428,7 +428,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "invalid jwks JSON in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -446,7 +446,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "public jwk in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -464,7 +464,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "private jwks in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -482,7 +482,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "invalid jwk key in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -500,7 +500,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "invalid jwks key in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -518,7 +518,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "missing active jwks in secret",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -536,7 +536,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "generate key fails",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPCWithStatus,
|
||||
},
|
||||
generateKeyErr: errors.New("some generate error"),
|
||||
@@ -545,7 +545,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "get secret fails",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPC,
|
||||
},
|
||||
configKubeClient: func(client *kubernetesfake.Clientset) {
|
||||
@@ -558,7 +558,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "create secret fails",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPC,
|
||||
},
|
||||
configKubeClient: func(client *kubernetesfake.Clientset) {
|
||||
@@ -571,7 +571,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "update secret fails",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPC,
|
||||
},
|
||||
secrets: []*corev1.Secret{
|
||||
@@ -587,11 +587,11 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "get opc fails",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPC,
|
||||
},
|
||||
configPinnipedClient: func(client *pinnipedfake.Clientset) {
|
||||
client.PrependReactor("get", "oidcproviders", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
client.PrependReactor("get", "federationdomains", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, errors.New("some get error")
|
||||
})
|
||||
},
|
||||
@@ -600,11 +600,11 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
{
|
||||
name: "update opc fails",
|
||||
key: controllerlib.Key{Namespace: goodOPC.Namespace, Name: goodOPC.Name},
|
||||
opcs: []*configv1alpha1.OIDCProvider{
|
||||
opcs: []*configv1alpha1.FederationDomain{
|
||||
goodOPC,
|
||||
},
|
||||
configPinnipedClient: func(client *pinnipedfake.Clientset) {
|
||||
client.PrependReactor("update", "oidcproviders", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
client.PrependReactor("update", "federationdomains", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, errors.New("some update error")
|
||||
})
|
||||
},
|
||||
@@ -661,7 +661,7 @@ func TestJWKSWriterControllerSync(t *testing.T) {
|
||||
kubeAPIClient,
|
||||
pinnipedAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
pinnipedInformers.Config().V1alpha1().OIDCProviders(),
|
||||
pinnipedInformers.Config().V1alpha1().FederationDomains(),
|
||||
controllerlib.WithInformer,
|
||||
)
|
||||
|
||||
|
||||
@@ -29,29 +29,29 @@ import (
|
||||
// If there are no longer any valid issuers, then it can be called with no arguments.
|
||||
// Implementations of this type should be thread-safe to support calls from multiple goroutines.
|
||||
type ProvidersSetter interface {
|
||||
SetProviders(oidcProviders ...*provider.OIDCProvider)
|
||||
SetProviders(federationDomains ...*provider.FederationDomain)
|
||||
}
|
||||
|
||||
type oidcProviderWatcherController struct {
|
||||
type federationDomainWatcherController struct {
|
||||
providerSetter ProvidersSetter
|
||||
clock clock.Clock
|
||||
client pinnipedclientset.Interface
|
||||
opcInformer configinformers.OIDCProviderInformer
|
||||
opcInformer configinformers.FederationDomainInformer
|
||||
}
|
||||
|
||||
// NewOIDCProviderWatcherController creates a controllerlib.Controller that watches
|
||||
// OIDCProvider objects and notifies a callback object of the collection of provider configs.
|
||||
func NewOIDCProviderWatcherController(
|
||||
// NewFederationDomainWatcherController creates a controllerlib.Controller that watches
|
||||
// FederationDomain objects and notifies a callback object of the collection of provider configs.
|
||||
func NewFederationDomainWatcherController(
|
||||
providerSetter ProvidersSetter,
|
||||
clock clock.Clock,
|
||||
client pinnipedclientset.Interface,
|
||||
opcInformer configinformers.OIDCProviderInformer,
|
||||
opcInformer configinformers.FederationDomainInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: "OIDCProviderWatcherController",
|
||||
Syncer: &oidcProviderWatcherController{
|
||||
Name: "FederationDomainWatcherController",
|
||||
Syncer: &federationDomainWatcherController{
|
||||
providerSetter: providerSetter,
|
||||
clock: clock,
|
||||
client: client,
|
||||
@@ -67,7 +67,7 @@ func NewOIDCProviderWatcherController(
|
||||
}
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
func (c *oidcProviderWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
all, err := c.opcInformer.Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -82,7 +82,7 @@ func (c *oidcProviderWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
}
|
||||
|
||||
// Make a map of issuer hostnames -> set of unique secret names. This will help us complain when
|
||||
// multiple OIDCProviders have the same issuer hostname (excluding port) but specify
|
||||
// multiple FederationDomains have the same issuer hostname (excluding port) but specify
|
||||
// different TLS serving Secrets. Doesn't make sense to have the one address use more than one
|
||||
// TLS cert. Ignore ports because SNI information on the incoming requests is not going to include
|
||||
// port numbers. Also make a helper function for forming keys into this map.
|
||||
@@ -109,7 +109,7 @@ func (c *oidcProviderWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
|
||||
errs := multierror.New()
|
||||
|
||||
oidcProviders := make([]*provider.OIDCProvider, 0)
|
||||
federationDomains := make([]*provider.FederationDomain, 0)
|
||||
for _, opc := range all {
|
||||
issuerURL, urlParseErr := url.Parse(opc.Spec.Issuer)
|
||||
|
||||
@@ -120,7 +120,7 @@ func (c *oidcProviderWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
ctx.Context,
|
||||
opc.Namespace,
|
||||
opc.Name,
|
||||
configv1alpha1.DuplicateOIDCProviderStatusCondition,
|
||||
configv1alpha1.DuplicateFederationDomainStatusCondition,
|
||||
"Duplicate issuer: "+opc.Spec.Issuer,
|
||||
); err != nil {
|
||||
errs.Add(fmt.Errorf("could not update status: %w", err))
|
||||
@@ -135,7 +135,7 @@ func (c *oidcProviderWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
ctx.Context,
|
||||
opc.Namespace,
|
||||
opc.Name,
|
||||
configv1alpha1.SameIssuerHostMustUseSameSecretOIDCProviderStatusCondition,
|
||||
configv1alpha1.SameIssuerHostMustUseSameSecretFederationDomainStatusCondition,
|
||||
"Issuers with the same DNS hostname (address not including port) must use the same secretName: "+issuerURLToHostnameKey(issuerURL),
|
||||
); err != nil {
|
||||
errs.Add(fmt.Errorf("could not update status: %w", err))
|
||||
@@ -143,13 +143,13 @@ func (c *oidcProviderWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
continue
|
||||
}
|
||||
|
||||
oidcProvider, err := provider.NewOIDCProvider(opc.Spec.Issuer) // This validates the Issuer URL.
|
||||
federationDomain, err := provider.NewFederationDomain(opc.Spec.Issuer) // This validates the Issuer URL.
|
||||
if err != nil {
|
||||
if err := c.updateStatus(
|
||||
ctx.Context,
|
||||
opc.Namespace,
|
||||
opc.Name,
|
||||
configv1alpha1.InvalidOIDCProviderStatusCondition,
|
||||
configv1alpha1.InvalidFederationDomainStatusCondition,
|
||||
"Invalid: "+err.Error(),
|
||||
); err != nil {
|
||||
errs.Add(fmt.Errorf("could not update status: %w", err))
|
||||
@@ -161,28 +161,28 @@ func (c *oidcProviderWatcherController) Sync(ctx controllerlib.Context) error {
|
||||
ctx.Context,
|
||||
opc.Namespace,
|
||||
opc.Name,
|
||||
configv1alpha1.SuccessOIDCProviderStatusCondition,
|
||||
configv1alpha1.SuccessFederationDomainStatusCondition,
|
||||
"Provider successfully created",
|
||||
); err != nil {
|
||||
errs.Add(fmt.Errorf("could not update status: %w", err))
|
||||
continue
|
||||
}
|
||||
oidcProviders = append(oidcProviders, oidcProvider)
|
||||
federationDomains = append(federationDomains, federationDomain)
|
||||
}
|
||||
|
||||
c.providerSetter.SetProviders(oidcProviders...)
|
||||
c.providerSetter.SetProviders(federationDomains...)
|
||||
|
||||
return errs.ErrOrNil()
|
||||
}
|
||||
|
||||
func (c *oidcProviderWatcherController) updateStatus(
|
||||
func (c *federationDomainWatcherController) updateStatus(
|
||||
ctx context.Context,
|
||||
namespace, name string,
|
||||
status configv1alpha1.OIDCProviderStatusCondition,
|
||||
status configv1alpha1.FederationDomainStatusCondition,
|
||||
message string,
|
||||
) error {
|
||||
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
opc, err := c.client.ConfigV1alpha1().OIDCProviders(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||
opc, err := c.client.ConfigV1alpha1().FederationDomains(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("get failed: %w", err)
|
||||
}
|
||||
@@ -193,7 +193,7 @@ func (c *oidcProviderWatcherController) updateStatus(
|
||||
|
||||
plog.Debug(
|
||||
"attempting status update",
|
||||
"openidproviderconfig",
|
||||
"federationdomainconfig",
|
||||
klog.KRef(namespace, name),
|
||||
"status",
|
||||
status,
|
||||
@@ -203,7 +203,7 @@ func (c *oidcProviderWatcherController) updateStatus(
|
||||
opc.Status.Status = status
|
||||
opc.Status.Message = message
|
||||
opc.Status.LastUpdateTime = timePtr(metav1.NewTime(c.clock.Now()))
|
||||
_, err = c.client.ConfigV1alpha1().OIDCProviders(namespace).Update(ctx, opc, metav1.UpdateOptions{})
|
||||
_, err = c.client.ConfigV1alpha1().FederationDomains(namespace).Update(ctx, opc, metav1.UpdateOptions{})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ import (
|
||||
type tlsCertObserverController struct {
|
||||
issuerTLSCertSetter IssuerTLSCertSetter
|
||||
defaultTLSCertificateSecretName string
|
||||
oidcProviderInformer v1alpha1.OIDCProviderInformer
|
||||
federationDomainInformer v1alpha1.FederationDomainInformer
|
||||
secretInformer corev1informers.SecretInformer
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func NewTLSCertObserverController(
|
||||
issuerTLSCertSetter IssuerTLSCertSetter,
|
||||
defaultTLSCertificateSecretName string,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
oidcProviderInformer v1alpha1.OIDCProviderInformer,
|
||||
federationDomainInformer v1alpha1.FederationDomainInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
@@ -43,7 +43,7 @@ func NewTLSCertObserverController(
|
||||
Syncer: &tlsCertObserverController{
|
||||
issuerTLSCertSetter: issuerTLSCertSetter,
|
||||
defaultTLSCertificateSecretName: defaultTLSCertificateSecretName,
|
||||
oidcProviderInformer: oidcProviderInformer,
|
||||
federationDomainInformer: federationDomainInformer,
|
||||
secretInformer: secretInformer,
|
||||
},
|
||||
},
|
||||
@@ -53,7 +53,7 @@ func NewTLSCertObserverController(
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
withInformer(
|
||||
oidcProviderInformer,
|
||||
federationDomainInformer,
|
||||
pinnipedcontroller.MatchAnythingFilter(nil),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
@@ -62,12 +62,12 @@ func NewTLSCertObserverController(
|
||||
|
||||
func (c *tlsCertObserverController) Sync(ctx controllerlib.Context) error {
|
||||
ns := ctx.Key.Namespace
|
||||
allProviders, err := c.oidcProviderInformer.Lister().OIDCProviders(ns).List(labels.Everything())
|
||||
allProviders, err := c.federationDomainInformer.Lister().FederationDomains(ns).List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list OIDCProviders: %w", err)
|
||||
return fmt.Errorf("failed to list FederationDomains: %w", err)
|
||||
}
|
||||
|
||||
// Rebuild the whole map on any change to any Secret or OIDCProvider, because either can have changes that
|
||||
// Rebuild the whole map on any change to any Secret or FederationDomain, because either can have changes that
|
||||
// can cause the map to need to be updated.
|
||||
issuerHostToTLSCertMap := map[string]*tls.Certificate{}
|
||||
|
||||
|
||||
@@ -29,26 +29,26 @@ import (
|
||||
func TestTLSCertObserverControllerInformerFilters(t *testing.T) {
|
||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||
var (
|
||||
r *require.Assertions
|
||||
observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||
secretsInformerFilter controllerlib.Filter
|
||||
oidcProviderInformerFilter controllerlib.Filter
|
||||
r *require.Assertions
|
||||
observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||
secretsInformerFilter controllerlib.Filter
|
||||
federationDomainInformerFilter controllerlib.Filter
|
||||
)
|
||||
|
||||
it.Before(func() {
|
||||
r = require.New(t)
|
||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
oidcProviderInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Config().V1alpha1().OIDCProviders()
|
||||
federationDomainInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Config().V1alpha1().FederationDomains()
|
||||
_ = NewTLSCertObserverController(
|
||||
nil,
|
||||
"", // don't care about the secret name for this test
|
||||
secretsInformer,
|
||||
oidcProviderInformer,
|
||||
federationDomainInformer,
|
||||
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
||||
)
|
||||
secretsInformerFilter = observableWithInformerOption.GetFilterForInformer(secretsInformer)
|
||||
oidcProviderInformerFilter = observableWithInformerOption.GetFilterForInformer(oidcProviderInformer)
|
||||
federationDomainInformerFilter = observableWithInformerOption.GetFilterForInformer(federationDomainInformer)
|
||||
})
|
||||
|
||||
when("watching Secret objects", func() {
|
||||
@@ -73,19 +73,19 @@ func TestTLSCertObserverControllerInformerFilters(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
when("watching OIDCProvider objects", func() {
|
||||
when("watching FederationDomain objects", func() {
|
||||
var (
|
||||
subject controllerlib.Filter
|
||||
provider, otherProvider *v1alpha1.OIDCProvider
|
||||
provider, otherProvider *v1alpha1.FederationDomain
|
||||
)
|
||||
|
||||
it.Before(func() {
|
||||
subject = oidcProviderInformerFilter
|
||||
provider = &v1alpha1.OIDCProvider{ObjectMeta: metav1.ObjectMeta{Name: "any-name", Namespace: "any-namespace"}}
|
||||
otherProvider = &v1alpha1.OIDCProvider{ObjectMeta: metav1.ObjectMeta{Name: "any-other-name", Namespace: "any-other-namespace"}}
|
||||
subject = federationDomainInformerFilter
|
||||
provider = &v1alpha1.FederationDomain{ObjectMeta: metav1.ObjectMeta{Name: "any-name", Namespace: "any-namespace"}}
|
||||
otherProvider = &v1alpha1.FederationDomain{ObjectMeta: metav1.ObjectMeta{Name: "any-other-name", Namespace: "any-other-namespace"}}
|
||||
})
|
||||
|
||||
when("any OIDCProvider changes", func() {
|
||||
when("any FederationDomain changes", func() {
|
||||
it("returns true to trigger the sync method", func() {
|
||||
r.True(subject.Add(provider))
|
||||
r.True(subject.Update(provider, otherProvider))
|
||||
@@ -142,7 +142,7 @@ func TestTLSCertObserverControllerSync(t *testing.T) {
|
||||
issuerTLSCertSetter,
|
||||
defaultTLSSecretName,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
pinnipedInformers.Config().V1alpha1().OIDCProviders(),
|
||||
pinnipedInformers.Config().V1alpha1().FederationDomains(),
|
||||
controllerlib.WithInformer,
|
||||
)
|
||||
|
||||
@@ -192,7 +192,7 @@ func TestTLSCertObserverControllerSync(t *testing.T) {
|
||||
timeoutContextCancel()
|
||||
})
|
||||
|
||||
when("there are no OIDCProviders and no TLS Secrets yet", func() {
|
||||
when("there are no FederationDomains and no TLS Secrets yet", func() {
|
||||
it("sets the issuerTLSCertSetter's map to be empty", func() {
|
||||
startInformersAndController()
|
||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||
@@ -205,71 +205,71 @@ func TestTLSCertObserverControllerSync(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
when("there are OIDCProviders where some have corresponding TLS Secrets and some don't", func() {
|
||||
when("there are FederationDomains where some have corresponding TLS Secrets and some don't", func() {
|
||||
var (
|
||||
expectedCertificate1, expectedCertificate2 tls.Certificate
|
||||
)
|
||||
|
||||
it.Before(func() {
|
||||
var err error
|
||||
oidcProviderWithoutSecret1 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithoutSecret1 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "no-secret-oidcprovider1",
|
||||
Name: "no-secret-federationdomain1",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: "https://no-secret-issuer1.com"}, // no SNICertificateSecretName field
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://no-secret-issuer1.com"}, // no SNICertificateSecretName field
|
||||
}
|
||||
oidcProviderWithoutSecret2 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithoutSecret2 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "no-secret-oidcprovider2",
|
||||
Name: "no-secret-federationdomain2",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{
|
||||
Spec: v1alpha1.FederationDomainSpec{
|
||||
Issuer: "https://no-secret-issuer2.com",
|
||||
TLS: &v1alpha1.OIDCProviderTLSSpec{SecretName: ""},
|
||||
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: ""},
|
||||
},
|
||||
}
|
||||
oidcProviderWithBadSecret := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithBadSecret := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bad-secret-oidcprovider",
|
||||
Name: "bad-secret-federationdomain",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{
|
||||
Spec: v1alpha1.FederationDomainSpec{
|
||||
Issuer: "https://bad-secret-issuer.com",
|
||||
TLS: &v1alpha1.OIDCProviderTLSSpec{SecretName: "bad-tls-secret-name"},
|
||||
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "bad-tls-secret-name"},
|
||||
},
|
||||
}
|
||||
// Also add one with a URL that cannot be parsed to make sure that the controller is not confused by invalid URLs.
|
||||
invalidIssuerURL := ":/host//path"
|
||||
_, err = url.Parse(invalidIssuerURL) //nolint:staticcheck // Yes, this URL is intentionally invalid.
|
||||
r.Error(err)
|
||||
oidcProviderWithBadIssuer := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithBadIssuer := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bad-issuer-oidcprovider",
|
||||
Name: "bad-issuer-federationdomain",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Spec: v1alpha1.OIDCProviderSpec{Issuer: invalidIssuerURL},
|
||||
Spec: v1alpha1.FederationDomainSpec{Issuer: invalidIssuerURL},
|
||||
}
|
||||
oidcProviderWithGoodSecret1 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithGoodSecret1 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "good-secret-oidcprovider1",
|
||||
Name: "good-secret-federationdomain1",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
// Issuer hostname should be treated in a case-insensitive way and SNI ignores port numbers. Test without a port number.
|
||||
Spec: v1alpha1.OIDCProviderSpec{
|
||||
Spec: v1alpha1.FederationDomainSpec{
|
||||
Issuer: "https://www.iSSuer-wiTh-goOd-secRet1.cOm/path",
|
||||
TLS: &v1alpha1.OIDCProviderTLSSpec{SecretName: "good-tls-secret-name1"},
|
||||
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "good-tls-secret-name1"},
|
||||
},
|
||||
}
|
||||
oidcProviderWithGoodSecret2 := &v1alpha1.OIDCProvider{
|
||||
federationDomainWithGoodSecret2 := &v1alpha1.FederationDomain{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "good-secret-oidcprovider2",
|
||||
Name: "good-secret-federationdomain2",
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
// Issuer hostname should be treated in a case-insensitive way and SNI ignores port numbers. Test with a port number.
|
||||
Spec: v1alpha1.OIDCProviderSpec{
|
||||
Spec: v1alpha1.FederationDomainSpec{
|
||||
Issuer: "https://www.issUEr-WIth-gOOd-seCret2.com:1234/path",
|
||||
TLS: &v1alpha1.OIDCProviderTLSSpec{SecretName: "good-tls-secret-name2"},
|
||||
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "good-tls-secret-name2"},
|
||||
},
|
||||
}
|
||||
testCrt1 := readTestFile("testdata/test.crt")
|
||||
@@ -296,12 +296,12 @@ func TestTLSCertObserverControllerSync(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "bad-tls-secret-name", Namespace: installedInNamespace},
|
||||
Data: map[string][]byte{"junk": nil},
|
||||
}
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithoutSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithoutSecret2))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithBadSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithBadIssuer))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithGoodSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(oidcProviderWithGoodSecret2))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithoutSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithoutSecret2))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithBadSecret))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithBadIssuer))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithGoodSecret1))
|
||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainWithGoodSecret2))
|
||||
r.NoError(kubeInformerClient.Tracker().Add(goodTLSSecret1))
|
||||
r.NoError(kubeInformerClient.Tracker().Add(goodTLSSecret2))
|
||||
r.NoError(kubeInformerClient.Tracker().Add(badTLSSecret))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package upstreamwatcher implements a controller that watches UpstreamOIDCProvider objects.
|
||||
// Package upstreamwatcher implements a controller that watches OIDCIdentityProvider objects.
|
||||
package upstreamwatcher
|
||||
|
||||
import (
|
||||
@@ -58,7 +58,7 @@ const (
|
||||
reasonInvalidResponse = "InvalidResponse"
|
||||
|
||||
// Errors that are generated by our reconcile process.
|
||||
errFailureStatus = constable.Error("UpstreamOIDCProvider has a failing condition")
|
||||
errFailureStatus = constable.Error("OIDCIdentityProvider has a failing condition")
|
||||
errNoCertificates = constable.Error("no certificates found")
|
||||
)
|
||||
|
||||
@@ -75,7 +75,7 @@ type lruValidatorCacheEntry struct {
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func (c *lruValidatorCache) getProvider(spec *v1alpha1.UpstreamOIDCProviderSpec) (*oidc.Provider, *http.Client) {
|
||||
func (c *lruValidatorCache) getProvider(spec *v1alpha1.OIDCIdentityProviderSpec) (*oidc.Provider, *http.Client) {
|
||||
if result, ok := c.cache.Get(c.cacheKey(spec)); ok {
|
||||
entry := result.(*lruValidatorCacheEntry)
|
||||
return entry.provider, entry.client
|
||||
@@ -83,11 +83,11 @@ func (c *lruValidatorCache) getProvider(spec *v1alpha1.UpstreamOIDCProviderSpec)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *lruValidatorCache) putProvider(spec *v1alpha1.UpstreamOIDCProviderSpec, provider *oidc.Provider, client *http.Client) {
|
||||
func (c *lruValidatorCache) putProvider(spec *v1alpha1.OIDCIdentityProviderSpec, provider *oidc.Provider, client *http.Client) {
|
||||
c.cache.Set(c.cacheKey(spec), &lruValidatorCacheEntry{provider: provider, client: client}, validatorCacheTTL)
|
||||
}
|
||||
|
||||
func (c *lruValidatorCache) cacheKey(spec *v1alpha1.UpstreamOIDCProviderSpec) interface{} {
|
||||
func (c *lruValidatorCache) cacheKey(spec *v1alpha1.OIDCIdentityProviderSpec) interface{} {
|
||||
var key struct{ issuer, caBundle string }
|
||||
key.issuer = spec.Issuer
|
||||
if spec.TLS != nil {
|
||||
@@ -100,11 +100,11 @@ type controller struct {
|
||||
cache IDPCache
|
||||
log logr.Logger
|
||||
client pinnipedclientset.Interface
|
||||
providers idpinformers.UpstreamOIDCProviderInformer
|
||||
providers idpinformers.OIDCIdentityProviderInformer
|
||||
secrets corev1informers.SecretInformer
|
||||
validatorCache interface {
|
||||
getProvider(*v1alpha1.UpstreamOIDCProviderSpec) (*oidc.Provider, *http.Client)
|
||||
putProvider(*v1alpha1.UpstreamOIDCProviderSpec, *oidc.Provider, *http.Client)
|
||||
getProvider(*v1alpha1.OIDCIdentityProviderSpec) (*oidc.Provider, *http.Client)
|
||||
putProvider(*v1alpha1.OIDCIdentityProviderSpec, *oidc.Provider, *http.Client)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ type controller struct {
|
||||
func New(
|
||||
idpCache IDPCache,
|
||||
client pinnipedclientset.Interface,
|
||||
providers idpinformers.UpstreamOIDCProviderInformer,
|
||||
providers idpinformers.OIDCIdentityProviderInformer,
|
||||
secrets corev1informers.SecretInformer,
|
||||
log logr.Logger,
|
||||
) controllerlib.Controller {
|
||||
@@ -136,7 +136,7 @@ func New(
|
||||
func (c *controller) Sync(ctx controllerlib.Context) error {
|
||||
actualUpstreams, err := c.providers.Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list UpstreamOIDCProviders: %w", err)
|
||||
return fmt.Errorf("failed to list OIDCIdentityProviders: %w", err)
|
||||
}
|
||||
|
||||
requeue := false
|
||||
@@ -156,9 +156,9 @@ func (c *controller) Sync(ctx controllerlib.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateUpstream validates the provided v1alpha1.UpstreamOIDCProvider and returns the validated configuration as a
|
||||
// provider.UpstreamOIDCIdentityProvider. As a side effect, it also updates the status of the v1alpha1.UpstreamOIDCProvider.
|
||||
func (c *controller) validateUpstream(ctx controllerlib.Context, upstream *v1alpha1.UpstreamOIDCProvider) *upstreamoidc.ProviderConfig {
|
||||
// validateUpstream validates the provided v1alpha1.OIDCIdentityProvider and returns the validated configuration as a
|
||||
// provider.UpstreamOIDCIdentityProvider. As a side effect, it also updates the status of the v1alpha1.OIDCIdentityProvider.
|
||||
func (c *controller) validateUpstream(ctx controllerlib.Context, upstream *v1alpha1.OIDCIdentityProvider) *upstreamoidc.ProviderConfig {
|
||||
result := upstreamoidc.ProviderConfig{
|
||||
Name: upstream.Name,
|
||||
Config: &oauth2.Config{
|
||||
@@ -192,7 +192,7 @@ func (c *controller) validateUpstream(ctx controllerlib.Context, upstream *v1alp
|
||||
}
|
||||
|
||||
// validateSecret validates the .spec.client.secretName field and returns the appropriate ClientCredentialsValid condition.
|
||||
func (c *controller) validateSecret(upstream *v1alpha1.UpstreamOIDCProvider, result *upstreamoidc.ProviderConfig) *v1alpha1.Condition {
|
||||
func (c *controller) validateSecret(upstream *v1alpha1.OIDCIdentityProvider, result *upstreamoidc.ProviderConfig) *v1alpha1.Condition {
|
||||
secretName := upstream.Spec.Client.SecretName
|
||||
|
||||
// Fetch the Secret from informer cache.
|
||||
@@ -240,7 +240,7 @@ func (c *controller) validateSecret(upstream *v1alpha1.UpstreamOIDCProvider, res
|
||||
}
|
||||
|
||||
// validateIssuer validates the .spec.issuer field, performs OIDC discovery, and returns the appropriate OIDCDiscoverySucceeded condition.
|
||||
func (c *controller) validateIssuer(ctx context.Context, upstream *v1alpha1.UpstreamOIDCProvider, result *upstreamoidc.ProviderConfig) *v1alpha1.Condition {
|
||||
func (c *controller) validateIssuer(ctx context.Context, upstream *v1alpha1.OIDCIdentityProvider, result *upstreamoidc.ProviderConfig) *v1alpha1.Condition {
|
||||
// Get the provider and HTTP Client from cache if possible.
|
||||
discoveredProvider, httpClient := c.validatorCache.getProvider(&upstream.Spec)
|
||||
|
||||
@@ -302,7 +302,7 @@ func (c *controller) validateIssuer(ctx context.Context, upstream *v1alpha1.Upst
|
||||
}
|
||||
}
|
||||
|
||||
func getTLSConfig(upstream *v1alpha1.UpstreamOIDCProvider) (*tls.Config, error) {
|
||||
func getTLSConfig(upstream *v1alpha1.OIDCIdentityProvider) (*tls.Config, error) {
|
||||
result := tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
@@ -324,7 +324,7 @@ func getTLSConfig(upstream *v1alpha1.UpstreamOIDCProvider) (*tls.Config, error)
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *controller) updateStatus(ctx context.Context, upstream *v1alpha1.UpstreamOIDCProvider, conditions []*v1alpha1.Condition) {
|
||||
func (c *controller) updateStatus(ctx context.Context, upstream *v1alpha1.OIDCIdentityProvider, conditions []*v1alpha1.Condition) {
|
||||
log := c.log.WithValues("namespace", upstream.Namespace, "name", upstream.Name)
|
||||
updated := upstream.DeepCopy()
|
||||
|
||||
@@ -352,7 +352,7 @@ func (c *controller) updateStatus(ctx context.Context, upstream *v1alpha1.Upstre
|
||||
|
||||
_, err := c.client.
|
||||
IDPV1alpha1().
|
||||
UpstreamOIDCProviders(upstream.Namespace).
|
||||
OIDCIdentityProviders(upstream.Namespace).
|
||||
UpdateStatus(ctx, updated, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
log.Error(err, "failed to update status")
|
||||
|
||||
@@ -61,16 +61,16 @@ func TestController(t *testing.T) {
|
||||
wantErr string
|
||||
wantLogs []string
|
||||
wantResultingCache []provider.UpstreamOIDCIdentityProviderI
|
||||
wantResultingUpstreams []v1alpha1.UpstreamOIDCProvider
|
||||
wantResultingUpstreams []v1alpha1.OIDCIdentityProvider
|
||||
}{
|
||||
{
|
||||
name: "no upstreams",
|
||||
},
|
||||
{
|
||||
name: "missing secret",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL,
|
||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
@@ -82,12 +82,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="secret \"test-client-secret\" not found" "reason"="SecretNotFound" "status"="False" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="discovered issuer configuration" "reason"="Success" "status"="True" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="secret \"test-client-secret\" not found" "name"="test-name" "namespace"="test-namespace" "reason"="SecretNotFound" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="secret \"test-client-secret\" not found" "name"="test-name" "namespace"="test-namespace" "reason"="SecretNotFound" "type"="ClientCredentialsValid"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -110,9 +110,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "secret has wrong type",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL,
|
||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
@@ -128,12 +128,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="referenced Secret \"test-client-secret\" has wrong type \"some-other-type\" (should be \"secrets.pinniped.dev/oidc-client\")" "reason"="SecretWrongType" "status"="False" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="discovered issuer configuration" "reason"="Success" "status"="True" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="referenced Secret \"test-client-secret\" has wrong type \"some-other-type\" (should be \"secrets.pinniped.dev/oidc-client\")" "name"="test-name" "namespace"="test-namespace" "reason"="SecretWrongType" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="referenced Secret \"test-client-secret\" has wrong type \"some-other-type\" (should be \"secrets.pinniped.dev/oidc-client\")" "name"="test-name" "namespace"="test-namespace" "reason"="SecretWrongType" "type"="ClientCredentialsValid"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -156,9 +156,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "secret is missing key",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL,
|
||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
@@ -173,12 +173,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="referenced Secret \"test-client-secret\" is missing required keys [\"clientID\" \"clientSecret\"]" "reason"="SecretMissingKeys" "status"="False" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="discovered issuer configuration" "reason"="Success" "status"="True" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="referenced Secret \"test-client-secret\" is missing required keys [\"clientID\" \"clientSecret\"]" "name"="test-name" "namespace"="test-namespace" "reason"="SecretMissingKeys" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="referenced Secret \"test-client-secret\" is missing required keys [\"clientID\" \"clientSecret\"]" "name"="test-name" "namespace"="test-namespace" "reason"="SecretMissingKeys" "type"="ClientCredentialsValid"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -201,9 +201,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "TLS CA bundle is invalid base64",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-name"},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL,
|
||||
TLS: &v1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: "invalid-base64",
|
||||
@@ -221,12 +221,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="spec.certificateAuthorityData is invalid: illegal base64 data at input byte 7" "reason"="InvalidTLSConfig" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="spec.certificateAuthorityData is invalid: illegal base64 data at input byte 7" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="spec.certificateAuthorityData is invalid: illegal base64 data at input byte 7" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -249,9 +249,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "TLS CA bundle does not have any certificates",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-name"},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL,
|
||||
TLS: &v1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte("not-a-pem-ca-bundle")),
|
||||
@@ -269,12 +269,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="spec.certificateAuthorityData is invalid: no certificates found" "reason"="InvalidTLSConfig" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="spec.certificateAuthorityData is invalid: no certificates found" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="spec.certificateAuthorityData is invalid: no certificates found" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -297,9 +297,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "issuer is invalid URL",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: "invalid-url",
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
AuthorizationConfig: v1alpha1.OIDCAuthorizationConfig{AdditionalScopes: testAdditionalScopes},
|
||||
@@ -314,12 +314,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="failed to perform OIDC discovery against \"invalid-url\"" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="failed to perform OIDC discovery against \"invalid-url\"" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="failed to perform OIDC discovery against \"invalid-url\"" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -342,9 +342,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "issuer returns invalid authorize URL",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL + "/invalid",
|
||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
@@ -360,12 +360,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="failed to parse authorization endpoint URL: parse \"%\": invalid URL escape \"%\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="failed to parse authorization endpoint URL: parse \"%\": invalid URL escape \"%\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="failed to parse authorization endpoint URL: parse \"%\": invalid URL escape \"%\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -388,9 +388,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "issuer returns insecure authorize URL",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL + "/insecure",
|
||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
@@ -406,12 +406,12 @@ func TestController(t *testing.T) {
|
||||
wantLogs: []string{
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||
`upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="UpstreamOIDCProvider has a failing condition" "msg"="found failing condition" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||
`upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||
},
|
||||
wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{
|
||||
@@ -434,16 +434,16 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "upstream becomes valid",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-name"},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL,
|
||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
AuthorizationConfig: v1alpha1.OIDCAuthorizationConfig{AdditionalScopes: append(testAdditionalScopes, "xyz", "openid")},
|
||||
Claims: v1alpha1.OIDCClaims{Groups: testGroupsClaim, Username: testUsernameClaim},
|
||||
},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Error",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{Type: "ClientCredentialsValid", Status: "False", LastTransitionTime: earlier, Reason: "SomeError1", Message: "some previous error 1"},
|
||||
@@ -470,9 +470,9 @@ func TestController(t *testing.T) {
|
||||
GroupsClaim: testGroupsClaim,
|
||||
},
|
||||
},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Ready",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{Type: "ClientCredentialsValid", Status: "True", LastTransitionTime: now, Reason: "Success", Message: "loaded client credentials"},
|
||||
@@ -483,16 +483,16 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "existing valid upstream",
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.UpstreamOIDCProvider{
|
||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
||||
Spec: v1alpha1.UpstreamOIDCProviderSpec{
|
||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||
Issuer: testIssuerURL,
|
||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||
AuthorizationConfig: v1alpha1.OIDCAuthorizationConfig{AdditionalScopes: testAdditionalScopes},
|
||||
Claims: v1alpha1.OIDCClaims{Groups: testGroupsClaim, Username: testUsernameClaim},
|
||||
},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Ready",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{Type: "ClientCredentialsValid", Status: "True", LastTransitionTime: earlier, Reason: "Success", Message: "loaded client credentials"},
|
||||
@@ -519,9 +519,9 @@ func TestController(t *testing.T) {
|
||||
GroupsClaim: testGroupsClaim,
|
||||
},
|
||||
},
|
||||
wantResultingUpstreams: []v1alpha1.UpstreamOIDCProvider{{
|
||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
||||
Status: v1alpha1.UpstreamOIDCProviderStatus{
|
||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||
Phase: "Ready",
|
||||
Conditions: []v1alpha1.Condition{
|
||||
{Type: "ClientCredentialsValid", Status: "True", LastTransitionTime: earlier, Reason: "Success", Message: "loaded client credentials", ObservedGeneration: 1234},
|
||||
@@ -548,7 +548,7 @@ func TestController(t *testing.T) {
|
||||
controller := New(
|
||||
cache,
|
||||
fakePinnipedClient,
|
||||
pinnipedInformers.IDP().V1alpha1().UpstreamOIDCProviders(),
|
||||
pinnipedInformers.IDP().V1alpha1().OIDCIdentityProviders(),
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
testLog)
|
||||
|
||||
@@ -580,7 +580,7 @@ func TestController(t *testing.T) {
|
||||
require.ElementsMatch(t, tt.wantResultingCache[i].GetScopes(), actualIDP.GetScopes())
|
||||
}
|
||||
|
||||
actualUpstreams, err := fakePinnipedClient.IDPV1alpha1().UpstreamOIDCProviders(testNamespace).List(ctx, metav1.ListOptions{})
|
||||
actualUpstreams, err := fakePinnipedClient.IDPV1alpha1().OIDCIdentityProviders(testNamespace).List(ctx, metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Preprocess the set of upstreams a bit so that they're easier to assert against.
|
||||
@@ -597,13 +597,13 @@ func TestController(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeUpstreams(upstreams []v1alpha1.UpstreamOIDCProvider, now metav1.Time) []v1alpha1.UpstreamOIDCProvider {
|
||||
result := make([]v1alpha1.UpstreamOIDCProvider, 0, len(upstreams))
|
||||
func normalizeUpstreams(upstreams []v1alpha1.OIDCIdentityProvider, now metav1.Time) []v1alpha1.OIDCIdentityProvider {
|
||||
result := make([]v1alpha1.OIDCIdentityProvider, 0, len(upstreams))
|
||||
for _, u := range upstreams {
|
||||
normalized := u.DeepCopy()
|
||||
|
||||
// We're only interested in comparing the status, so zero out the spec.
|
||||
normalized.Spec = v1alpha1.UpstreamOIDCProviderSpec{}
|
||||
normalized.Spec = v1alpha1.OIDCIdentityProviderSpec{}
|
||||
|
||||
// Round down the LastTransitionTime values to `now` if they were just updated. This makes
|
||||
// it much easier to encode assertions about the expected timestamps.
|
||||
|
||||
Reference in New Issue
Block a user