diff --git a/controllers/oauth2client_controller.go b/controllers/oauth2client_controller.go index c6cea9d..09d8733 100644 --- a/controllers/oauth2client_controller.go +++ b/controllers/oauth2client_controller.go @@ -229,11 +229,14 @@ func (r *OAuth2ClientReconciler) registerOAuth2Client(ctx context.Context, c *hy }}, }, Data: map[string][]byte{ - ClientIDKey: []byte(*created.ClientID), - ClientSecretKey: []byte(*created.Secret), + ClientIDKey: []byte(*created.ClientID), }, } + if created.Secret != nil { + clientSecret.Data[ClientSecretKey] = []byte(*created.Secret) + } + if err := r.Create(ctx, &clientSecret); err != nil { if updateErr := r.updateReconciliationStatusError(ctx, c, hydrav1alpha1.StatusCreateSecretFailed, err); updateErr != nil { return updateErr @@ -317,10 +320,7 @@ func parseSecret(secret apiv1.Secret) (*hydra.Oauth2ClientCredentials, error) { return nil, errors.New(`"client_id property missing"`) } - psw, found := secret.Data[ClientSecretKey] - if !found { - return nil, errors.New(`"client_secret property missing"`) - } + psw := secret.Data[ClientSecretKey] return &hydra.Oauth2ClientCredentials{ ID: id, diff --git a/controllers/oauth2client_controller_integration_test.go b/controllers/oauth2client_controller_integration_test.go index 2d35693..aa216bd 100644 --- a/controllers/oauth2client_controller_integration_test.go +++ b/controllers/oauth2client_controller_integration_test.go @@ -35,6 +35,15 @@ const ( tstSecret = "testSecret" ) +var clientIter = 0 + +func makeClientInfo() (string, string, string) { + defer func() { clientIter++ }() + return fmt.Sprintf("test-client-%d", clientIter), + fmt.Sprintf("test-client-id-%d", clientIter), + fmt.Sprintf("test-client-secret-%d", clientIter) +} + var _ = Describe("OAuth2Client Controller", func() { Context("in a happy-path scenario", func() { @@ -43,7 +52,7 @@ var _ = Describe("OAuth2Client Controller", func() { It("create a Secret if it does not exist", func() { - tstName, tstClientID, tstSecretName := "test", "testClientID", "my-secret-123" + tstName, tstClientID, tstSecretName := makeClientInfo() expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}} s := scheme.Scheme @@ -121,9 +130,87 @@ var _ = Describe("OAuth2Client Controller", func() { mgrStopped.Wait() }) + It("create a Secret if it does not exist and no client secret is generated", func() { + + tstName, tstClientID, tstSecretName := makeClientInfo() + expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}} + + s := scheme.Scheme + err := hydrav1alpha1.AddToScheme(s) + Expect(err).NotTo(HaveOccurred()) + + err = apiv1.AddToScheme(s) + Expect(err).NotTo(HaveOccurred()) + + // Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a + // channel when it is finished. + mgr, err := manager.New(cfg, manager.Options{Scheme: s}) + Expect(err).NotTo(HaveOccurred()) + c := mgr.GetClient() + + mch := &mocks.HydraClientInterface{} + mch.On("DeleteOAuth2Client", Anything).Return(nil) + mch.On("ListOAuth2Client", Anything).Return(nil, nil) + mch.On("PostOAuth2Client", AnythingOfType("*hydra.OAuth2ClientJSON")).Return(func(o *hydra.OAuth2ClientJSON) *hydra.OAuth2ClientJSON { + return &hydra.OAuth2ClientJSON{ + ClientID: &tstClientID, + GrantTypes: o.GrantTypes, + ResponseTypes: o.ResponseTypes, + RedirectURIs: o.RedirectURIs, + Scope: o.Scope, + Audience: o.Audience, + Owner: o.Owner, + TokenEndpointAuthMethod: o.TokenEndpointAuthMethod, + } + }, func(o *hydra.OAuth2ClientJSON) error { + return nil + }) + + recFn, requests := SetupTestReconcile(getAPIReconciler(mgr, mch)) + + Expect(add(mgr, recFn)).To(Succeed()) + + //Start the manager and the controller + stopMgr, mgrStopped := StartTestManager(mgr) + + instance := testInstance(tstName, tstSecretName) + err = c.Create(context.TODO(), instance) + // The instance object may not be a valid object because it might be missing some required fields. + // Please modify the instance object by adding required fields and then remove the following if statement. + if apierrors.IsInvalid(err) { + Fail(fmt.Sprintf("failed to create object, got an invalid object error: %v", err)) + return + } + Expect(err).NotTo(HaveOccurred()) + Eventually(requests, timeout).Should(Receive(Equal(*expectedRequest))) + + //Verify the created CR instance status + var retrieved hydrav1alpha1.OAuth2Client + ok := client.ObjectKey{Name: tstName, Namespace: tstNamespace} + err = c.Get(context.TODO(), ok, &retrieved) + Expect(err).NotTo(HaveOccurred()) + Expect(retrieved.Status.ReconciliationError.Code).To(BeEmpty()) + Expect(retrieved.Status.ReconciliationError.Description).To(BeEmpty()) + + //Verify the created Secret + var createdSecret apiv1.Secret + ok = client.ObjectKey{Name: tstSecretName, Namespace: tstNamespace} + err = k8sClient.Get(context.TODO(), ok, &createdSecret) + Expect(err).NotTo(HaveOccurred()) + Expect(createdSecret.Data[controllers.ClientIDKey]).To(Equal([]byte(tstClientID))) + Expect(createdSecret.OwnerReferences).To(Equal(getOwnerReferenceTo(retrieved))) + + //delete instance + c.Delete(context.TODO(), instance) + + //Ensure manager is stopped properly + close(stopMgr) + mgrStopped.Wait() + }) + It("update object status if the call failed", func() { - tstName, tstSecretName := "test2", "my-secret-456" + tstName, _, tstSecretName := makeClientInfo() expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}} s := scheme.Scheme @@ -189,7 +276,7 @@ var _ = Describe("OAuth2Client Controller", func() { It("use provided Secret if it exists", func() { - tstName, tstClientID, tstSecretName := "test3", "testClientID-3", "my-secret-789" + tstName, tstClientID, tstSecretName := makeClientInfo() var postedClient *hydra.OAuth2ClientJSON expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}} @@ -286,7 +373,7 @@ var _ = Describe("OAuth2Client Controller", func() { It("update object status if provided Secret is invalid", func() { - tstName, tstClientID, tstSecretName := "test4", "testClientID-4", "my-secret-000" + tstName, tstClientID, tstSecretName := makeClientInfo() expectedRequest := &reconcile.Request{NamespacedName: types.NamespacedName{Name: tstName, Namespace: tstNamespace}} s := scheme.Scheme