From 64e5e20010cb2864c495521c8e9a1882e411e5f3 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Wed, 16 Jul 2025 14:28:37 -0700 Subject: [PATCH] add usernameExpression and groupsExpression to JWTAuthenticator CRD --- .../v1alpha1/types_jwtauthenticator.go.tmpl | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.26/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.27/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.28/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.29/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.30/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.31/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.32/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/1.33/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- ...cierge.pinniped.dev_jwtauthenticators.yaml | 55 +++++- generated/latest/README.adoc | 51 ++++- .../v1alpha1/types_jwtauthenticator.go | 59 +++++- .../convert_jwtauthenticator_type.go | 78 +++++--- .../convert_jwtauthenticator_type_test.go | 29 ++- .../jwtcachefiller/jwtcachefiller_test.go | 177 ++++++++++++++++-- 31 files changed, 1700 insertions(+), 128 deletions(-) diff --git a/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go.tmpl b/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go.tmpl index d5149642f..8d416bcbf 100644 --- a/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go.tmpl +++ b/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go.tmpl @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/deploy/concierge/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/deploy/concierge/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/deploy/concierge/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/deploy/concierge/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.26/README.adoc b/generated/1.26/README.adoc index 14bb3c853..0983f1dc9 100644 --- a/generated/1.26/README.adoc +++ b/generated/1.26/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.26/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.26/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.26/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.26/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.26/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.26/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.26/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.26/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.27/README.adoc b/generated/1.27/README.adoc index ed8964abf..ba630e361 100644 --- a/generated/1.27/README.adoc +++ b/generated/1.27/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.27/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.27/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.27/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.27/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.27/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.27/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.27/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.27/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.28/README.adoc b/generated/1.28/README.adoc index d813352df..42d652eeb 100644 --- a/generated/1.28/README.adoc +++ b/generated/1.28/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.28/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.28/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.28/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.28/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.28/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.28/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.28/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.28/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.29/README.adoc b/generated/1.29/README.adoc index d935f9896..2b5102cf5 100644 --- a/generated/1.29/README.adoc +++ b/generated/1.29/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.29/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.29/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.29/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.29/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.29/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.29/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.29/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.29/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.30/README.adoc b/generated/1.30/README.adoc index 2615c5333..3c64b7b2d 100644 --- a/generated/1.30/README.adoc +++ b/generated/1.30/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.30/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.30/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.30/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.30/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.30/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.30/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.30/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.30/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.31/README.adoc b/generated/1.31/README.adoc index 870693cb6..d05ca7c5d 100644 --- a/generated/1.31/README.adoc +++ b/generated/1.31/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.31/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.31/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.31/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.31/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.31/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.31/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.31/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.31/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.32/README.adoc b/generated/1.32/README.adoc index 3e4990deb..ab808e660 100644 --- a/generated/1.32/README.adoc +++ b/generated/1.32/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.32/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.32/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.32/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.32/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.32/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.32/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.32/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.32/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/1.33/README.adoc b/generated/1.33/README.adoc index 5c4577bd0..5796e1366 100644 --- a/generated/1.33/README.adoc +++ b/generated/1.33/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/1.33/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/1.33/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/1.33/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/1.33/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/generated/1.33/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml b/generated/1.33/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml index cbb567616..057c8d7b8 100644 --- a/generated/1.33/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml +++ b/generated/1.33/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml @@ -167,12 +167,63 @@ spec: groups: description: |- groups is the name of the claim which should be read to extract the user's - group membership from the JWT token. When not specified, it will default to "groups". + group membership from the JWT token. When not specified, it will default to "groups", + unless groupsExpression is specified. + + Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. + type: string + groupsExpression: + description: |- + groupsExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's group memberships. + + The expression must produce a string or string array value. + "", [], and null values are treated as the group mapping not being present. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with groups. Use either groups or groupsExpression to + determine the user's group membership from the JWT token. type: string username: description: |- username is the name of the claim which should be read to extract the - username from the JWT token. When not specified, it will default to "username". + username from the JWT token. When not specified, it will default to "username", + unless usernameExpression is specified. + + Mutually exclusive with usernameExpression. Use either username or usernameExpression to + determine the user's username from the JWT token. + type: string + usernameExpression: + description: |- + usernameExpression represents an expression which will be evaluated by CEL. + + The expression's result will become the user's username. + + The expression must produce a non-empty string value. + If the expression uses 'claims.email', then 'claims.email_verified' must be used in + the expression or extra[*].valueExpression or claimValidationRules[*].expression. + An example claim validation rule expression that matches the validation automatically + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + and to make sure a non-boolean email_verified claim will be caught at runtime. + + CEL expressions have access to the contents of the token claims, organized into CEL variable: + - 'claims' is a map of claim names to claim values. + For example, a variable named 'sub' can be accessed as 'claims.sub'. + Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + Mutually exclusive with username. Use either username or usernameExpression to + determine the user's username from the JWT token. type: string type: object issuer: diff --git a/generated/latest/README.adoc b/generated/latest/README.adoc index 5c4577bd0..5796e1366 100644 --- a/generated/latest/README.adoc +++ b/generated/latest/README.adoc @@ -237,10 +237,55 @@ for Kubernetes access. [cols="25a,75a", options="header"] |=== | Field | Description -| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + -group membership from the JWT token. When not specified, it will default to "groups". + | *`username`* __string__ | username is the name of the claim which should be read to extract the + -username from the JWT token. When not specified, it will default to "username". + +username from the JWT token. When not specified, it will default to "username", + +unless usernameExpression is specified. + + +Mutually exclusive with usernameExpression. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's username. + + +The expression must produce a non-empty string value. + +If the expression uses 'claims.email', then 'claims.email_verified' must be used in + +the expression or extra[*].valueExpression or claimValidationRules[*].expression. + +An example claim validation rule expression that matches the validation automatically + +applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + +By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + +and to make sure a non-boolean email_verified claim will be caught at runtime. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with username. Use either username or usernameExpression to + +determine the user's username from the JWT token. + +| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's + +group membership from the JWT token. When not specified, it will default to "groups", + +unless groupsExpression is specified. + + +Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + +| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. + + +The expression's result will become the user's group memberships. + + +The expression must produce a string or string array value. + +"", [], and null values are treated as the group mapping not being present. + + +CEL expressions have access to the contents of the token claims, organized into CEL variable: + +- 'claims' is a map of claim names to claim values. + +For example, a variable named 'sub' can be accessed as 'claims.sub'. + +Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + + +Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + + +Mutually exclusive with groups. Use either groups or groupsExpression to + +determine the user's group membership from the JWT token. + | *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in + https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the + Pinniped Concierge issues client certificates to users for the purpose of authenticating, and + diff --git a/generated/latest/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go b/generated/latest/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go index d5149642f..8d416bcbf 100644 --- a/generated/latest/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go +++ b/generated/latest/apis/concierge/authentication/v1alpha1/types_jwtauthenticator.go @@ -137,15 +137,66 @@ type UserValidationRule struct { // JWTTokenClaims allows customization of the claims that will be mapped to user identity // for Kubernetes access. type JWTTokenClaims struct { + // username is the name of the claim which should be read to extract the + // username from the JWT token. When not specified, it will default to "username", + // unless usernameExpression is specified. + // + // Mutually exclusive with usernameExpression. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + Username string `json:"username"` + + // usernameExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's username. + // + // The expression must produce a non-empty string value. + // If the expression uses 'claims.email', then 'claims.email_verified' must be used in + // the expression or extra[*].valueExpression or claimValidationRules[*].expression. + // An example claim validation rule expression that matches the validation automatically + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. + // By explicitly comparing the value to true, we let type-checking see the result will be a boolean, + // and to make sure a non-boolean email_verified claim will be caught at runtime. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with username. Use either username or usernameExpression to + // determine the user's username from the JWT token. + // +optional + UsernameExpression string `json:"usernameExpression,omitempty"` + // groups is the name of the claim which should be read to extract the user's - // group membership from the JWT token. When not specified, it will default to "groups". + // group membership from the JWT token. When not specified, it will default to "groups", + // unless groupsExpression is specified. + // + // Mutually exclusive with groupsExpression. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional Groups string `json:"groups"` - // username is the name of the claim which should be read to extract the - // username from the JWT token. When not specified, it will default to "username". + // groupsExpression represents an expression which will be evaluated by CEL. + // + // The expression's result will become the user's group memberships. + // + // The expression must produce a string or string array value. + // "", [], and null values are treated as the group mapping not being present. + // + // CEL expressions have access to the contents of the token claims, organized into CEL variable: + // - 'claims' is a map of claim names to claim values. + // For example, a variable named 'sub' can be accessed as 'claims.sub'. + // Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. + // + // Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ + // + // Mutually exclusive with groups. Use either groups or groupsExpression to + // determine the user's group membership from the JWT token. // +optional - Username string `json:"username"` + GroupsExpression string `json:"groupsExpression,omitempty"` // extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration as documented in // https://kubernetes.io/docs/reference/access-authn-authz/authentication. However, note that the diff --git a/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type.go b/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type.go index 9650487cb..5c9fb4ff4 100644 --- a/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type.go +++ b/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type.go @@ -15,45 +15,65 @@ import ( // but is otherwise a straight conversion. The Pinniped type includes TLS configuration which does not need // to be converted because that is applied elsewhere. func convertJWTAuthenticatorSpecType(spec *authenticationv1alpha1.JWTAuthenticatorSpec) apiserver.JWTAuthenticator { - usernameClaim := spec.Claims.Username - if usernameClaim == "" { - usernameClaim = defaultUsernameClaim - } - - groupsClaim := spec.Claims.Groups - if groupsClaim == "" { - groupsClaim = defaultGroupsClaim + return apiserver.JWTAuthenticator{ + Issuer: convertIssuerType(spec), + ClaimMappings: convertClaimMappingsType(spec.Claims), + ClaimValidationRules: convertClaimValidationRulesType(spec.ClaimValidationRules), + UserValidationRules: convertUserValidationRulesType(spec.UserValidationRules), } +} +func convertIssuerType(spec *authenticationv1alpha1.JWTAuthenticatorSpec) apiserver.Issuer { var aud []string if len(spec.Audience) > 0 { aud = []string{spec.Audience} } - jwtAuthenticator := apiserver.JWTAuthenticator{ - Issuer: apiserver.Issuer{ - URL: spec.Issuer, - Audiences: aud, - }, - ClaimMappings: apiserver.ClaimMappings{ - Username: apiserver.PrefixedClaimOrExpression{ - Claim: usernameClaim, - Prefix: ptr.To(""), - }, - Groups: apiserver.PrefixedClaimOrExpression{ - Claim: groupsClaim, - Prefix: ptr.To(""), - }, - Extra: convertExtraType(spec.Claims.Extra), - }, - ClaimValidationRules: convertClaimValidationRulesType(spec.ClaimValidationRules), - UserValidationRules: convertUserValidationRules(spec.UserValidationRules), + return apiserver.Issuer{ + URL: spec.Issuer, + Audiences: aud, } - - return jwtAuthenticator } -func convertUserValidationRules(rules []authenticationv1alpha1.UserValidationRule) []apiserver.UserValidationRule { +func convertClaimMappingsType(claims authenticationv1alpha1.JWTTokenClaims) apiserver.ClaimMappings { + usernameClaim := claims.Username + if usernameClaim == "" && claims.UsernameExpression == "" { + usernameClaim = defaultUsernameClaim + } + + var usernamePrefix *string + if usernameClaim != "" { + // Must be set only when username claim name is set. + usernamePrefix = ptr.To("") + } + + groupsClaim := claims.Groups + if groupsClaim == "" && claims.GroupsExpression == "" { + groupsClaim = defaultGroupsClaim + } + + var groupsPrefix *string + if groupsClaim != "" { + // Must be set only when groups claim name is set. + groupsPrefix = ptr.To("") + } + + return apiserver.ClaimMappings{ + Username: apiserver.PrefixedClaimOrExpression{ + Claim: usernameClaim, + Prefix: usernamePrefix, + Expression: claims.UsernameExpression, + }, + Groups: apiserver.PrefixedClaimOrExpression{ + Claim: groupsClaim, + Prefix: groupsPrefix, + Expression: claims.GroupsExpression, + }, + Extra: convertExtraType(claims.Extra), + } +} + +func convertUserValidationRulesType(rules []authenticationv1alpha1.UserValidationRule) []apiserver.UserValidationRule { if len(rules) == 0 { return nil } diff --git a/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type_test.go b/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type_test.go index fc92334a8..bbbbadb5c 100644 --- a/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type_test.go +++ b/internal/controller/authenticator/jwtcachefiller/convert_jwtauthenticator_type_test.go @@ -21,7 +21,7 @@ func Test_convertJWTAuthenticatorSpecType(t *testing.T) { want apiserver.JWTAuthenticator }{ { - name: "defaults the username and groups claims", + name: "defaults the username and groups claims when the usernameExpression and groupExpression are not set", spec: &authenticationv1alpha1.JWTAuthenticatorSpec{ Issuer: "https://example.com", }, @@ -41,6 +41,33 @@ func Test_convertJWTAuthenticatorSpecType(t *testing.T) { }, }, }, + { + name: "does not default the username and groups claims an prefixes when the usernameExpression and groupExpression are set", + spec: &authenticationv1alpha1.JWTAuthenticatorSpec{ + Issuer: "https://example.com", + Claims: authenticationv1alpha1.JWTTokenClaims{ + UsernameExpression: `"foo"`, + GroupsExpression: `["foo"]`, + }, + }, + want: apiserver.JWTAuthenticator{ + Issuer: apiserver.Issuer{ + URL: "https://example.com", + }, + ClaimMappings: apiserver.ClaimMappings{ + Username: apiserver.PrefixedClaimOrExpression{ + Claim: "", + Prefix: nil, + Expression: `"foo"`, + }, + Groups: apiserver.PrefixedClaimOrExpression{ + Claim: "", + Prefix: nil, + Expression: `["foo"]`, + }, + }, + }, + }, { name: "converts every field except for TLS", spec: &authenticationv1alpha1.JWTAuthenticatorSpec{ diff --git a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go index a31f1a59d..4ea127c3d 100644 --- a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go +++ b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go @@ -360,13 +360,13 @@ func TestController(t *testing.T) { Groups: customGroupsClaim, }, } - someJWTAuthenticatorSpecWithEveryOptionalValue := &authenticationv1alpha1.JWTAuthenticatorSpec{ + someJWTAuthenticatorSpecWithManyOptionalValues := &authenticationv1alpha1.JWTAuthenticatorSpec{ Issuer: goodIssuer, Audience: goodAudience, TLS: goodOIDCIssuerServerTLSSpec, Claims: authenticationv1alpha1.JWTTokenClaims{ - Username: "my-custom-username-claim", - Groups: customGroupsClaim, + Username: "my-custom-username-claim", // note: can't specify this and usernameExpression at the same time + Groups: customGroupsClaim, // note: can't specify this and groupsExpression at the same time Extra: []authenticationv1alpha1.ExtraMapping{ { Key: "example.com/key-name", // must be a domain and path @@ -387,6 +387,15 @@ func TestController(t *testing.T) { }, }, } + someJWTAuthenticatorSpecWithUsernameAndGroupExpressions := &authenticationv1alpha1.JWTAuthenticatorSpec{ + Issuer: goodIssuer, + Audience: goodAudience, + TLS: goodOIDCIssuerServerTLSSpec, + Claims: authenticationv1alpha1.JWTTokenClaims{ + UsernameExpression: "claims.otherUsernameClaim", + GroupsExpression: "has(claims.otherGroupsClaim) ? claims.otherGroupsClaim : []", // handles the case where the claim does not exist in the JWT + }, + } invalidClaimsExtraJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{ Issuer: goodIssuer, Audience: goodAudience, @@ -420,6 +429,17 @@ func TestController(t *testing.T) { }, }, } + invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{ + Issuer: goodIssuer, + Audience: goodAudience, + TLS: goodOIDCIssuerServerTLSSpec, + Claims: authenticationv1alpha1.JWTTokenClaims{ + Username: "user", + UsernameExpression: `"user"`, + Groups: "groups", + GroupsExpression: `["group1"]`, + }, + } invalidClaimsExtraContainsEqualSignJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{ Issuer: goodIssuer, Audience: goodAudience, @@ -1193,13 +1213,13 @@ func TestController(t *testing.T) { wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"}, }, { - name: "Sync: JWTAuthenticator with every optional value: loop will complete successfully and update status conditions", + name: "Sync: JWTAuthenticator with many optional values: loop will complete successfully and update status conditions", jwtAuthenticators: []runtime.Object{ &authenticationv1alpha1.JWTAuthenticator{ ObjectMeta: metav1.ObjectMeta{ Name: "test-name", }, - Spec: *someJWTAuthenticatorSpecWithEveryOptionalValue, + Spec: *someJWTAuthenticatorSpecWithManyOptionalValues, }, }, wantLogLines: []string{ @@ -1211,7 +1231,7 @@ func TestController(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "test-name", }, - Spec: *someJWTAuthenticatorSpecWithEveryOptionalValue, + Spec: *someJWTAuthenticatorSpecWithManyOptionalValues, Status: authenticationv1alpha1.JWTAuthenticatorStatus{ Conditions: allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0), Phase: "Ready", @@ -1229,6 +1249,42 @@ func TestController(t *testing.T) { wantExtras: map[string][]string{"example.com/key-name": {"extra-value"}}, wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"}, }, + { + name: "Sync: JWTAuthenticator with usernameExpression and groupsExpression values: loop will complete successfully and update status conditions", + jwtAuthenticators: []runtime.Object{ + &authenticationv1alpha1.JWTAuthenticator{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: *someJWTAuthenticatorSpecWithUsernameAndGroupExpressions, + }, + }, + wantLogLines: []string{ + fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Ready"}`, goodIssuer), + fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"added or updated jwt authenticator in cache","jwtAuthenticator":"test-name","issuer":"%s","isOverwrite":false}`, goodIssuer), + }, + wantActions: func() []coretesting.Action { + updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: *someJWTAuthenticatorSpecWithUsernameAndGroupExpressions, + Status: authenticationv1alpha1.JWTAuthenticatorStatus{ + Conditions: allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0), + Phase: "Ready", + }, + }) + updateStatusAction.Subresource = "status" + return []coretesting.Action{ + coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}), + coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}), + updateStatusAction, + } + }, + wantUsernameClaim: "otherUsernameClaim", + wantGroupsClaim: "otherGroupsClaim", + wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"}, + }, { name: "Sync: JWTAuthenticator with new spec.tls fields: loop will close previous instance of JWTAuthenticator and complete successfully and update status conditions", cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) { @@ -2652,6 +2708,53 @@ func TestController(t *testing.T) { } }, }, + { + name: "newCachedJWTAuthenticator: validateAuthenticationConfiguration: when username and usernameExpression and/or groups and groupsExpression are both set: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error", + jwtAuthenticators: []runtime.Object{ + &authenticationv1alpha1.JWTAuthenticator{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: *invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec, + }, + }, + wantLogLines: []string{ + fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"invalid jwt authenticator","jwtAuthenticator":"test-name","issuer":"%s","removedFromCache":false}`, invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec.Issuer), + fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Error"}`, invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec.Issuer), + }, + wantActions: func() []coretesting.Action { + updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: *invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec, + Status: authenticationv1alpha1.JWTAuthenticatorStatus{ + Conditions: conditionstestutil.Replace( + allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0), + []metav1.Condition{ + sadReadyCondition(frozenMetav1Now, 0), + happyIssuerURLValid(frozenMetav1Now, 0), + happyDiscoveryURLValid(frozenMetav1Now, 0), + sadAuthenticatorValid( + `could not initialize jwt authenticator: [claims.username: Invalid value: "": claim and expression can't both be set, claims.groups: Invalid value: "": claim and expression can't both be set]`, + frozenMetav1Now, + 0, + ), + happyJWKSURLValid(frozenMetav1Now, 0), + happyJWKSFetch(frozenMetav1Now, 0), + }, + ), + Phase: "Error", + }, + }) + updateStatusAction.Subresource = "status" + return []coretesting.Action{ + coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}), + coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}), + updateStatusAction, + } + }, + }, { name: "newCachedJWTAuthenticator: when any claims.extra[].key contains an equals sign: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error", jwtAuthenticators: []runtime.Object{ @@ -2903,6 +3006,15 @@ func TestController(t *testing.T) { cachedAuthenticator, ok := temp.(tokenAuthenticatorCloser) require.True(t, ok) + usernameClaimIsCelExpression := false + if temp.(*cachedJWTAuthenticator).claims.UsernameExpression != "" { + usernameClaimIsCelExpression = true + } + groupsClaimIsCelExpression := false + if temp.(*cachedJWTAuthenticator).claims.GroupsExpression != "" { + groupsClaimIsCelExpression = true + } + // Schedule it to be closed at the end of the test. t.Cleanup(cachedAuthenticator.Close) @@ -2930,13 +3042,19 @@ func TestController(t *testing.T) { group1, goodUsername, tt.wantUsernameClaim, + usernameClaimIsCelExpression, tt.wantGroupsClaim, + groupsClaimIsCelExpression, tt.wantExtras, goodIssuer, ) { t.Run(test.name, func(t *testing.T) { t.Parallel() + if test.skip != nil { + test.skip(t) // give the test a chance to skip itself if it wants to + } + wellKnownClaims := josejwt.Claims{ Issuer: goodIssuer, Subject: goodSubject, @@ -3012,7 +3130,9 @@ func testTableForAuthenticateTokenTests( group1 string, goodUsername string, expectedUsernameClaim string, + usernameClaimIsCelExpression bool, expectedGroupsClaim string, + groupsClaimIsCelExpression bool, expectedExtras map[string][]string, issuer string, ) []struct { @@ -3023,7 +3143,22 @@ func testTableForAuthenticateTokenTests( wantAuthenticated bool wantErr testutil.RequireErrorStringFunc distributedGroupsClaimURL string + skip func(t *testing.T) } { + expectedErrForBadTokenWithGroupsAsMap := func() testutil.RequireErrorStringFunc { + if groupsClaimIsCelExpression { + return testutil.WantExactErrorString(`oidc: error evaluating group claim expression: expression must return a string or a list of strings`) + } + return testutil.WantExactErrorString(`oidc: parse groups claim "` + expectedGroupsClaim + `": json: cannot unmarshal object into Go value of type string`) + } + + expectedErrForTokenDoesNotHaveUsernameClaim := func() testutil.RequireErrorStringFunc { + if usernameClaimIsCelExpression { + return testutil.WantMatchingErrorString(`oidc: error evaluating username claim expression: expression '.+' resulted in error: no such key: ` + expectedUsernameClaim) + } + return testutil.WantExactErrorString(`oidc: parse username claims "` + expectedUsernameClaim + `": claim not present`) + } + tests := []struct { name string jwtClaims func(wellKnownClaims *josejwt.Claims, groups *any, username *string) @@ -3032,6 +3167,7 @@ func testTableForAuthenticateTokenTests( wantAuthenticated bool wantErr testutil.RequireErrorStringFunc distributedGroupsClaimURL string + skip func(t *testing.T) }{ { name: "good token without groups and with EC signature", @@ -3085,13 +3221,23 @@ func testTableForAuthenticateTokenTests( }, }, wantAuthenticated: true, + skip: func(t *testing.T) { + if groupsClaimIsCelExpression { + t.Skip("skipping test because Kubernetes does not support using a CEL expression for groups mapping with distributed claims") + } + }, }, { name: "distributed groups returns a 404", jwtClaims: func(claims *josejwt.Claims, groups *any, username *string) { }, distributedGroupsClaimURL: issuer + "/not_found_claim_source", - wantErr: testutil.WantMatchingErrorString(`oidc: could not expand distributed claims: while getting distributed claim "` + expectedGroupsClaim + `": error while getting distributed claim JWT: 404 Not Found`), + wantErr: testutil.WantExactErrorString(`oidc: could not expand distributed claims: while getting distributed claim "` + expectedGroupsClaim + `": error while getting distributed claim JWT: 404 Not Found`), + skip: func(t *testing.T) { + if groupsClaimIsCelExpression { + t.Skip("skipping test because Kubernetes does not support using a CEL expression for groups mapping with distributed claims") + } + }, }, { name: "distributed groups doesn't return the right claim", @@ -3099,6 +3245,11 @@ func testTableForAuthenticateTokenTests( }, distributedGroupsClaimURL: issuer + "/wrong_claim_source", wantErr: testutil.WantMatchingErrorString(`oidc: could not expand distributed claims: jwt returned by distributed claim endpoint "` + issuer + `/wrong_claim_source" did not contain claim: `), + skip: func(t *testing.T) { + if groupsClaimIsCelExpression { + t.Skip("skipping test because Kubernetes does not support using a CEL expression for groups mapping with distributed claims") + } + }, }, { name: "good token with groups as string", @@ -3132,7 +3283,7 @@ func testTableForAuthenticateTokenTests( jwtClaims: func(_ *josejwt.Claims, groups *any, username *string) { *groups = map[string]string{"not an array": "or a string"} }, - wantErr: testutil.WantMatchingErrorString(`oidc: parse groups claim "` + expectedGroupsClaim + `": json: cannot unmarshal object into Go value of type string`), + wantErr: expectedErrForBadTokenWithGroupsAsMap(), }, { name: "bad token with wrong issuer", @@ -3147,14 +3298,14 @@ func testTableForAuthenticateTokenTests( jwtClaims: func(claims *josejwt.Claims, _ *any, username *string) { claims.Audience = nil }, - wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: expected audience "some-audience" got \[\]`), + wantErr: testutil.WantExactErrorString(`oidc: verify token: oidc: expected audience "some-audience" got []`), }, { name: "bad token with wrong audience", jwtClaims: func(claims *josejwt.Claims, _ *any, username *string) { claims.Audience = []string{"wrong-audience"} }, - wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: expected audience "some-audience" got \["wrong-audience"\]`), + wantErr: testutil.WantExactErrorString(`oidc: verify token: oidc: expected audience "some-audience" got ["wrong-audience"]`), }, { name: "bad token with nbf in the future", @@ -3182,7 +3333,7 @@ func testTableForAuthenticateTokenTests( jwtClaims: func(claims *josejwt.Claims, _ *any, username *string) { *username = "" }, - wantErr: testutil.WantMatchingErrorString(`oidc: parse username claims "` + expectedUsernameClaim + `": claim not present`), + wantErr: expectedErrForTokenDoesNotHaveUsernameClaim(), }, { name: "signing key is wrong", @@ -3192,7 +3343,7 @@ func testTableForAuthenticateTokenTests( require.NoError(t, err) *algo = jose.ES256 }, - wantErr: testutil.WantMatchingErrorString(`oidc: verify token: failed to verify signature: failed to verify id token signature`), + wantErr: testutil.WantExactErrorString(`oidc: verify token: failed to verify signature: failed to verify id token signature`), }, { name: "signing algo is unsupported", @@ -3202,7 +3353,7 @@ func testTableForAuthenticateTokenTests( require.NoError(t, err) *algo = jose.ES384 }, - wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: id token signed with unsupported algorithm, expected \["RS256" "ES256"\] got "ES384"`), + wantErr: testutil.WantExactErrorString(`oidc: verify token: oidc: id token signed with unsupported algorithm, expected ["RS256" "ES256"] got "ES384"`), }, }