Skip to content

Commit

Permalink
feat: disable oauth2 client deletion
Browse files Browse the repository at this point in the history
This new feature allows to disable hydra-maester OAuth2 client deletion.
It can be a pitfall that, when a Kube CRD gets deleted, the OAuth2 client gets deleted.

OAuth2 clients can be critical for production environments to work properly,
and allowing to delete one when a Kubernetes CRD gets deleted has shown to be brittle.

This feature should make hydra-maester safer.
  • Loading branch information
David-Wobrock committed Sep 27, 2024
1 parent aa0bff2 commit d12c170
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 4 deletions.
14 changes: 13 additions & 1 deletion api/v1alpha1/oauth2client_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ type OAuth2ClientSpec struct {

// +kubebuilder:validation:Enum=client_secret_basic;client_secret_post;private_key_jwt;none
//
// Indication which authentication method shoud be used for the token endpoint
// Indication which authentication method should be used for the token endpoint
TokenEndpointAuthMethod TokenEndpointAuthMethod `json:"tokenEndpointAuthMethod,omitempty"`

// TokenLifespans is the configuration to use for managing different token lifespans
Expand Down Expand Up @@ -213,6 +213,11 @@ type OAuth2ClientSpec struct {
//
// 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=Delete;Orphan
//
// Indicates if a deleted OAuth2Client custom resource should delete the database row or not
DeletionPolicy OAuth2ClientDeletionPolicy `json:"deletionPolicy,omitempty"`
}

// GrantType represents an OAuth 2.0 grant type
Expand Down Expand Up @@ -259,6 +264,13 @@ const (
OAuth2ClientConditionReady = "Ready"
)

// OAuth2ClientDeletionPolicy represents if a deleted oauth2 client object should delete the database row or not.
type OAuth2ClientDeletionPolicy string

const (
OAuth2ClientDeletionPolicyOrphan = "Orphan"
)

// +kubebuilder:validation:Enum=True;False;Unknown
type ConditionStatus string

Expand Down
1 change: 1 addition & 0 deletions api/v1alpha1/oauth2client_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func TestCreateAPI(t *testing.T) {
"invalid lifespan refresh token access token": func() { created.Spec.TokenLifespans.RefreshTokenGrantAccessTokenLifespan = "invalid" },
"invalid lifespan refresh token id token": func() { created.Spec.TokenLifespans.RefreshTokenGrantIdTokenLifespan = "invalid" },
"invalid lifespan refresh token refresh token": func() { created.Spec.TokenLifespans.RefreshTokenGrantRefreshTokenLifespan = "invalid" },
"invalid deletion policy": func() { created.Spec.DeletionPolicy = "invalid" },
} {
t.Run(fmt.Sprintf("case=%s", desc), func(t *testing.T) {
resetTestClient()
Expand Down
12 changes: 10 additions & 2 deletions config/crd/bases/hydra.ory.sh_oauth2clients.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ spec:
ClientName is the human-readable string name of the client
to be presented to the end-user during authorization.
type: string
deletionPolicy:
description:
Indicates if a deleted OAuth2Client custom resource should
delete the database row or not
enum:
- Delete
- Orphan
type: string
frontChannelLogoutSessionRequired:
default: false
description:
Expand Down Expand Up @@ -230,8 +238,8 @@ spec:
- private_key_jwt
- none
description:
Indication which authentication method shoud be used for the
token endpoint
Indication which authentication method should be used for
the token endpoint
type: string
tokenLifespans:
description: |-
Expand Down
6 changes: 5 additions & 1 deletion controllers/oauth2client_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,6 @@ func (r *OAuth2ClientReconciler) updateRegisteredOAuth2Client(ctx context.Contex
}

func (r *OAuth2ClientReconciler) unregisterOAuth2Clients(ctx context.Context, c *hydrav1alpha1.OAuth2Client) error {

// 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 == "" {
Expand All @@ -347,6 +346,11 @@ func (r *OAuth2ClientReconciler) unregisterOAuth2Clients(ctx context.Context, c

for _, cJSON := range clients {
if cJSON.Owner == fmt.Sprintf("%s/%s", c.Name, c.Namespace) {
if c.Spec.DeletionPolicy == hydrav1alpha1.OAuth2ClientDeletionPolicyOrphan {
// Do not delete the OAuth2 client.
r.Log.Info("oauth2 client deletion, leave the row orphan")
return nil
}
if err := h.DeleteOAuth2Client(*cJSON.ClientID); err != nil {
return err
}
Expand Down

0 comments on commit d12c170

Please sign in to comment.