From d5ad7f4c995178e8eb3f1b78e41bf294ab6ca1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20B=C5=82aszczyk?= Date: Tue, 10 Oct 2023 13:22:06 +0200 Subject: [PATCH] feat: add channels to crd (#135) --- Makefile | 7 +++- api/v1alpha1/oauth2client_types.go | 34 +++++++++++++++--- .../crd/bases/hydra.ory.sh_oauth2clients.yaml | 36 ++++++++++++++++++- controllers/oauth2client_controller.go | 20 +++++------ 4 files changed, 80 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 064b10a..2028932 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ k3d-down: k3d cluster delete ory || true .PHONY: k3d-deploy -k3d-deploy: manager manifests docker-build-notest k3d-up +k3d-deploy: manager-ci manifests docker-build-notest k3d-up kubectl config set-context k3d-ory k3d image load controller:latest -c ory kubectl apply -f config/crd/bases @@ -124,6 +124,11 @@ test-integration: manager: generate vet CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -a -o manager main.go +# Build manager binary for CI +.PHONY: manager-ci +manager: generate vet + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go + # Run against the configured Kubernetes cluster in ~/.kube/config .PHONY: run run: generate vet diff --git a/api/v1alpha1/oauth2client_types.go b/api/v1alpha1/oauth2client_types.go index 5734596..ffd1829 100644 --- a/api/v1alpha1/oauth2client_types.go +++ b/api/v1alpha1/oauth2client_types.go @@ -114,7 +114,7 @@ type OAuth2ClientSpec struct { // +nullable // +optional // - // Metadata is abritrary data + // Metadata is arbitrary data Metadata apiextensionsv1.JSON `json:"metadata,omitempty"` // +kubebuilder:validation:type=string @@ -122,22 +122,46 @@ type OAuth2ClientSpec struct { // // JwksUri Define the URL where the JSON Web Key Set should be fetched from when performing the private_key_jwt client authentication method. JwksUri string `json:"jwksUri,omitempty"` + + // +kubebuilder:validation:type=bool + // +kubebuilder:default=false + // + // FrontChannelLogoutSessionRequired Boolean value specifying whether the RP requires that iss (issuer) and sid (session ID) query parameters be included to identify the RP session with the OP when the frontchannel_logout_uri is used + FrontChannelLogoutSessionRequired bool `json:"frontChannelLogoutSessionRequired,omitempty"` + + // +kubebuilder:validation:type=string + // +kubebuilder:validation:Pattern=`(^$|^https?://.*)` + // + // FrontChannelLogoutURI RP URL that will cause the RP to log itself out when rendered in an iframe by the OP. An iss (issuer) query parameter and a sid (session ID) query parameter MAY be included by the OP to enable the RP to validate the request and to determine which of the potentially multiple sessions is to be logged out; if either is included, both MUST be + FrontChannelLogoutURI string `json:"frontChannelLogoutURI,omitempty"` + + // +kubebuilder:validation:type=bool + // +kubebuilder:default=false + // + // BackChannelLogoutSessionRequired Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout Token to identify the RP session with the OP when the backchannel_logout_uri is used. If omitted, the default value is false. + BackChannelLogoutSessionRequired bool `json:"backChannelLogoutSessionRequired,omitempty"` + + // +kubebuilder:validation:type=string + // +kubebuilder:validation:Pattern=`(^$|^https?://.*)` + // + // BackChannelLogoutURI RP URL that will cause the RP to log itself out when sent a Logout Token by the OP + BackChannelLogoutURI string `json:"backChannelLogoutURI,omitempty"` } -// +kubebuilder:validation:Enum=client_credentials;authorization_code;implicit;refresh_token // GrantType represents an OAuth 2.0 grant type +// +kubebuilder:validation:Enum=client_credentials;authorization_code;implicit;refresh_token type GrantType string -// +kubebuilder:validation:Enum=id_token;code;token;code token;code id_token;id_token token;code id_token token // ResponseType represents an OAuth 2.0 response type strings +// +kubebuilder:validation:Enum=id_token;code;token;code token;code id_token;id_token token;code id_token token type ResponseType string -// +kubebuilder:validation:Pattern=`\w+:/?/?[^\s]+` // RedirectURI represents a redirect URI for the client +// +kubebuilder:validation:Pattern=`\w+:/?/?[^\s]+` type RedirectURI string -// +kubebuilder:validation:Enum=client_secret_basic;client_secret_post;private_key_jwt;none // TokenEndpointAuthMethod represents an authentication method for token endpoint +// +kubebuilder:validation:Enum=client_secret_basic;client_secret_post;private_key_jwt;none type TokenEndpointAuthMethod string // OAuth2ClientStatus defines the observed state of OAuth2Client diff --git a/config/crd/bases/hydra.ory.sh_oauth2clients.yaml b/config/crd/bases/hydra.ory.sh_oauth2clients.yaml index e896e94..57c2154 100644 --- a/config/crd/bases/hydra.ory.sh_oauth2clients.yaml +++ b/config/crd/bases/hydra.ory.sh_oauth2clients.yaml @@ -58,11 +58,45 @@ spec: items: type: string type: array + backChannelLogoutSessionRequired: + default: false + description: + BackChannelLogoutSessionRequired Boolean value specifying + whether the RP requires that a sid (session ID) Claim be + included in the Logout Token to identify the RP session with + the OP when the backchannel_logout_uri is used. If omitted, + the default value is false. + type: boolean + backChannelLogoutURI: + description: + BackChannelLogoutURI RP URL that will cause the RP to log + itself out when sent a Logout Token by the OP + pattern: (^$|^https?://.*) + type: string clientName: description: ClientName is the human-readable string name of the client to be presented to the end-user during authorization. type: string + frontChannelLogoutSessionRequired: + default: false + description: + FrontChannelLogoutSessionRequired Boolean value specifying + whether the RP requires that iss (issuer) and sid (session + ID) query parameters be included to identify the RP session + with the OP when the frontchannel_logout_uri is used + type: boolean + frontChannelLogoutURI: + description: + FrontChannelLogoutURI RP URL that will cause the RP to log + itself out when rendered in an iframe by the OP. An iss + (issuer) query parameter and a sid (session ID) query + parameter MAY be included by the OP to enable the RP to + validate the request and to determine which of the + potentially multiple sessions is to be logged out; if either + is included, both MUST be + pattern: (^$|^https?://.*) + type: string grantTypes: description: GrantTypes is an array of grant types the client is allowed @@ -122,7 +156,7 @@ spec: pattern: (^$|^https?://.*) type: string metadata: - description: Metadata is abritrary data + description: Metadata is arbitrary data nullable: true type: object x-kubernetes-preserve-unknown-fields: true diff --git a/controllers/oauth2client_controller.go b/controllers/oauth2client_controller.go index 36968fa..98c61c0 100644 --- a/controllers/oauth2client_controller.go +++ b/controllers/oauth2client_controller.go @@ -121,9 +121,9 @@ func (r *OAuth2ClientReconciler) Reconcile(ctx context.Context, req ctrl.Request // Check request namespace if r.ControllerNamespace != "" { - r.Log.Info((fmt.Sprintf("ControllerNamespace is set to: %s, working only on items in this namespace. Other namespaces are ignored.", r.ControllerNamespace))) + r.Log.Info(fmt.Sprintf("ControllerNamespace is set to: %s, working only on items in this namespace. Other namespaces are ignored.", r.ControllerNamespace)) if req.NamespacedName.Namespace != r.ControllerNamespace { - r.Log.Info((fmt.Sprintf("Requested resource %s is not in namespace: %s and will be ignored", req.String(), r.ControllerNamespace))) + r.Log.Info(fmt.Sprintf("Requested resource %s is not in namespace: %s and will be ignored", req.String(), r.ControllerNamespace)) return ctrl.Result{}, nil } } @@ -314,25 +314,25 @@ func (r *OAuth2ClientReconciler) updateRegisteredOAuth2Client(ctx context.Contex func (r *OAuth2ClientReconciler) unregisterOAuth2Clients(ctx context.Context, c *hydrav1alpha1.OAuth2Client) error { - // if a reqired field is empty, that means this is a delete after + // if a required field is empty, that means this is deleted after // the finalizers have done their job, so just return if c.Spec.Scope == "" || c.Spec.SecretName == "" { return nil } - hydra, err := r.getHydraClientForClient(*c) + h, err := r.getHydraClientForClient(*c) if err != nil { return err } - clients, err := hydra.ListOAuth2Client() + clients, err := h.ListOAuth2Client() if err != nil { return err } for _, cJSON := range clients { if cJSON.Owner == fmt.Sprintf("%s/%s", c.Name, c.Namespace) { - if err := hydra.DeleteOAuth2Client(*cJSON.ClientID); err != nil { + if err := h.DeleteOAuth2Client(*cJSON.ClientID); err != nil { return err } } @@ -419,13 +419,13 @@ func (r *OAuth2ClientReconciler) getHydraClientForClient( return c, nil } - client, err := r.oauth2ClientFactory(spec, "", false) + c, err := r.oauth2ClientFactory(spec, "", false) if err != nil { - return nil, fmt.Errorf("cannot create oauth2 client from CRD: %w", err) + return nil, fmt.Errorf("cannot create oauth2 c from CRD: %w", err) } - r.oauth2Clients[key] = client - return client, nil + r.oauth2Clients[key] = c + return c, nil } if r.HydraClient == nil {