Merge pull request #258 from ankeesler/jwt-authenticator
Add JWTAuthenticator API and initial controller
This commit is contained in:
commit
8fcc176d8b
@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&WebhookAuthenticator{},
|
||||
&WebhookAuthenticatorList{},
|
||||
&JWTAuthenticator{},
|
||||
&JWTAuthenticatorList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
|
62
apis/concierge/authentication/v1alpha1/types_jwt.go.tmpl
Normal file
62
apis/concierge/authentication/v1alpha1/types_jwt.go.tmpl
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
// +patchStrategy=merge
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
//
|
||||
// Upon receiving a signed JWT, a JWTAuthenticator will performs some validation on it (e.g., valid
|
||||
// signature, existence of claims, etc.) and extract the username and groups from the token.
|
||||
//
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +kubebuilder:resource:categories=pinniped;pinniped-authenticator;pinniped-authenticators
|
||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||
type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []JWTAuthenticator `json:"items"`
|
||||
}
|
@ -64,7 +64,7 @@ func newExchangeCredentialCmd(args []string, stdout, stderr io.Writer) *exchange
|
||||
- PINNIPED_NAMESPACE: the namespace of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_AUTHENTICATOR_TYPE: the type of authenticator to authenticate
|
||||
against (e.g., "webhook")
|
||||
against (e.g., "webhook", "jwt")
|
||||
- PINNIPED_AUTHENTICATOR_NAME: the name of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_CA_BUNDLE: the CA bundle to trust when calling
|
||||
@ -148,8 +148,11 @@ func exchangeCredential(envGetter envGetter, tokenExchanger tokenExchanger, outp
|
||||
case "webhook":
|
||||
authenticator.APIGroup = &auth1alpha1.SchemeGroupVersion.Group
|
||||
authenticator.Kind = "WebhookAuthenticator"
|
||||
case "jwt":
|
||||
authenticator.APIGroup = &auth1alpha1.SchemeGroupVersion.Group
|
||||
authenticator.Kind = "JWTAuthenticator"
|
||||
default:
|
||||
return fmt.Errorf(`%w: %q, supported values are "webhook"`, ErrInvalidAuthenticatorType, authenticatorType)
|
||||
return fmt.Errorf(`%w: %q, supported values are "webhook" and "jwt"`, ErrInvalidAuthenticatorType, authenticatorType)
|
||||
}
|
||||
|
||||
cred, err := tokenExchanger(ctx, namespace, authenticator, token, caBundle, apiEndpoint)
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
"go.pinniped.dev/internal/here"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
@ -46,7 +47,7 @@ var (
|
||||
- PINNIPED_NAMESPACE: the namespace of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_AUTHENTICATOR_TYPE: the type of authenticator to authenticate
|
||||
against (e.g., "webhook")
|
||||
against (e.g., "webhook", "jwt")
|
||||
- PINNIPED_AUTHENTICATOR_NAME: the name of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_CA_BUNDLE: the CA bundle to trust when calling
|
||||
@ -193,7 +194,7 @@ func TestExchangeCredential(t *testing.T) {
|
||||
it("returns an error when PINNIPED_AUTHENTICATOR_TYPE is missing", func() {
|
||||
fakeEnv["PINNIPED_AUTHENTICATOR_TYPE"] = "invalid"
|
||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||
r.EqualError(err, `invalid authenticator type: "invalid", supported values are "webhook"`)
|
||||
r.EqualError(err, `invalid authenticator type: "invalid", supported values are "webhook" and "jwt"`)
|
||||
})
|
||||
})
|
||||
|
||||
@ -292,5 +293,50 @@ func TestExchangeCredential(t *testing.T) {
|
||||
r.JSONEq(expected, buffer.String())
|
||||
})
|
||||
})
|
||||
|
||||
when("the authenticator info is passed", func() {
|
||||
var actualAuthenticator corev1.TypedLocalObjectReference
|
||||
|
||||
it.Before(func() {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, authenticator corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
actualAuthenticator = authenticator
|
||||
return nil, nil
|
||||
}
|
||||
})
|
||||
|
||||
when("the authenticator is of type webhook", func() {
|
||||
it.Before(func() {
|
||||
fakeEnv["PINNIPED_AUTHENTICATOR_TYPE"] = "webhook"
|
||||
fakeEnv["PINNIPED_AUTHENTICATOR_NAME"] = "some-webhook-name"
|
||||
})
|
||||
|
||||
it("passes the correct authenticator type to the token exchanger", func() {
|
||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||
r.NoError(err)
|
||||
require.Equal(t, corev1.TypedLocalObjectReference{
|
||||
APIGroup: &auth1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "WebhookAuthenticator",
|
||||
Name: "some-webhook-name",
|
||||
}, actualAuthenticator)
|
||||
})
|
||||
})
|
||||
|
||||
when("the authenticator is of type jwt", func() {
|
||||
it.Before(func() {
|
||||
fakeEnv["PINNIPED_AUTHENTICATOR_TYPE"] = "jwt"
|
||||
fakeEnv["PINNIPED_AUTHENTICATOR_NAME"] = "some-jwt-authenticator-name"
|
||||
})
|
||||
|
||||
it("passes the correct authenticator type to the token exchanger", func() {
|
||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||
r.NoError(err)
|
||||
require.Equal(t, corev1.TypedLocalObjectReference{
|
||||
APIGroup: &auth1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "JWTAuthenticator",
|
||||
Name: "some-jwt-authenticator-name",
|
||||
}, actualAuthenticator)
|
||||
})
|
||||
})
|
||||
})
|
||||
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func (c *getKubeConfigCommand) Command() *cobra.Command {
|
||||
cmd.Flags().StringVar(&c.flags.kubeconfig, "kubeconfig", c.flags.kubeconfig, "Path to the kubeconfig file")
|
||||
cmd.Flags().StringVar(&c.flags.contextOverride, "kubeconfig-context", c.flags.contextOverride, "Kubeconfig context override")
|
||||
cmd.Flags().StringVar(&c.flags.namespace, "pinniped-namespace", c.flags.namespace, "Namespace in which Pinniped was installed")
|
||||
cmd.Flags().StringVar(&c.flags.authenticatorType, "authenticator-type", c.flags.authenticatorType, "Authenticator type (e.g., 'webhook')")
|
||||
cmd.Flags().StringVar(&c.flags.authenticatorType, "authenticator-type", c.flags.authenticatorType, "Authenticator type (e.g., 'webhook', 'jwt')")
|
||||
cmd.Flags().StringVar(&c.flags.authenticatorName, "authenticator-name", c.flags.authenticatorType, "Authenticator name")
|
||||
mustMarkRequired(cmd, "token")
|
||||
plog.RemoveKlogGlobalFlags()
|
||||
|
@ -31,7 +31,7 @@ var (
|
||||
|
||||
Flags:
|
||||
--authenticator-name string Authenticator name
|
||||
--authenticator-type string Authenticator type (e.g., 'webhook')
|
||||
--authenticator-type string Authenticator type (e.g., 'webhook', 'jwt')
|
||||
-h, --help help for get-kubeconfig
|
||||
--kubeconfig string Path to the kubeconfig file
|
||||
--kubeconfig-context string Kubeconfig context override
|
||||
@ -62,7 +62,7 @@ var (
|
||||
|
||||
Flags:
|
||||
--authenticator-name string Authenticator name
|
||||
--authenticator-type string Authenticator type (e.g., 'webhook')
|
||||
--authenticator-type string Authenticator type (e.g., 'webhook', 'jwt')
|
||||
-h, --help help for get-kubeconfig
|
||||
--kubeconfig string Path to the kubeconfig file
|
||||
--kubeconfig-context string Kubeconfig context override
|
||||
|
@ -0,0 +1,155 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.4.0
|
||||
creationTimestamp: null
|
||||
name: jwtauthenticators.authentication.concierge.pinniped.dev
|
||||
spec:
|
||||
group: authentication.concierge.pinniped.dev
|
||||
names:
|
||||
categories:
|
||||
- pinniped
|
||||
- pinniped-authenticator
|
||||
- pinniped-authenticators
|
||||
kind: JWTAuthenticator
|
||||
listKind: JWTAuthenticatorList
|
||||
plural: jwtauthenticators
|
||||
singular: jwtauthenticator
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.issuer
|
||||
name: Issuer
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
\n Upon receiving a signed JWT, a JWTAuthenticator will performs some validation
|
||||
on it (e.g., valid signature, existence of claims, etc.) and extract the
|
||||
username and groups from the token."
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
issuer:
|
||||
description: Issuer is the OIDC issuer URL that will be used to discover
|
||||
public signing keys. Issuer is also used to validate the "iss" JWT
|
||||
claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
If omitted, a default set of system roots will be trusted.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
state.
|
||||
items:
|
||||
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||
type added in Kubernetes 1.19). In a future API version we can
|
||||
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
@ -15,3 +15,9 @@ metadata:
|
||||
metadata:
|
||||
#@overlay/match missing_ok=True
|
||||
labels: #@ labels()
|
||||
|
||||
#@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"jwtauthenticators.authentication.concierge.pinniped.dev"}}), expects=1
|
||||
---
|
||||
metadata:
|
||||
#@overlay/match missing_ok=True
|
||||
labels: #@ labels()
|
||||
|
83
generated/1.17/README.adoc
generated
83
generated/1.17/README.adoc
generated
@ -22,10 +22,11 @@ Package v1alpha1 is the v1alpha1 version of the Pinniped concierge authenticatio
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-condition"]
|
||||
==== Condition
|
||||
|
||||
Condition status of a resource (mirrored from the metav1.Condition type added in Kubernetes 1.19). In a future API version we can switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-webhookauthenticatorstatus[$$WebhookAuthenticatorStatus$$]
|
||||
****
|
||||
|
||||
@ -41,13 +42,85 @@ Condition status of a resource (mirrored from the metav1.Condition type added in
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-tlsspec"]
|
||||
==== TLSSpec
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-conditionstatus"]
|
||||
==== ConditionStatus (string)
|
||||
|
||||
|
||||
Configuration for configuring TLS on various authenticators.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-condition[$$Condition$$]
|
||||
****
|
||||
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
Upon receiving a signed JWT, a JWTAuthenticator will performs some validation on it (e.g., valid signature, existence of claims, etc.) and extract the username and groups from the token.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticatorlist[$$JWTAuthenticatorList$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator.
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticator[$$JWTAuthenticator$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is also used to validate the "iss" JWT claim.
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider.
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticator[$$JWTAuthenticator$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-condition[$$Condition$$] array__ | Represents the observations of the authenticator's current state.
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-tlsspec"]
|
||||
==== TLSSpec
|
||||
|
||||
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-webhookauthenticatorspec[$$WebhookAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
@ -111,7 +184,7 @@ Status of a webhook authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-condition[$$Condition$$]__ | Represents the observations of the authenticator's current state.
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-authentication-v1alpha1-condition[$$Condition$$] array__ | Represents the observations of the authenticator's current state.
|
||||
|===
|
||||
|
||||
|
||||
|
@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&WebhookAuthenticator{},
|
||||
&WebhookAuthenticatorList{},
|
||||
&JWTAuthenticator{},
|
||||
&JWTAuthenticatorList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
|
62
generated/1.17/apis/concierge/authentication/v1alpha1/types_jwt.go
generated
Normal file
62
generated/1.17/apis/concierge/authentication/v1alpha1/types_jwt.go
generated
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
// +patchStrategy=merge
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
//
|
||||
// Upon receiving a signed JWT, a JWTAuthenticator will performs some validation on it (e.g., valid
|
||||
// signature, existence of claims, etc.) and extract the username and groups from the token.
|
||||
//
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +kubebuilder:resource:categories=pinniped;pinniped-authenticator;pinniped-authenticators
|
||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||
type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []JWTAuthenticator `json:"items"`
|
||||
}
|
@ -28,6 +28,111 @@ func (in *Condition) DeepCopy() *Condition {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticator.
|
||||
func (in *JWTAuthenticator) DeepCopy() *JWTAuthenticator {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticator)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JWTAuthenticator) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorList) DeepCopyInto(out *JWTAuthenticatorList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]JWTAuthenticator, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorList.
|
||||
func (in *JWTAuthenticatorList) DeepCopy() *JWTAuthenticatorList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorSpec.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopy() *JWTAuthenticatorSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorStatus) DeepCopyInto(out *JWTAuthenticatorStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorStatus.
|
||||
func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSSpec) DeepCopyInto(out *TLSSpec) {
|
||||
*out = *in
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
type AuthenticationV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
JWTAuthenticatorsGetter
|
||||
WebhookAuthenticatorsGetter
|
||||
}
|
||||
|
||||
@ -21,6 +22,10 @@ type AuthenticationV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *AuthenticationV1alpha1Client) JWTAuthenticators(namespace string) JWTAuthenticatorInterface {
|
||||
return newJWTAuthenticators(c, namespace)
|
||||
}
|
||||
|
||||
func (c *AuthenticationV1alpha1Client) WebhookAuthenticators(namespace string) WebhookAuthenticatorInterface {
|
||||
return newWebhookAuthenticators(c, namespace)
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ type FakeAuthenticationV1alpha1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeAuthenticationV1alpha1) JWTAuthenticators(namespace string) v1alpha1.JWTAuthenticatorInterface {
|
||||
return &FakeJWTAuthenticators{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeAuthenticationV1alpha1) WebhookAuthenticators(namespace string) v1alpha1.WebhookAuthenticatorInterface {
|
||||
return &FakeWebhookAuthenticators{c, namespace}
|
||||
}
|
||||
|
@ -0,0 +1,127 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "go.pinniped.dev/generated/1.17/apis/concierge/authentication/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeJWTAuthenticators implements JWTAuthenticatorInterface
|
||||
type FakeJWTAuthenticators struct {
|
||||
Fake *FakeAuthenticationV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var jwtauthenticatorsResource = schema.GroupVersionResource{Group: "authentication.concierge.pinniped.dev", Version: "v1alpha1", Resource: "jwtauthenticators"}
|
||||
|
||||
var jwtauthenticatorsKind = schema.GroupVersionKind{Group: "authentication.concierge.pinniped.dev", Version: "v1alpha1", Kind: "JWTAuthenticator"}
|
||||
|
||||
// Get takes name of the jWTAuthenticator, and returns the corresponding jWTAuthenticator object, and an error if there is any.
|
||||
func (c *FakeJWTAuthenticators) Get(name string, options v1.GetOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(jwtauthenticatorsResource, c.ns, name), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of JWTAuthenticators that match those selectors.
|
||||
func (c *FakeJWTAuthenticators) List(opts v1.ListOptions) (result *v1alpha1.JWTAuthenticatorList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(jwtauthenticatorsResource, jwtauthenticatorsKind, c.ns, opts), &v1alpha1.JWTAuthenticatorList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.JWTAuthenticatorList{ListMeta: obj.(*v1alpha1.JWTAuthenticatorList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.JWTAuthenticatorList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested jWTAuthenticators.
|
||||
func (c *FakeJWTAuthenticators) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(jwtauthenticatorsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a jWTAuthenticator and creates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *FakeJWTAuthenticators) Create(jWTAuthenticator *v1alpha1.JWTAuthenticator) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(jwtauthenticatorsResource, c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a jWTAuthenticator and updates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *FakeJWTAuthenticators) Update(jWTAuthenticator *v1alpha1.JWTAuthenticator) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(jwtauthenticatorsResource, c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeJWTAuthenticators) UpdateStatus(jWTAuthenticator *v1alpha1.JWTAuthenticator) (*v1alpha1.JWTAuthenticator, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(jwtauthenticatorsResource, "status", c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// Delete takes name of the jWTAuthenticator and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeJWTAuthenticators) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(jwtauthenticatorsResource, c.ns, name), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeJWTAuthenticators) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(jwtauthenticatorsResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.JWTAuthenticatorList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched jWTAuthenticator.
|
||||
func (c *FakeJWTAuthenticators) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(jwtauthenticatorsResource, c.ns, name, pt, data, subresources...), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
@ -5,4 +5,6 @@
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type JWTAuthenticatorExpansion interface{}
|
||||
|
||||
type WebhookAuthenticatorExpansion interface{}
|
||||
|
178
generated/1.17/client/concierge/clientset/versioned/typed/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
178
generated/1.17/client/concierge/clientset/versioned/typed/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
@ -0,0 +1,178 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1alpha1 "go.pinniped.dev/generated/1.17/apis/concierge/authentication/v1alpha1"
|
||||
scheme "go.pinniped.dev/generated/1.17/client/concierge/clientset/versioned/scheme"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorsGetter has a method to return a JWTAuthenticatorInterface.
|
||||
// A group's client should implement this interface.
|
||||
type JWTAuthenticatorsGetter interface {
|
||||
JWTAuthenticators(namespace string) JWTAuthenticatorInterface
|
||||
}
|
||||
|
||||
// JWTAuthenticatorInterface has methods to work with JWTAuthenticator resources.
|
||||
type JWTAuthenticatorInterface interface {
|
||||
Create(*v1alpha1.JWTAuthenticator) (*v1alpha1.JWTAuthenticator, error)
|
||||
Update(*v1alpha1.JWTAuthenticator) (*v1alpha1.JWTAuthenticator, error)
|
||||
UpdateStatus(*v1alpha1.JWTAuthenticator) (*v1alpha1.JWTAuthenticator, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.JWTAuthenticatorList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error)
|
||||
JWTAuthenticatorExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticators implements JWTAuthenticatorInterface
|
||||
type jWTAuthenticators struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newJWTAuthenticators returns a JWTAuthenticators
|
||||
func newJWTAuthenticators(c *AuthenticationV1alpha1Client, namespace string) *jWTAuthenticators {
|
||||
return &jWTAuthenticators{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the jWTAuthenticator, and returns the corresponding jWTAuthenticator object, and an error if there is any.
|
||||
func (c *jWTAuthenticators) Get(name string, options v1.GetOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of JWTAuthenticators that match those selectors.
|
||||
func (c *jWTAuthenticators) List(opts v1.ListOptions) (result *v1alpha1.JWTAuthenticatorList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha1.JWTAuthenticatorList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested jWTAuthenticators.
|
||||
func (c *jWTAuthenticators) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a jWTAuthenticator and creates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *jWTAuthenticators) Create(jWTAuthenticator *v1alpha1.JWTAuthenticator) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Body(jWTAuthenticator).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a jWTAuthenticator and updates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *jWTAuthenticators) Update(jWTAuthenticator *v1alpha1.JWTAuthenticator) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(jWTAuthenticator.Name).
|
||||
Body(jWTAuthenticator).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *jWTAuthenticators) UpdateStatus(jWTAuthenticator *v1alpha1.JWTAuthenticator) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(jWTAuthenticator.Name).
|
||||
SubResource("status").
|
||||
Body(jWTAuthenticator).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the jWTAuthenticator and deletes it. Returns an error if one occurs.
|
||||
func (c *jWTAuthenticators) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *jWTAuthenticators) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched jWTAuthenticator.
|
||||
func (c *jWTAuthenticators) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
@ -11,6 +11,8 @@ import (
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// JWTAuthenticators returns a JWTAuthenticatorInformer.
|
||||
JWTAuthenticators() JWTAuthenticatorInformer
|
||||
// WebhookAuthenticators returns a WebhookAuthenticatorInformer.
|
||||
WebhookAuthenticators() WebhookAuthenticatorInformer
|
||||
}
|
||||
@ -26,6 +28,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// JWTAuthenticators returns a JWTAuthenticatorInformer.
|
||||
func (v *version) JWTAuthenticators() JWTAuthenticatorInformer {
|
||||
return &jWTAuthenticatorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// WebhookAuthenticators returns a WebhookAuthenticatorInformer.
|
||||
func (v *version) WebhookAuthenticators() WebhookAuthenticatorInformer {
|
||||
return &webhookAuthenticatorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
|
@ -0,0 +1,76 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
authenticationv1alpha1 "go.pinniped.dev/generated/1.17/apis/concierge/authentication/v1alpha1"
|
||||
versioned "go.pinniped.dev/generated/1.17/client/concierge/clientset/versioned"
|
||||
internalinterfaces "go.pinniped.dev/generated/1.17/client/concierge/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "go.pinniped.dev/generated/1.17/client/concierge/listers/authentication/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorInformer provides access to a shared informer and lister for
|
||||
// JWTAuthenticators.
|
||||
type JWTAuthenticatorInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.JWTAuthenticatorLister
|
||||
}
|
||||
|
||||
type jWTAuthenticatorInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewJWTAuthenticatorInformer constructs a new informer for JWTAuthenticator type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewJWTAuthenticatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredJWTAuthenticatorInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredJWTAuthenticatorInformer constructs a new informer for JWTAuthenticator type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredJWTAuthenticatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.AuthenticationV1alpha1().JWTAuthenticators(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.AuthenticationV1alpha1().JWTAuthenticators(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&authenticationv1alpha1.JWTAuthenticator{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredJWTAuthenticatorInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&authenticationv1alpha1.JWTAuthenticator{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) Lister() v1alpha1.JWTAuthenticatorLister {
|
||||
return v1alpha1.NewJWTAuthenticatorLister(f.Informer().GetIndexer())
|
||||
}
|
@ -42,6 +42,8 @@ func (f *genericInformer) Lister() cache.GenericLister {
|
||||
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
|
||||
switch resource {
|
||||
// Group=authentication.concierge.pinniped.dev, Version=v1alpha1
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("jwtauthenticators"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Authentication().V1alpha1().JWTAuthenticators().Informer()}, nil
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("webhookauthenticators"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Authentication().V1alpha1().WebhookAuthenticators().Informer()}, nil
|
||||
|
||||
|
@ -5,6 +5,14 @@
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// JWTAuthenticatorListerExpansion allows custom methods to be added to
|
||||
// JWTAuthenticatorLister.
|
||||
type JWTAuthenticatorListerExpansion interface{}
|
||||
|
||||
// JWTAuthenticatorNamespaceListerExpansion allows custom methods to be added to
|
||||
// JWTAuthenticatorNamespaceLister.
|
||||
type JWTAuthenticatorNamespaceListerExpansion interface{}
|
||||
|
||||
// WebhookAuthenticatorListerExpansion allows custom methods to be added to
|
||||
// WebhookAuthenticatorLister.
|
||||
type WebhookAuthenticatorListerExpansion interface{}
|
||||
|
81
generated/1.17/client/concierge/listers/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
81
generated/1.17/client/concierge/listers/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "go.pinniped.dev/generated/1.17/apis/concierge/authentication/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorLister helps list JWTAuthenticators.
|
||||
type JWTAuthenticatorLister interface {
|
||||
// List lists all JWTAuthenticators in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error)
|
||||
// JWTAuthenticators returns an object that can list and get JWTAuthenticators.
|
||||
JWTAuthenticators(namespace string) JWTAuthenticatorNamespaceLister
|
||||
JWTAuthenticatorListerExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticatorLister implements the JWTAuthenticatorLister interface.
|
||||
type jWTAuthenticatorLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewJWTAuthenticatorLister returns a new JWTAuthenticatorLister.
|
||||
func NewJWTAuthenticatorLister(indexer cache.Indexer) JWTAuthenticatorLister {
|
||||
return &jWTAuthenticatorLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all JWTAuthenticators in the indexer.
|
||||
func (s *jWTAuthenticatorLister) List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.JWTAuthenticator))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// JWTAuthenticators returns an object that can list and get JWTAuthenticators.
|
||||
func (s *jWTAuthenticatorLister) JWTAuthenticators(namespace string) JWTAuthenticatorNamespaceLister {
|
||||
return jWTAuthenticatorNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// JWTAuthenticatorNamespaceLister helps list and get JWTAuthenticators.
|
||||
type JWTAuthenticatorNamespaceLister interface {
|
||||
// List lists all JWTAuthenticators in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error)
|
||||
// Get retrieves the JWTAuthenticator from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.JWTAuthenticator, error)
|
||||
JWTAuthenticatorNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticatorNamespaceLister implements the JWTAuthenticatorNamespaceLister
|
||||
// interface.
|
||||
type jWTAuthenticatorNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all JWTAuthenticators in the indexer for a given namespace.
|
||||
func (s jWTAuthenticatorNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.JWTAuthenticator))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the JWTAuthenticator from the indexer for a given namespace and name.
|
||||
func (s jWTAuthenticatorNamespaceLister) Get(name string) (*v1alpha1.JWTAuthenticator, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("jwtauthenticator"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), nil
|
||||
}
|
155
generated/1.17/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml
generated
Normal file
155
generated/1.17/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml
generated
Normal file
@ -0,0 +1,155 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.4.0
|
||||
creationTimestamp: null
|
||||
name: jwtauthenticators.authentication.concierge.pinniped.dev
|
||||
spec:
|
||||
group: authentication.concierge.pinniped.dev
|
||||
names:
|
||||
categories:
|
||||
- pinniped
|
||||
- pinniped-authenticator
|
||||
- pinniped-authenticators
|
||||
kind: JWTAuthenticator
|
||||
listKind: JWTAuthenticatorList
|
||||
plural: jwtauthenticators
|
||||
singular: jwtauthenticator
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.issuer
|
||||
name: Issuer
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
\n Upon receiving a signed JWT, a JWTAuthenticator will performs some validation
|
||||
on it (e.g., valid signature, existence of claims, etc.) and extract the
|
||||
username and groups from the token."
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
issuer:
|
||||
description: Issuer is the OIDC issuer URL that will be used to discover
|
||||
public signing keys. Issuer is also used to validate the "iss" JWT
|
||||
claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
If omitted, a default set of system roots will be trusted.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
state.
|
||||
items:
|
||||
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||
type added in Kubernetes 1.19). In a future API version we can
|
||||
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
83
generated/1.18/README.adoc
generated
83
generated/1.18/README.adoc
generated
@ -22,10 +22,11 @@ Package v1alpha1 is the v1alpha1 version of the Pinniped concierge authenticatio
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-condition"]
|
||||
==== Condition
|
||||
|
||||
Condition status of a resource (mirrored from the metav1.Condition type added in Kubernetes 1.19). In a future API version we can switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-webhookauthenticatorstatus[$$WebhookAuthenticatorStatus$$]
|
||||
****
|
||||
|
||||
@ -41,13 +42,85 @@ Condition status of a resource (mirrored from the metav1.Condition type added in
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-tlsspec"]
|
||||
==== TLSSpec
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-conditionstatus"]
|
||||
==== ConditionStatus (string)
|
||||
|
||||
|
||||
Configuration for configuring TLS on various authenticators.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-condition[$$Condition$$]
|
||||
****
|
||||
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
Upon receiving a signed JWT, a JWTAuthenticator will performs some validation on it (e.g., valid signature, existence of claims, etc.) and extract the username and groups from the token.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticatorlist[$$JWTAuthenticatorList$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator.
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticator[$$JWTAuthenticator$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is also used to validate the "iss" JWT claim.
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider.
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticator[$$JWTAuthenticator$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-condition[$$Condition$$] array__ | Represents the observations of the authenticator's current state.
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-tlsspec"]
|
||||
==== TLSSpec
|
||||
|
||||
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-webhookauthenticatorspec[$$WebhookAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
@ -111,7 +184,7 @@ Status of a webhook authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-condition[$$Condition$$]__ | Represents the observations of the authenticator's current state.
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-authentication-v1alpha1-condition[$$Condition$$] array__ | Represents the observations of the authenticator's current state.
|
||||
|===
|
||||
|
||||
|
||||
|
@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&WebhookAuthenticator{},
|
||||
&WebhookAuthenticatorList{},
|
||||
&JWTAuthenticator{},
|
||||
&JWTAuthenticatorList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
|
62
generated/1.18/apis/concierge/authentication/v1alpha1/types_jwt.go
generated
Normal file
62
generated/1.18/apis/concierge/authentication/v1alpha1/types_jwt.go
generated
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
// +patchStrategy=merge
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
//
|
||||
// Upon receiving a signed JWT, a JWTAuthenticator will performs some validation on it (e.g., valid
|
||||
// signature, existence of claims, etc.) and extract the username and groups from the token.
|
||||
//
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +kubebuilder:resource:categories=pinniped;pinniped-authenticator;pinniped-authenticators
|
||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||
type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []JWTAuthenticator `json:"items"`
|
||||
}
|
@ -28,6 +28,111 @@ func (in *Condition) DeepCopy() *Condition {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticator.
|
||||
func (in *JWTAuthenticator) DeepCopy() *JWTAuthenticator {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticator)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JWTAuthenticator) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorList) DeepCopyInto(out *JWTAuthenticatorList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]JWTAuthenticator, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorList.
|
||||
func (in *JWTAuthenticatorList) DeepCopy() *JWTAuthenticatorList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorSpec.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopy() *JWTAuthenticatorSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorStatus) DeepCopyInto(out *JWTAuthenticatorStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorStatus.
|
||||
func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSSpec) DeepCopyInto(out *TLSSpec) {
|
||||
*out = *in
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
type AuthenticationV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
JWTAuthenticatorsGetter
|
||||
WebhookAuthenticatorsGetter
|
||||
}
|
||||
|
||||
@ -21,6 +22,10 @@ type AuthenticationV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *AuthenticationV1alpha1Client) JWTAuthenticators(namespace string) JWTAuthenticatorInterface {
|
||||
return newJWTAuthenticators(c, namespace)
|
||||
}
|
||||
|
||||
func (c *AuthenticationV1alpha1Client) WebhookAuthenticators(namespace string) WebhookAuthenticatorInterface {
|
||||
return newWebhookAuthenticators(c, namespace)
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ type FakeAuthenticationV1alpha1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeAuthenticationV1alpha1) JWTAuthenticators(namespace string) v1alpha1.JWTAuthenticatorInterface {
|
||||
return &FakeJWTAuthenticators{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeAuthenticationV1alpha1) WebhookAuthenticators(namespace string) v1alpha1.WebhookAuthenticatorInterface {
|
||||
return &FakeWebhookAuthenticators{c, namespace}
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1alpha1 "go.pinniped.dev/generated/1.18/apis/concierge/authentication/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeJWTAuthenticators implements JWTAuthenticatorInterface
|
||||
type FakeJWTAuthenticators struct {
|
||||
Fake *FakeAuthenticationV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var jwtauthenticatorsResource = schema.GroupVersionResource{Group: "authentication.concierge.pinniped.dev", Version: "v1alpha1", Resource: "jwtauthenticators"}
|
||||
|
||||
var jwtauthenticatorsKind = schema.GroupVersionKind{Group: "authentication.concierge.pinniped.dev", Version: "v1alpha1", Kind: "JWTAuthenticator"}
|
||||
|
||||
// Get takes name of the jWTAuthenticator, and returns the corresponding jWTAuthenticator object, and an error if there is any.
|
||||
func (c *FakeJWTAuthenticators) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(jwtauthenticatorsResource, c.ns, name), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of JWTAuthenticators that match those selectors.
|
||||
func (c *FakeJWTAuthenticators) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.JWTAuthenticatorList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(jwtauthenticatorsResource, jwtauthenticatorsKind, c.ns, opts), &v1alpha1.JWTAuthenticatorList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.JWTAuthenticatorList{ListMeta: obj.(*v1alpha1.JWTAuthenticatorList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.JWTAuthenticatorList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested jWTAuthenticators.
|
||||
func (c *FakeJWTAuthenticators) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(jwtauthenticatorsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a jWTAuthenticator and creates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *FakeJWTAuthenticators) Create(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.CreateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(jwtauthenticatorsResource, c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a jWTAuthenticator and updates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *FakeJWTAuthenticators) Update(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(jwtauthenticatorsResource, c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeJWTAuthenticators) UpdateStatus(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (*v1alpha1.JWTAuthenticator, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(jwtauthenticatorsResource, "status", c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// Delete takes name of the jWTAuthenticator and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeJWTAuthenticators) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(jwtauthenticatorsResource, c.ns, name), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeJWTAuthenticators) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(jwtauthenticatorsResource, c.ns, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.JWTAuthenticatorList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched jWTAuthenticator.
|
||||
func (c *FakeJWTAuthenticators) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(jwtauthenticatorsResource, c.ns, name, pt, data, subresources...), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
@ -5,4 +5,6 @@
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type JWTAuthenticatorExpansion interface{}
|
||||
|
||||
type WebhookAuthenticatorExpansion interface{}
|
||||
|
182
generated/1.18/client/concierge/clientset/versioned/typed/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
182
generated/1.18/client/concierge/clientset/versioned/typed/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
@ -0,0 +1,182 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1alpha1 "go.pinniped.dev/generated/1.18/apis/concierge/authentication/v1alpha1"
|
||||
scheme "go.pinniped.dev/generated/1.18/client/concierge/clientset/versioned/scheme"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorsGetter has a method to return a JWTAuthenticatorInterface.
|
||||
// A group's client should implement this interface.
|
||||
type JWTAuthenticatorsGetter interface {
|
||||
JWTAuthenticators(namespace string) JWTAuthenticatorInterface
|
||||
}
|
||||
|
||||
// JWTAuthenticatorInterface has methods to work with JWTAuthenticator resources.
|
||||
type JWTAuthenticatorInterface interface {
|
||||
Create(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.CreateOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
Update(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
UpdateStatus(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.JWTAuthenticatorList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error)
|
||||
JWTAuthenticatorExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticators implements JWTAuthenticatorInterface
|
||||
type jWTAuthenticators struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newJWTAuthenticators returns a JWTAuthenticators
|
||||
func newJWTAuthenticators(c *AuthenticationV1alpha1Client, namespace string) *jWTAuthenticators {
|
||||
return &jWTAuthenticators{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the jWTAuthenticator, and returns the corresponding jWTAuthenticator object, and an error if there is any.
|
||||
func (c *jWTAuthenticators) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of JWTAuthenticators that match those selectors.
|
||||
func (c *jWTAuthenticators) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.JWTAuthenticatorList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha1.JWTAuthenticatorList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested jWTAuthenticators.
|
||||
func (c *jWTAuthenticators) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a jWTAuthenticator and creates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *jWTAuthenticators) Create(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.CreateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(jWTAuthenticator).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a jWTAuthenticator and updates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *jWTAuthenticators) Update(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(jWTAuthenticator.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(jWTAuthenticator).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *jWTAuthenticators) UpdateStatus(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(jWTAuthenticator.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(jWTAuthenticator).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the jWTAuthenticator and deletes it. Returns an error if one occurs.
|
||||
func (c *jWTAuthenticators) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *jWTAuthenticators) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched jWTAuthenticator.
|
||||
func (c *jWTAuthenticators) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
@ -11,6 +11,8 @@ import (
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// JWTAuthenticators returns a JWTAuthenticatorInformer.
|
||||
JWTAuthenticators() JWTAuthenticatorInformer
|
||||
// WebhookAuthenticators returns a WebhookAuthenticatorInformer.
|
||||
WebhookAuthenticators() WebhookAuthenticatorInformer
|
||||
}
|
||||
@ -26,6 +28,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// JWTAuthenticators returns a JWTAuthenticatorInformer.
|
||||
func (v *version) JWTAuthenticators() JWTAuthenticatorInformer {
|
||||
return &jWTAuthenticatorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// WebhookAuthenticators returns a WebhookAuthenticatorInformer.
|
||||
func (v *version) WebhookAuthenticators() WebhookAuthenticatorInformer {
|
||||
return &webhookAuthenticatorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
|
@ -0,0 +1,77 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
time "time"
|
||||
|
||||
authenticationv1alpha1 "go.pinniped.dev/generated/1.18/apis/concierge/authentication/v1alpha1"
|
||||
versioned "go.pinniped.dev/generated/1.18/client/concierge/clientset/versioned"
|
||||
internalinterfaces "go.pinniped.dev/generated/1.18/client/concierge/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "go.pinniped.dev/generated/1.18/client/concierge/listers/authentication/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorInformer provides access to a shared informer and lister for
|
||||
// JWTAuthenticators.
|
||||
type JWTAuthenticatorInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.JWTAuthenticatorLister
|
||||
}
|
||||
|
||||
type jWTAuthenticatorInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewJWTAuthenticatorInformer constructs a new informer for JWTAuthenticator type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewJWTAuthenticatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredJWTAuthenticatorInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredJWTAuthenticatorInformer constructs a new informer for JWTAuthenticator type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredJWTAuthenticatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.AuthenticationV1alpha1().JWTAuthenticators(namespace).List(context.TODO(), options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.AuthenticationV1alpha1().JWTAuthenticators(namespace).Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&authenticationv1alpha1.JWTAuthenticator{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredJWTAuthenticatorInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&authenticationv1alpha1.JWTAuthenticator{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) Lister() v1alpha1.JWTAuthenticatorLister {
|
||||
return v1alpha1.NewJWTAuthenticatorLister(f.Informer().GetIndexer())
|
||||
}
|
@ -42,6 +42,8 @@ func (f *genericInformer) Lister() cache.GenericLister {
|
||||
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
|
||||
switch resource {
|
||||
// Group=authentication.concierge.pinniped.dev, Version=v1alpha1
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("jwtauthenticators"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Authentication().V1alpha1().JWTAuthenticators().Informer()}, nil
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("webhookauthenticators"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Authentication().V1alpha1().WebhookAuthenticators().Informer()}, nil
|
||||
|
||||
|
@ -5,6 +5,14 @@
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// JWTAuthenticatorListerExpansion allows custom methods to be added to
|
||||
// JWTAuthenticatorLister.
|
||||
type JWTAuthenticatorListerExpansion interface{}
|
||||
|
||||
// JWTAuthenticatorNamespaceListerExpansion allows custom methods to be added to
|
||||
// JWTAuthenticatorNamespaceLister.
|
||||
type JWTAuthenticatorNamespaceListerExpansion interface{}
|
||||
|
||||
// WebhookAuthenticatorListerExpansion allows custom methods to be added to
|
||||
// WebhookAuthenticatorLister.
|
||||
type WebhookAuthenticatorListerExpansion interface{}
|
||||
|
81
generated/1.18/client/concierge/listers/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
81
generated/1.18/client/concierge/listers/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "go.pinniped.dev/generated/1.18/apis/concierge/authentication/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorLister helps list JWTAuthenticators.
|
||||
type JWTAuthenticatorLister interface {
|
||||
// List lists all JWTAuthenticators in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error)
|
||||
// JWTAuthenticators returns an object that can list and get JWTAuthenticators.
|
||||
JWTAuthenticators(namespace string) JWTAuthenticatorNamespaceLister
|
||||
JWTAuthenticatorListerExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticatorLister implements the JWTAuthenticatorLister interface.
|
||||
type jWTAuthenticatorLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewJWTAuthenticatorLister returns a new JWTAuthenticatorLister.
|
||||
func NewJWTAuthenticatorLister(indexer cache.Indexer) JWTAuthenticatorLister {
|
||||
return &jWTAuthenticatorLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all JWTAuthenticators in the indexer.
|
||||
func (s *jWTAuthenticatorLister) List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.JWTAuthenticator))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// JWTAuthenticators returns an object that can list and get JWTAuthenticators.
|
||||
func (s *jWTAuthenticatorLister) JWTAuthenticators(namespace string) JWTAuthenticatorNamespaceLister {
|
||||
return jWTAuthenticatorNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// JWTAuthenticatorNamespaceLister helps list and get JWTAuthenticators.
|
||||
type JWTAuthenticatorNamespaceLister interface {
|
||||
// List lists all JWTAuthenticators in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error)
|
||||
// Get retrieves the JWTAuthenticator from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.JWTAuthenticator, error)
|
||||
JWTAuthenticatorNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticatorNamespaceLister implements the JWTAuthenticatorNamespaceLister
|
||||
// interface.
|
||||
type jWTAuthenticatorNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all JWTAuthenticators in the indexer for a given namespace.
|
||||
func (s jWTAuthenticatorNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.JWTAuthenticator))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the JWTAuthenticator from the indexer for a given namespace and name.
|
||||
func (s jWTAuthenticatorNamespaceLister) Get(name string) (*v1alpha1.JWTAuthenticator, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("jwtauthenticator"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), nil
|
||||
}
|
155
generated/1.18/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml
generated
Normal file
155
generated/1.18/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml
generated
Normal file
@ -0,0 +1,155 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.4.0
|
||||
creationTimestamp: null
|
||||
name: jwtauthenticators.authentication.concierge.pinniped.dev
|
||||
spec:
|
||||
group: authentication.concierge.pinniped.dev
|
||||
names:
|
||||
categories:
|
||||
- pinniped
|
||||
- pinniped-authenticator
|
||||
- pinniped-authenticators
|
||||
kind: JWTAuthenticator
|
||||
listKind: JWTAuthenticatorList
|
||||
plural: jwtauthenticators
|
||||
singular: jwtauthenticator
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.issuer
|
||||
name: Issuer
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
\n Upon receiving a signed JWT, a JWTAuthenticator will performs some validation
|
||||
on it (e.g., valid signature, existence of claims, etc.) and extract the
|
||||
username and groups from the token."
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
issuer:
|
||||
description: Issuer is the OIDC issuer URL that will be used to discover
|
||||
public signing keys. Issuer is also used to validate the "iss" JWT
|
||||
claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
If omitted, a default set of system roots will be trusted.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
state.
|
||||
items:
|
||||
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||
type added in Kubernetes 1.19). In a future API version we can
|
||||
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
83
generated/1.19/README.adoc
generated
83
generated/1.19/README.adoc
generated
@ -22,10 +22,11 @@ Package v1alpha1 is the v1alpha1 version of the Pinniped concierge authenticatio
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-condition"]
|
||||
==== Condition
|
||||
|
||||
Condition status of a resource (mirrored from the metav1.Condition type added in Kubernetes 1.19). In a future API version we can switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-webhookauthenticatorstatus[$$WebhookAuthenticatorStatus$$]
|
||||
****
|
||||
|
||||
@ -41,13 +42,85 @@ Condition status of a resource (mirrored from the metav1.Condition type added in
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-tlsspec"]
|
||||
==== TLSSpec
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-conditionstatus"]
|
||||
==== ConditionStatus (string)
|
||||
|
||||
|
||||
Configuration for configuring TLS on various authenticators.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-condition[$$Condition$$]
|
||||
****
|
||||
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
Upon receiving a signed JWT, a JWTAuthenticator will performs some validation on it (e.g., valid signature, existence of claims, etc.) and extract the username and groups from the token.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticatorlist[$$JWTAuthenticatorList$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator.
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticator[$$JWTAuthenticator$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is also used to validate the "iss" JWT claim.
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider.
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticator[$$JWTAuthenticator$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-condition[$$Condition$$] array__ | Represents the observations of the authenticator's current state.
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-tlsspec"]
|
||||
==== TLSSpec
|
||||
|
||||
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-webhookauthenticatorspec[$$WebhookAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
@ -111,7 +184,7 @@ Status of a webhook authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-condition[$$Condition$$]__ | Represents the observations of the authenticator's current state.
|
||||
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-condition[$$Condition$$] array__ | Represents the observations of the authenticator's current state.
|
||||
|===
|
||||
|
||||
|
||||
|
@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&WebhookAuthenticator{},
|
||||
&WebhookAuthenticatorList{},
|
||||
&JWTAuthenticator{},
|
||||
&JWTAuthenticatorList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
|
62
generated/1.19/apis/concierge/authentication/v1alpha1/types_jwt.go
generated
Normal file
62
generated/1.19/apis/concierge/authentication/v1alpha1/types_jwt.go
generated
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
// +patchStrategy=merge
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
//
|
||||
// Upon receiving a signed JWT, a JWTAuthenticator will performs some validation on it (e.g., valid
|
||||
// signature, existence of claims, etc.) and extract the username and groups from the token.
|
||||
//
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +kubebuilder:resource:categories=pinniped;pinniped-authenticator;pinniped-authenticators
|
||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||
type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []JWTAuthenticator `json:"items"`
|
||||
}
|
@ -28,6 +28,111 @@ func (in *Condition) DeepCopy() *Condition {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticator.
|
||||
func (in *JWTAuthenticator) DeepCopy() *JWTAuthenticator {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticator)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JWTAuthenticator) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorList) DeepCopyInto(out *JWTAuthenticatorList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]JWTAuthenticator, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorList.
|
||||
func (in *JWTAuthenticatorList) DeepCopy() *JWTAuthenticatorList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorSpec.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopy() *JWTAuthenticatorSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorStatus) DeepCopyInto(out *JWTAuthenticatorStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTAuthenticatorStatus.
|
||||
func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JWTAuthenticatorStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSSpec) DeepCopyInto(out *TLSSpec) {
|
||||
*out = *in
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
type AuthenticationV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
JWTAuthenticatorsGetter
|
||||
WebhookAuthenticatorsGetter
|
||||
}
|
||||
|
||||
@ -21,6 +22,10 @@ type AuthenticationV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *AuthenticationV1alpha1Client) JWTAuthenticators(namespace string) JWTAuthenticatorInterface {
|
||||
return newJWTAuthenticators(c, namespace)
|
||||
}
|
||||
|
||||
func (c *AuthenticationV1alpha1Client) WebhookAuthenticators(namespace string) WebhookAuthenticatorInterface {
|
||||
return newWebhookAuthenticators(c, namespace)
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ type FakeAuthenticationV1alpha1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeAuthenticationV1alpha1) JWTAuthenticators(namespace string) v1alpha1.JWTAuthenticatorInterface {
|
||||
return &FakeJWTAuthenticators{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeAuthenticationV1alpha1) WebhookAuthenticators(namespace string) v1alpha1.WebhookAuthenticatorInterface {
|
||||
return &FakeWebhookAuthenticators{c, namespace}
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeJWTAuthenticators implements JWTAuthenticatorInterface
|
||||
type FakeJWTAuthenticators struct {
|
||||
Fake *FakeAuthenticationV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var jwtauthenticatorsResource = schema.GroupVersionResource{Group: "authentication.concierge.pinniped.dev", Version: "v1alpha1", Resource: "jwtauthenticators"}
|
||||
|
||||
var jwtauthenticatorsKind = schema.GroupVersionKind{Group: "authentication.concierge.pinniped.dev", Version: "v1alpha1", Kind: "JWTAuthenticator"}
|
||||
|
||||
// Get takes name of the jWTAuthenticator, and returns the corresponding jWTAuthenticator object, and an error if there is any.
|
||||
func (c *FakeJWTAuthenticators) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(jwtauthenticatorsResource, c.ns, name), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of JWTAuthenticators that match those selectors.
|
||||
func (c *FakeJWTAuthenticators) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.JWTAuthenticatorList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(jwtauthenticatorsResource, jwtauthenticatorsKind, c.ns, opts), &v1alpha1.JWTAuthenticatorList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.JWTAuthenticatorList{ListMeta: obj.(*v1alpha1.JWTAuthenticatorList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.JWTAuthenticatorList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested jWTAuthenticators.
|
||||
func (c *FakeJWTAuthenticators) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(jwtauthenticatorsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a jWTAuthenticator and creates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *FakeJWTAuthenticators) Create(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.CreateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(jwtauthenticatorsResource, c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a jWTAuthenticator and updates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *FakeJWTAuthenticators) Update(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(jwtauthenticatorsResource, c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeJWTAuthenticators) UpdateStatus(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (*v1alpha1.JWTAuthenticator, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(jwtauthenticatorsResource, "status", c.ns, jWTAuthenticator), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
||||
|
||||
// Delete takes name of the jWTAuthenticator and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeJWTAuthenticators) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(jwtauthenticatorsResource, c.ns, name), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeJWTAuthenticators) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(jwtauthenticatorsResource, c.ns, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.JWTAuthenticatorList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched jWTAuthenticator.
|
||||
func (c *FakeJWTAuthenticators) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(jwtauthenticatorsResource, c.ns, name, pt, data, subresources...), &v1alpha1.JWTAuthenticator{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), err
|
||||
}
|
@ -5,4 +5,6 @@
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type JWTAuthenticatorExpansion interface{}
|
||||
|
||||
type WebhookAuthenticatorExpansion interface{}
|
||||
|
182
generated/1.19/client/concierge/clientset/versioned/typed/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
182
generated/1.19/client/concierge/clientset/versioned/typed/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
@ -0,0 +1,182 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
scheme "go.pinniped.dev/generated/1.19/client/concierge/clientset/versioned/scheme"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorsGetter has a method to return a JWTAuthenticatorInterface.
|
||||
// A group's client should implement this interface.
|
||||
type JWTAuthenticatorsGetter interface {
|
||||
JWTAuthenticators(namespace string) JWTAuthenticatorInterface
|
||||
}
|
||||
|
||||
// JWTAuthenticatorInterface has methods to work with JWTAuthenticator resources.
|
||||
type JWTAuthenticatorInterface interface {
|
||||
Create(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.CreateOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
Update(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
UpdateStatus(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.JWTAuthenticator, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.JWTAuthenticatorList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error)
|
||||
JWTAuthenticatorExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticators implements JWTAuthenticatorInterface
|
||||
type jWTAuthenticators struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newJWTAuthenticators returns a JWTAuthenticators
|
||||
func newJWTAuthenticators(c *AuthenticationV1alpha1Client, namespace string) *jWTAuthenticators {
|
||||
return &jWTAuthenticators{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the jWTAuthenticator, and returns the corresponding jWTAuthenticator object, and an error if there is any.
|
||||
func (c *jWTAuthenticators) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of JWTAuthenticators that match those selectors.
|
||||
func (c *jWTAuthenticators) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.JWTAuthenticatorList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha1.JWTAuthenticatorList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested jWTAuthenticators.
|
||||
func (c *jWTAuthenticators) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a jWTAuthenticator and creates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *jWTAuthenticators) Create(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.CreateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(jWTAuthenticator).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a jWTAuthenticator and updates it. Returns the server's representation of the jWTAuthenticator, and an error, if there is any.
|
||||
func (c *jWTAuthenticators) Update(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(jWTAuthenticator.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(jWTAuthenticator).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *jWTAuthenticators) UpdateStatus(ctx context.Context, jWTAuthenticator *v1alpha1.JWTAuthenticator, opts v1.UpdateOptions) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(jWTAuthenticator.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(jWTAuthenticator).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the jWTAuthenticator and deletes it. Returns an error if one occurs.
|
||||
func (c *jWTAuthenticators) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *jWTAuthenticators) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched jWTAuthenticator.
|
||||
func (c *jWTAuthenticators) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JWTAuthenticator, err error) {
|
||||
result = &v1alpha1.JWTAuthenticator{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("jwtauthenticators").
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
@ -11,6 +11,8 @@ import (
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// JWTAuthenticators returns a JWTAuthenticatorInformer.
|
||||
JWTAuthenticators() JWTAuthenticatorInformer
|
||||
// WebhookAuthenticators returns a WebhookAuthenticatorInformer.
|
||||
WebhookAuthenticators() WebhookAuthenticatorInformer
|
||||
}
|
||||
@ -26,6 +28,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// JWTAuthenticators returns a JWTAuthenticatorInformer.
|
||||
func (v *version) JWTAuthenticators() JWTAuthenticatorInformer {
|
||||
return &jWTAuthenticatorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// WebhookAuthenticators returns a WebhookAuthenticatorInformer.
|
||||
func (v *version) WebhookAuthenticators() WebhookAuthenticatorInformer {
|
||||
return &webhookAuthenticatorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
|
@ -0,0 +1,77 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
time "time"
|
||||
|
||||
authenticationv1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
versioned "go.pinniped.dev/generated/1.19/client/concierge/clientset/versioned"
|
||||
internalinterfaces "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "go.pinniped.dev/generated/1.19/client/concierge/listers/authentication/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorInformer provides access to a shared informer and lister for
|
||||
// JWTAuthenticators.
|
||||
type JWTAuthenticatorInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.JWTAuthenticatorLister
|
||||
}
|
||||
|
||||
type jWTAuthenticatorInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewJWTAuthenticatorInformer constructs a new informer for JWTAuthenticator type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewJWTAuthenticatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredJWTAuthenticatorInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredJWTAuthenticatorInformer constructs a new informer for JWTAuthenticator type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredJWTAuthenticatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.AuthenticationV1alpha1().JWTAuthenticators(namespace).List(context.TODO(), options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.AuthenticationV1alpha1().JWTAuthenticators(namespace).Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&authenticationv1alpha1.JWTAuthenticator{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredJWTAuthenticatorInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&authenticationv1alpha1.JWTAuthenticator{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *jWTAuthenticatorInformer) Lister() v1alpha1.JWTAuthenticatorLister {
|
||||
return v1alpha1.NewJWTAuthenticatorLister(f.Informer().GetIndexer())
|
||||
}
|
@ -42,6 +42,8 @@ func (f *genericInformer) Lister() cache.GenericLister {
|
||||
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
|
||||
switch resource {
|
||||
// Group=authentication.concierge.pinniped.dev, Version=v1alpha1
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("jwtauthenticators"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Authentication().V1alpha1().JWTAuthenticators().Informer()}, nil
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("webhookauthenticators"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Authentication().V1alpha1().WebhookAuthenticators().Informer()}, nil
|
||||
|
||||
|
@ -5,6 +5,14 @@
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// JWTAuthenticatorListerExpansion allows custom methods to be added to
|
||||
// JWTAuthenticatorLister.
|
||||
type JWTAuthenticatorListerExpansion interface{}
|
||||
|
||||
// JWTAuthenticatorNamespaceListerExpansion allows custom methods to be added to
|
||||
// JWTAuthenticatorNamespaceLister.
|
||||
type JWTAuthenticatorNamespaceListerExpansion interface{}
|
||||
|
||||
// WebhookAuthenticatorListerExpansion allows custom methods to be added to
|
||||
// WebhookAuthenticatorLister.
|
||||
type WebhookAuthenticatorListerExpansion interface{}
|
||||
|
86
generated/1.19/client/concierge/listers/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
86
generated/1.19/client/concierge/listers/authentication/v1alpha1/jwtauthenticator.go
generated
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// JWTAuthenticatorLister helps list JWTAuthenticators.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type JWTAuthenticatorLister interface {
|
||||
// List lists all JWTAuthenticators in the indexer.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error)
|
||||
// JWTAuthenticators returns an object that can list and get JWTAuthenticators.
|
||||
JWTAuthenticators(namespace string) JWTAuthenticatorNamespaceLister
|
||||
JWTAuthenticatorListerExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticatorLister implements the JWTAuthenticatorLister interface.
|
||||
type jWTAuthenticatorLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewJWTAuthenticatorLister returns a new JWTAuthenticatorLister.
|
||||
func NewJWTAuthenticatorLister(indexer cache.Indexer) JWTAuthenticatorLister {
|
||||
return &jWTAuthenticatorLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all JWTAuthenticators in the indexer.
|
||||
func (s *jWTAuthenticatorLister) List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.JWTAuthenticator))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// JWTAuthenticators returns an object that can list and get JWTAuthenticators.
|
||||
func (s *jWTAuthenticatorLister) JWTAuthenticators(namespace string) JWTAuthenticatorNamespaceLister {
|
||||
return jWTAuthenticatorNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// JWTAuthenticatorNamespaceLister helps list and get JWTAuthenticators.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type JWTAuthenticatorNamespaceLister interface {
|
||||
// List lists all JWTAuthenticators in the indexer for a given namespace.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error)
|
||||
// Get retrieves the JWTAuthenticator from the indexer for a given namespace and name.
|
||||
// Objects returned here must be treated as read-only.
|
||||
Get(name string) (*v1alpha1.JWTAuthenticator, error)
|
||||
JWTAuthenticatorNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// jWTAuthenticatorNamespaceLister implements the JWTAuthenticatorNamespaceLister
|
||||
// interface.
|
||||
type jWTAuthenticatorNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all JWTAuthenticators in the indexer for a given namespace.
|
||||
func (s jWTAuthenticatorNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.JWTAuthenticator, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.JWTAuthenticator))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the JWTAuthenticator from the indexer for a given namespace and name.
|
||||
func (s jWTAuthenticatorNamespaceLister) Get(name string) (*v1alpha1.JWTAuthenticator, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("jwtauthenticator"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.JWTAuthenticator), nil
|
||||
}
|
155
generated/1.19/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml
generated
Normal file
155
generated/1.19/crds/authentication.concierge.pinniped.dev_jwtauthenticators.yaml
generated
Normal file
@ -0,0 +1,155 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.4.0
|
||||
creationTimestamp: null
|
||||
name: jwtauthenticators.authentication.concierge.pinniped.dev
|
||||
spec:
|
||||
group: authentication.concierge.pinniped.dev
|
||||
names:
|
||||
categories:
|
||||
- pinniped
|
||||
- pinniped-authenticator
|
||||
- pinniped-authenticators
|
||||
kind: JWTAuthenticator
|
||||
listKind: JWTAuthenticatorList
|
||||
plural: jwtauthenticators
|
||||
singular: jwtauthenticator
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.issuer
|
||||
name: Issuer
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
\n Upon receiving a signed JWT, a JWTAuthenticator will performs some validation
|
||||
on it (e.g., valid signature, existence of claims, etc.) and extract the
|
||||
username and groups from the token."
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
issuer:
|
||||
description: Issuer is the OIDC issuer URL that will be used to discover
|
||||
public signing keys. Issuer is also used to validate the "iss" JWT
|
||||
claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
If omitted, a default set of system roots will be trusted.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
state.
|
||||
items:
|
||||
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||
type added in Kubernetes 1.19). In a future API version we can
|
||||
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
29
internal/controller/authenticator/authenticator.go
Normal file
29
internal/controller/authenticator/authenticator.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package authenticator contains helper code for dealing with *Authenticator CRDs.
|
||||
package authenticator
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
)
|
||||
|
||||
// Closer is a type that can be closed idempotently.
|
||||
//
|
||||
// This type is slightly different from io.Closer, because io.Closer can return an error and is not
|
||||
// necessarily idempotent.
|
||||
type Closer interface {
|
||||
Close()
|
||||
}
|
||||
|
||||
// CABundle returns a PEM-encoded CA bundle from the provided spec. If the provided spec is nil, a
|
||||
// nil CA bundle will be returned. If the provided spec contains a CA bundle that is not properly
|
||||
// encoded, an error will be returned.
|
||||
func CABundle(spec *auth1alpha1.TLSSpec) ([]byte, error) {
|
||||
if spec == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return base64.StdEncoding.DecodeString(spec.CertificateAuthorityData)
|
||||
}
|
@ -12,8 +12,10 @@ import (
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
loginapi "go.pinniped.dev/generated/1.19/apis/concierge/login"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -93,6 +95,12 @@ func (c *Cache) AuthenticateTokenCredentialRequest(ctx context.Context, req *log
|
||||
|
||||
val := c.Get(key)
|
||||
if val == nil {
|
||||
plog.Debug(
|
||||
"authenticator does not exist",
|
||||
"authenticator", klog.KRef(key.Namespace, key.Name),
|
||||
"kind", key.Kind,
|
||||
"apiGroup", key.APIGroup,
|
||||
)
|
||||
return nil, ErrNoSuchAuthenticator
|
||||
}
|
||||
|
||||
|
114
internal/controller/authenticator/cachecleaner/cachecleaner.go
Normal file
114
internal/controller/authenticator/cachecleaner/cachecleaner.go
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package cachecleaner implements a controller for garbage collecting authenticators from an authenticator cache.
|
||||
package cachecleaner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
authinformers "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions/authentication/v1alpha1"
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
"go.pinniped.dev/internal/controller/authenticator"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
)
|
||||
|
||||
// New instantiates a new controllerlib.Controller which will garbage collect authenticators from the provided Cache.
|
||||
func New(
|
||||
cache *authncache.Cache,
|
||||
webhooks authinformers.WebhookAuthenticatorInformer,
|
||||
jwtAuthenticators authinformers.JWTAuthenticatorInformer,
|
||||
log logr.Logger,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: "cachecleaner-controller",
|
||||
Syncer: &controller{
|
||||
cache: cache,
|
||||
webhooks: webhooks,
|
||||
jwtAuthenticators: jwtAuthenticators,
|
||||
log: log.WithName("cachecleaner-controller"),
|
||||
},
|
||||
},
|
||||
controllerlib.WithInformer(
|
||||
webhooks,
|
||||
pinnipedcontroller.MatchAnythingFilter(pinnipedcontroller.SingletonQueue()),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
controllerlib.WithInformer(
|
||||
jwtAuthenticators,
|
||||
pinnipedcontroller.MatchAnythingFilter(pinnipedcontroller.SingletonQueue()),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
cache *authncache.Cache
|
||||
webhooks authinformers.WebhookAuthenticatorInformer
|
||||
jwtAuthenticators authinformers.JWTAuthenticatorInformer
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
func (c *controller) Sync(_ controllerlib.Context) error {
|
||||
webhooks, err := c.webhooks.Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list WebhookAuthenticators: %w", err)
|
||||
}
|
||||
|
||||
jwtAuthenticators, err := c.jwtAuthenticators.Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list JWTAuthenticators: %w", err)
|
||||
}
|
||||
|
||||
// Index the current authenticators by cache key.
|
||||
authenticatorSet := map[authncache.Key]bool{}
|
||||
for _, webhook := range webhooks {
|
||||
key := authncache.Key{
|
||||
Namespace: webhook.Namespace,
|
||||
Name: webhook.Name,
|
||||
Kind: "WebhookAuthenticator",
|
||||
APIGroup: auth1alpha1.SchemeGroupVersion.Group,
|
||||
}
|
||||
authenticatorSet[key] = true
|
||||
}
|
||||
for _, jwtAuthenticator := range jwtAuthenticators {
|
||||
key := authncache.Key{
|
||||
Namespace: jwtAuthenticator.Namespace,
|
||||
Name: jwtAuthenticator.Name,
|
||||
Kind: "JWTAuthenticator",
|
||||
APIGroup: auth1alpha1.SchemeGroupVersion.Group,
|
||||
}
|
||||
authenticatorSet[key] = true
|
||||
}
|
||||
|
||||
// Delete any entries from the cache which are no longer in the cluster.
|
||||
for _, key := range c.cache.Keys() {
|
||||
if key.APIGroup != auth1alpha1.SchemeGroupVersion.Group || (key.Kind != "WebhookAuthenticator" && key.Kind != "JWTAuthenticator") {
|
||||
continue
|
||||
}
|
||||
if _, exists := authenticatorSet[key]; !exists {
|
||||
c.log.WithValues(
|
||||
"authenticator",
|
||||
klog.KRef(key.Namespace, key.Name),
|
||||
"kind",
|
||||
key.Kind,
|
||||
).Info("deleting authenticator from cache")
|
||||
|
||||
value := c.cache.Get(key)
|
||||
if closer, ok := value.(authenticator.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
|
||||
c.cache.Delete(key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cachecleaner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
authv1alpha "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
pinnipedfake "go.pinniped.dev/generated/1.19/client/concierge/clientset/versioned/fake"
|
||||
pinnipedinformers "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/mocks/mocktokenauthenticatorcloser"
|
||||
"go.pinniped.dev/internal/testutil/testlogger"
|
||||
)
|
||||
|
||||
func TestController(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testWebhookKey1 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "WebhookAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-webhook-name-one",
|
||||
}
|
||||
testWebhookKey2 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "WebhookAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-webhook-name-two",
|
||||
}
|
||||
testJWTAuthenticatorKey1 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "JWTAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-jwt-authenticator-name-one",
|
||||
}
|
||||
testJWTAuthenticatorKey2 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "JWTAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-jwt-authenticator-name-two",
|
||||
}
|
||||
testKeyUnknownType := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "SomeOtherAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-one",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
objects []runtime.Object
|
||||
initialCache func(t *testing.T, cache *authncache.Cache)
|
||||
wantErr string
|
||||
wantLogs []string
|
||||
wantCacheKeys []authncache.Key
|
||||
}{
|
||||
{
|
||||
name: "no change",
|
||||
initialCache: func(t *testing.T, cache *authncache.Cache) {
|
||||
cache.Store(testWebhookKey1, nil)
|
||||
cache.Store(testJWTAuthenticatorKey1, nil)
|
||||
},
|
||||
objects: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testWebhookKey1.Namespace,
|
||||
Name: testWebhookKey1.Name,
|
||||
},
|
||||
},
|
||||
&authv1alpha.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testJWTAuthenticatorKey1.Namespace,
|
||||
Name: testJWTAuthenticatorKey1.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCacheKeys: []authncache.Key{testWebhookKey1, testJWTAuthenticatorKey1},
|
||||
},
|
||||
{
|
||||
name: "authenticators not yet added",
|
||||
objects: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testWebhookKey1.Namespace,
|
||||
Name: testWebhookKey1.Name,
|
||||
},
|
||||
},
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testWebhookKey2.Namespace,
|
||||
Name: testWebhookKey2.Name,
|
||||
},
|
||||
},
|
||||
&authv1alpha.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testJWTAuthenticatorKey1.Namespace,
|
||||
Name: testJWTAuthenticatorKey1.Name,
|
||||
},
|
||||
},
|
||||
&authv1alpha.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testJWTAuthenticatorKey2.Namespace,
|
||||
Name: testJWTAuthenticatorKey2.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCacheKeys: []authncache.Key{},
|
||||
},
|
||||
{
|
||||
name: "successful cleanup",
|
||||
initialCache: func(t *testing.T, cache *authncache.Cache) {
|
||||
cache.Store(testWebhookKey1, nil)
|
||||
cache.Store(testWebhookKey2, nil)
|
||||
cache.Store(testJWTAuthenticatorKey1, newClosableCacheValue(t, 0))
|
||||
cache.Store(testJWTAuthenticatorKey2, newClosableCacheValue(t, 1))
|
||||
cache.Store(testKeyUnknownType, nil)
|
||||
},
|
||||
objects: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testWebhookKey1.Namespace,
|
||||
Name: testWebhookKey1.Name,
|
||||
},
|
||||
},
|
||||
&authv1alpha.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testJWTAuthenticatorKey1.Namespace,
|
||||
Name: testJWTAuthenticatorKey1.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`cachecleaner-controller "level"=0 "msg"="deleting authenticator from cache" "authenticator"={"name":"test-jwt-authenticator-name-two","namespace":"test-namespace"} "kind"="JWTAuthenticator"`,
|
||||
`cachecleaner-controller "level"=0 "msg"="deleting authenticator from cache" "authenticator"={"name":"test-webhook-name-two","namespace":"test-namespace"} "kind"="WebhookAuthenticator"`,
|
||||
},
|
||||
wantCacheKeys: []authncache.Key{testWebhookKey1, testJWTAuthenticatorKey1, testKeyUnknownType},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// When we have t.Parallel() here, this test blocks pretty consistently...y tho?
|
||||
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.objects...)
|
||||
informers := pinnipedinformers.NewSharedInformerFactory(fakeClient, 0)
|
||||
cache := authncache.New()
|
||||
if tt.initialCache != nil {
|
||||
tt.initialCache(t, cache)
|
||||
}
|
||||
testLog := testlogger.New(t)
|
||||
|
||||
webhooks := informers.Authentication().V1alpha1().WebhookAuthenticators()
|
||||
jwtAuthenticators := informers.Authentication().V1alpha1().JWTAuthenticators()
|
||||
controller := New(cache, webhooks, jwtAuthenticators, testLog)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
informers.Start(ctx.Done())
|
||||
informers.WaitForCacheSync(ctx.Done())
|
||||
controllerlib.TestRunSynchronously(t, controller)
|
||||
|
||||
syncCtx := controllerlib.Context{
|
||||
Context: ctx,
|
||||
Key: controllerlib.Key{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-webhook-name-one",
|
||||
},
|
||||
}
|
||||
|
||||
if err := controllerlib.TestSync(t, controller, syncCtx); tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.ElementsMatch(t, tt.wantLogs, testLog.Lines())
|
||||
require.ElementsMatch(t, tt.wantCacheKeys, cache.Keys())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newClosableCacheValue(t *testing.T, wantCloses int) authncache.Value {
|
||||
ctrl := gomock.NewController(t)
|
||||
t.Cleanup(ctrl.Finish)
|
||||
tac := mocktokenauthenticatorcloser.NewMockTokenAuthenticatorCloser(ctrl)
|
||||
tac.EXPECT().Close().Times(wantCloses)
|
||||
return tac
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package jwtcachefiller implements a controller for filling an authncache.Cache with each
|
||||
// added/updated JWTAuthenticator.
|
||||
package jwtcachefiller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
authinformers "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions/authentication/v1alpha1"
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
pinnipedauthenticator "go.pinniped.dev/internal/controller/authenticator"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
)
|
||||
|
||||
// These default values come from the way that the Supervisor issues and signs tokens. We make these
|
||||
// the defaults for a JWTAuthenticator so that they can easily integrate with the Supervisor.
|
||||
const (
|
||||
defaultUsernameClaim = "sub"
|
||||
defaultGroupsClaim = "groups"
|
||||
)
|
||||
|
||||
// defaultSupportedSigningAlgos returns the default signing algos that this JWTAuthenticator
|
||||
// supports (i.e., if none are supplied by the user).
|
||||
func defaultSupportedSigningAlgos() []string {
|
||||
return []string{
|
||||
// RS256 is recommended by the OIDC spec and required, in some capacity. Since we want the
|
||||
// JWTAuthenticator to be able to support many OIDC ID tokens out of the box, we include this
|
||||
// algorithm by default.
|
||||
string(jose.RS256),
|
||||
// ES256 is what the Supervisor does, by default. We want integration with the JWTAuthenticator
|
||||
// to be as seamless as possible, so we include this algorithm by default.
|
||||
string(jose.ES256),
|
||||
}
|
||||
}
|
||||
|
||||
type tokenAuthenticatorCloser interface {
|
||||
authenticator.Token
|
||||
pinnipedauthenticator.Closer
|
||||
}
|
||||
|
||||
type jwtAuthenticator struct {
|
||||
tokenAuthenticatorCloser
|
||||
spec *auth1alpha1.JWTAuthenticatorSpec
|
||||
}
|
||||
|
||||
// New instantiates a new controllerlib.Controller which will populate the provided authncache.Cache.
|
||||
func New(
|
||||
cache *authncache.Cache,
|
||||
jwtAuthenticators authinformers.JWTAuthenticatorInformer,
|
||||
log logr.Logger,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: "jwtcachefiller-controller",
|
||||
Syncer: &controller{
|
||||
cache: cache,
|
||||
jwtAuthenticators: jwtAuthenticators,
|
||||
log: log.WithName("jwtcachefiller-controller"),
|
||||
},
|
||||
},
|
||||
controllerlib.WithInformer(
|
||||
jwtAuthenticators,
|
||||
pinnipedcontroller.MatchAnythingFilter(nil), // nil parent func is fine because each event is distinct
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
cache *authncache.Cache
|
||||
jwtAuthenticators authinformers.JWTAuthenticatorInformer
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
func (c *controller) Sync(ctx controllerlib.Context) error {
|
||||
obj, err := c.jwtAuthenticators.Lister().JWTAuthenticators(ctx.Key.Namespace).Get(ctx.Key.Name)
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
c.log.Info("Sync() found that the JWTAuthenticator does not exist yet or was deleted")
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get JWTAuthenticator %s/%s: %w", ctx.Key.Namespace, ctx.Key.Name, err)
|
||||
}
|
||||
|
||||
cacheKey := authncache.Key{
|
||||
APIGroup: auth1alpha1.GroupName,
|
||||
Kind: "JWTAuthenticator",
|
||||
Namespace: ctx.Key.Namespace,
|
||||
Name: ctx.Key.Name,
|
||||
}
|
||||
|
||||
// If this authenticator already exists, then only recreate it if is different from the desired
|
||||
// authenticator. We don't want to be creating a new authenticator for every resync period.
|
||||
//
|
||||
// If we do need to recreate the authenticator, then make sure we close the old one to avoid
|
||||
// goroutine leaks.
|
||||
if value := c.cache.Get(cacheKey); value != nil {
|
||||
jwtAuthenticator := c.extractValueAsJWTAuthenticator(value)
|
||||
if jwtAuthenticator != nil {
|
||||
if reflect.DeepEqual(jwtAuthenticator.spec, &obj.Spec) {
|
||||
c.log.WithValues("jwtAuthenticator", klog.KObj(obj), "issuer", obj.Spec.Issuer).Info("actual jwt authenticator and desired jwt authenticator are the same")
|
||||
return nil
|
||||
}
|
||||
jwtAuthenticator.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Make a deep copy of the spec so we aren't storing pointers to something that the informer cache
|
||||
// may mutate!
|
||||
jwtAuthenticator, err := newJWTAuthenticator(obj.Spec.DeepCopy())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build jwt authenticator: %w", err)
|
||||
}
|
||||
|
||||
c.cache.Store(cacheKey, jwtAuthenticator)
|
||||
c.log.WithValues("jwtAuthenticator", klog.KObj(obj), "issuer", obj.Spec.Issuer).Info("added new jwt authenticator")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) extractValueAsJWTAuthenticator(value authncache.Value) *jwtAuthenticator {
|
||||
jwtAuthenticator, ok := value.(*jwtAuthenticator)
|
||||
if !ok {
|
||||
actualType := "<nil>"
|
||||
if t := reflect.TypeOf(value); t != nil {
|
||||
actualType = t.String()
|
||||
}
|
||||
c.log.WithValues("actualType", actualType).Info("wrong JWT authenticator type in cache")
|
||||
return nil
|
||||
}
|
||||
return jwtAuthenticator
|
||||
}
|
||||
|
||||
// newJWTAuthenticator creates a jwt authenticator from the provided spec.
|
||||
func newJWTAuthenticator(spec *auth1alpha1.JWTAuthenticatorSpec) (*jwtAuthenticator, error) {
|
||||
caBundle, err := pinnipedauthenticator.CABundle(spec.TLS)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid TLS configuration: %w", err)
|
||||
}
|
||||
|
||||
var caFile string
|
||||
if caBundle != nil {
|
||||
temp, err := ioutil.TempFile("", "pinniped-jwkauthenticator-cafile-*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create temporary file: %w", err)
|
||||
}
|
||||
|
||||
// We can safely remove the temp file at the end of this function since oidc.New() reads the
|
||||
// provided CA file and then forgets about it.
|
||||
defer func() { _ = os.Remove(temp.Name()) }()
|
||||
|
||||
if _, err := temp.Write(caBundle); err != nil {
|
||||
return nil, fmt.Errorf("cannot write CA file: %w", err)
|
||||
}
|
||||
|
||||
caFile = temp.Name()
|
||||
}
|
||||
|
||||
authenticator, err := oidc.New(oidc.Options{
|
||||
IssuerURL: spec.Issuer,
|
||||
ClientID: spec.Audience,
|
||||
UsernameClaim: defaultUsernameClaim,
|
||||
GroupsClaim: defaultGroupsClaim,
|
||||
SupportedSigningAlgs: defaultSupportedSigningAlgos(),
|
||||
CAFile: caFile,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not initialize authenticator: %w", err)
|
||||
}
|
||||
|
||||
return &jwtAuthenticator{
|
||||
tokenAuthenticatorCloser: authenticator,
|
||||
spec: spec,
|
||||
}, nil
|
||||
}
|
@ -0,0 +1,557 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package jwtcachefiller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
pinnipedfake "go.pinniped.dev/generated/1.19/client/concierge/clientset/versioned/fake"
|
||||
pinnipedinformers "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/mocks/mocktokenauthenticatorcloser"
|
||||
"go.pinniped.dev/internal/testutil/testlogger"
|
||||
)
|
||||
|
||||
func TestController(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
someJWTAuthenticatorSpec := &auth1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: "https://some-issuer.com",
|
||||
Audience: "some-audience",
|
||||
TLS: &auth1alpha1.TLSSpec{CertificateAuthorityData: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVVENDQWptZ0F3SUJBZ0lWQUpzNStTbVRtaTJXeUI0bGJJRXBXaUs5a1RkUE1BMEdDU3FHU0liM0RRRUIKQ3dVQU1COHhDekFKQmdOVkJBWVRBbFZUTVJBd0RnWURWUVFLREFkUWFYWnZkR0ZzTUI0WERUSXdNRFV3TkRFMgpNamMxT0ZvWERUSTBNRFV3TlRFMk1qYzFPRm93SHpFTE1Ba0dBMVVFQmhNQ1ZWTXhFREFPQmdOVkJBb01CMUJwCmRtOTBZV3d3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRERZWmZvWGR4Z2NXTEMKZEJtbHB5a0tBaG9JMlBuUWtsVFNXMno1cGcwaXJjOGFRL1E3MXZzMTRZYStmdWtFTGlvOTRZYWw4R01DdVFrbApMZ3AvUEE5N1VYelhQNDBpK25iNXcwRGpwWWd2dU9KQXJXMno2MFRnWE5NSFh3VHk4ME1SZEhpUFVWZ0VZd0JpCmtkNThzdEFVS1Y1MnBQTU1reTJjNy9BcFhJNmRXR2xjalUvaFBsNmtpRzZ5dEw2REtGYjJQRWV3MmdJM3pHZ2IKOFVVbnA1V05DZDd2WjNVY0ZHNXlsZEd3aGc3cnZ4U1ZLWi9WOEhCMGJmbjlxamlrSVcxWFM4dzdpUUNlQmdQMApYZWhKZmVITlZJaTJtZlczNlVQbWpMdnVKaGpqNDIrdFBQWndvdDkzdWtlcEgvbWpHcFJEVm9wamJyWGlpTUYrCkYxdnlPNGMxQWdNQkFBR2pnWU13Z1lBd0hRWURWUjBPQkJZRUZNTWJpSXFhdVkwajRVWWphWDl0bDJzby9LQ1IKTUI4R0ExVWRJd1FZTUJhQUZNTWJpSXFhdVkwajRVWWphWDl0bDJzby9LQ1JNQjBHQTFVZEpRUVdNQlFHQ0NzRwpBUVVGQndNQ0JnZ3JCZ0VGQlFjREFUQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BNEdBMVVkRHdFQi93UUVBd0lCCkJqQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFYbEh4M2tIMDZwY2NDTDlEVE5qTnBCYnlVSytGd2R6T2IwWFYKcmpNaGtxdHVmdEpUUnR5T3hKZ0ZKNXhUR3pCdEtKamcrVU1pczBOV0t0VDBNWThVMU45U2c5SDl0RFpHRHBjVQpxMlVRU0Y4dXRQMVR3dnJIUzIrdzB2MUoxdHgrTEFiU0lmWmJCV0xXQ21EODUzRlVoWlFZekkvYXpFM28vd0p1CmlPUklMdUpNUk5vNlBXY3VLZmRFVkhaS1RTWnk3a25FcHNidGtsN3EwRE91eUFWdG9HVnlkb3VUR0FOdFhXK2YKczNUSTJjKzErZXg3L2RZOEJGQTFzNWFUOG5vZnU3T1RTTzdiS1kzSkRBUHZOeFQzKzVZUXJwNGR1Nmh0YUFMbAppOHNaRkhidmxpd2EzdlhxL3p1Y2JEaHEzQzBhZnAzV2ZwRGxwSlpvLy9QUUFKaTZLQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"},
|
||||
}
|
||||
otherJWTAuthenticatorSpec := &auth1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: "https://some-other-issuer.com",
|
||||
Audience: "some-audience",
|
||||
TLS: &auth1alpha1.TLSSpec{CertificateAuthorityData: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVVENDQWptZ0F3SUJBZ0lWQUpzNStTbVRtaTJXeUI0bGJJRXBXaUs5a1RkUE1BMEdDU3FHU0liM0RRRUIKQ3dVQU1COHhDekFKQmdOVkJBWVRBbFZUTVJBd0RnWURWUVFLREFkUWFYWnZkR0ZzTUI0WERUSXdNRFV3TkRFMgpNamMxT0ZvWERUSTBNRFV3TlRFMk1qYzFPRm93SHpFTE1Ba0dBMVVFQmhNQ1ZWTXhFREFPQmdOVkJBb01CMUJwCmRtOTBZV3d3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRERZWmZvWGR4Z2NXTEMKZEJtbHB5a0tBaG9JMlBuUWtsVFNXMno1cGcwaXJjOGFRL1E3MXZzMTRZYStmdWtFTGlvOTRZYWw4R01DdVFrbApMZ3AvUEE5N1VYelhQNDBpK25iNXcwRGpwWWd2dU9KQXJXMno2MFRnWE5NSFh3VHk4ME1SZEhpUFVWZ0VZd0JpCmtkNThzdEFVS1Y1MnBQTU1reTJjNy9BcFhJNmRXR2xjalUvaFBsNmtpRzZ5dEw2REtGYjJQRWV3MmdJM3pHZ2IKOFVVbnA1V05DZDd2WjNVY0ZHNXlsZEd3aGc3cnZ4U1ZLWi9WOEhCMGJmbjlxamlrSVcxWFM4dzdpUUNlQmdQMApYZWhKZmVITlZJaTJtZlczNlVQbWpMdnVKaGpqNDIrdFBQWndvdDkzdWtlcEgvbWpHcFJEVm9wamJyWGlpTUYrCkYxdnlPNGMxQWdNQkFBR2pnWU13Z1lBd0hRWURWUjBPQkJZRUZNTWJpSXFhdVkwajRVWWphWDl0bDJzby9LQ1IKTUI4R0ExVWRJd1FZTUJhQUZNTWJpSXFhdVkwajRVWWphWDl0bDJzby9LQ1JNQjBHQTFVZEpRUVdNQlFHQ0NzRwpBUVVGQndNQ0JnZ3JCZ0VGQlFjREFUQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BNEdBMVVkRHdFQi93UUVBd0lCCkJqQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFYbEh4M2tIMDZwY2NDTDlEVE5qTnBCYnlVSytGd2R6T2IwWFYKcmpNaGtxdHVmdEpUUnR5T3hKZ0ZKNXhUR3pCdEtKamcrVU1pczBOV0t0VDBNWThVMU45U2c5SDl0RFpHRHBjVQpxMlVRU0Y4dXRQMVR3dnJIUzIrdzB2MUoxdHgrTEFiU0lmWmJCV0xXQ21EODUzRlVoWlFZekkvYXpFM28vd0p1CmlPUklMdUpNUk5vNlBXY3VLZmRFVkhaS1RTWnk3a25FcHNidGtsN3EwRE91eUFWdG9HVnlkb3VUR0FOdFhXK2YKczNUSTJjKzErZXg3L2RZOEJGQTFzNWFUOG5vZnU3T1RTTzdiS1kzSkRBUHZOeFQzKzVZUXJwNGR1Nmh0YUFMbAppOHNaRkhidmxpd2EzdlhxL3p1Y2JEaHEzQzBhZnAzV2ZwRGxwSlpvLy9QUUFKaTZLQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"},
|
||||
}
|
||||
missingTLSJWTAuthenticatorSpec := &auth1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: "https://some-issuer.com",
|
||||
Audience: "some-audience",
|
||||
}
|
||||
invalidTLSJWTAuthenticatorSpec := &auth1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: "https://some-other-issuer.com",
|
||||
Audience: "some-audience",
|
||||
TLS: &auth1alpha1.TLSSpec{CertificateAuthorityData: "invalid base64-encoded data"},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cache func(*testing.T, *authncache.Cache, bool)
|
||||
wantClose bool
|
||||
syncKey controllerlib.Key
|
||||
jwtAuthenticators []runtime.Object
|
||||
wantErr string
|
||||
wantLogs []string
|
||||
wantCacheEntries int
|
||||
}{
|
||||
{
|
||||
name: "not found",
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
wantLogs: []string{
|
||||
`jwtcachefiller-controller "level"=0 "msg"="Sync() found that the JWTAuthenticator does not exist yet or was deleted"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid jwt authenticator with CA",
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&auth1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`jwtcachefiller-controller "level"=0 "msg"="added new jwt authenticator" "issuer"="https://some-issuer.com" "jwtAuthenticator"={"name":"test-name","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheEntries: 1,
|
||||
},
|
||||
{
|
||||
name: "updating jwt authenticator with new fields closes previous instance",
|
||||
cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) {
|
||||
cache.Store(
|
||||
authncache.Key{
|
||||
Name: "test-name",
|
||||
Namespace: "test-namespace",
|
||||
Kind: "JWTAuthenticator",
|
||||
APIGroup: auth1alpha1.SchemeGroupVersion.Group,
|
||||
},
|
||||
newCacheValue(t, *otherJWTAuthenticatorSpec, wantClose),
|
||||
)
|
||||
},
|
||||
wantClose: true,
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&auth1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`jwtcachefiller-controller "level"=0 "msg"="added new jwt authenticator" "issuer"="https://some-issuer.com" "jwtAuthenticator"={"name":"test-name","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheEntries: 1,
|
||||
},
|
||||
{
|
||||
name: "updating jwt authenticator with the same value does nothing",
|
||||
cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) {
|
||||
cache.Store(
|
||||
authncache.Key{
|
||||
Name: "test-name",
|
||||
Namespace: "test-namespace",
|
||||
Kind: "JWTAuthenticator",
|
||||
APIGroup: auth1alpha1.SchemeGroupVersion.Group,
|
||||
},
|
||||
newCacheValue(t, *someJWTAuthenticatorSpec, wantClose),
|
||||
)
|
||||
},
|
||||
wantClose: false,
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&auth1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`jwtcachefiller-controller "level"=0 "msg"="actual jwt authenticator and desired jwt authenticator are the same" "issuer"="https://some-issuer.com" "jwtAuthenticator"={"name":"test-name","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheEntries: 1,
|
||||
},
|
||||
{
|
||||
name: "updating jwt authenticator when cache value is wrong type",
|
||||
cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) {
|
||||
cache.Store(
|
||||
authncache.Key{
|
||||
Name: "test-name",
|
||||
Namespace: "test-namespace",
|
||||
Kind: "JWTAuthenticator",
|
||||
APIGroup: auth1alpha1.SchemeGroupVersion.Group,
|
||||
},
|
||||
struct{ authenticator.Token }{},
|
||||
)
|
||||
},
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&auth1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`jwtcachefiller-controller "level"=0 "msg"="wrong JWT authenticator type in cache" "actualType"="struct { authenticator.Token }"`,
|
||||
`jwtcachefiller-controller "level"=0 "msg"="added new jwt authenticator" "issuer"="https://some-issuer.com" "jwtAuthenticator"={"name":"test-name","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheEntries: 1,
|
||||
},
|
||||
{
|
||||
name: "valid jwt authenticator without CA",
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&auth1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *missingTLSJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`jwtcachefiller-controller "level"=0 "msg"="added new jwt authenticator" "issuer"="https://some-issuer.com" "jwtAuthenticator"={"name":"test-name","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheEntries: 1,
|
||||
},
|
||||
{
|
||||
name: "invalid jwt authenticator CA",
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&auth1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidTLSJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantErr: "failed to build jwt authenticator: invalid TLS configuration: illegal base64 data at input byte 7",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.jwtAuthenticators...)
|
||||
informers := pinnipedinformers.NewSharedInformerFactory(fakeClient, 0)
|
||||
cache := authncache.New()
|
||||
testLog := testlogger.New(t)
|
||||
|
||||
if tt.cache != nil {
|
||||
tt.cache(t, cache, tt.wantClose)
|
||||
}
|
||||
|
||||
controller := New(cache, informers.Authentication().V1alpha1().JWTAuthenticators(), testLog)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
informers.Start(ctx.Done())
|
||||
controllerlib.TestRunSynchronously(t, controller)
|
||||
|
||||
syncCtx := controllerlib.Context{Context: ctx, Key: tt.syncKey}
|
||||
|
||||
if err := controllerlib.TestSync(t, controller, syncCtx); tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.Equal(t, tt.wantLogs, testLog.Lines())
|
||||
require.Equal(t, tt.wantCacheEntries, len(cache.Keys()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewJWTAuthenticator(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
goodSubject = "some-subject"
|
||||
goodAudience = "some-audience"
|
||||
group0 = "some-group-0"
|
||||
group1 = "some-group-1"
|
||||
|
||||
goodECSigningKeyID = "some-ec-key-id"
|
||||
goodRSASigningKeyID = "some-rsa-key-id"
|
||||
)
|
||||
|
||||
goodECSigningKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
goodECSigningAlgo := jose.ES256
|
||||
require.NoError(t, err)
|
||||
|
||||
goodRSASigningKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err)
|
||||
goodRSASigningAlgo := jose.RS256
|
||||
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewTLSServer(mux)
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
mux.Handle("/.well-known/openid-configuration", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, err := fmt.Fprintf(w, `{"issuer": "%s", "jwks_uri": "%s"}`, server.URL, server.URL+"/jwks.json")
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
mux.Handle("/jwks.json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ecJWK := jose.JSONWebKey{
|
||||
Key: goodECSigningKey,
|
||||
KeyID: goodECSigningKeyID,
|
||||
Algorithm: string(goodECSigningAlgo),
|
||||
Use: "sig",
|
||||
}
|
||||
rsaJWK := jose.JSONWebKey{
|
||||
Key: goodRSASigningKey,
|
||||
KeyID: goodRSASigningKeyID,
|
||||
Algorithm: string(goodRSASigningAlgo),
|
||||
Use: "sig",
|
||||
}
|
||||
jwks := jose.JSONWebKeySet{
|
||||
Keys: []jose.JSONWebKey{ecJWK.Public(), rsaJWK.Public()},
|
||||
}
|
||||
require.NoError(t, json.NewEncoder(w).Encode(jwks))
|
||||
}))
|
||||
|
||||
goodIssuer := server.URL
|
||||
a, err := newJWTAuthenticator(&auth1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: tlsSpecFromTLSConfig(server.TLS),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(a.Close)
|
||||
|
||||
// The implementation of AuthenticateToken() that we use waits 10 seconds after creation to
|
||||
// perform OIDC discovery. Therefore, the JWTAuthenticator is not functional for the first 10
|
||||
// seconds. We sleep for 13 seconds in this unit test to give a little bit of cushion to that 10
|
||||
// second delay.
|
||||
//
|
||||
// We should get rid of this 10 second delay. See
|
||||
// https://github.com/vmware-tanzu/pinniped/issues/260.
|
||||
if testing.Short() {
|
||||
t.Skip("skipping this test when '-short' flag is passed to avoid necessary 13 second sleep")
|
||||
}
|
||||
time.Sleep(time.Second * 13)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
jwtClaims func(wellKnownClaims *jwt.Claims, groups *interface{})
|
||||
jwtSignature func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string)
|
||||
wantResponse *authenticator.Response
|
||||
wantAuthenticated bool
|
||||
wantErrorRegexp string
|
||||
}{
|
||||
{
|
||||
name: "good token without groups and with EC signature",
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodSubject,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
},
|
||||
{
|
||||
name: "good token without groups and with RSA signature",
|
||||
jwtSignature: func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string) {
|
||||
*key = goodRSASigningKey
|
||||
*algo = goodRSASigningAlgo
|
||||
*kid = goodRSASigningKeyID
|
||||
},
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodSubject,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
},
|
||||
{
|
||||
name: "good token with groups as array",
|
||||
jwtClaims: func(_ *jwt.Claims, groups *interface{}) {
|
||||
*groups = []string{group0, group1}
|
||||
},
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodSubject,
|
||||
Groups: []string{group0, group1},
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
},
|
||||
{
|
||||
name: "good token with groups as string",
|
||||
jwtClaims: func(_ *jwt.Claims, groups *interface{}) {
|
||||
*groups = group0
|
||||
},
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodSubject,
|
||||
Groups: []string{group0},
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
},
|
||||
{
|
||||
name: "good token with nbf unset",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
||||
claims.NotBefore = nil
|
||||
},
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodSubject,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
},
|
||||
{
|
||||
name: "bad token with groups as map",
|
||||
jwtClaims: func(_ *jwt.Claims, groups *interface{}) {
|
||||
*groups = map[string]string{"not an array": "or a string"}
|
||||
},
|
||||
wantErrorRegexp: "oidc: parse groups claim \"groups\": json: cannot unmarshal object into Go value of type string",
|
||||
},
|
||||
{
|
||||
name: "bad token with wrong issuer",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
||||
claims.Issuer = "wrong-issuer"
|
||||
},
|
||||
wantResponse: nil,
|
||||
wantAuthenticated: false,
|
||||
},
|
||||
{
|
||||
name: "bad token with no audience",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
||||
claims.Audience = nil
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \[\]`,
|
||||
},
|
||||
{
|
||||
name: "bad token with wrong audience",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
||||
claims.Audience = []string{"wrong-audience"}
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \["wrong-audience"\]`,
|
||||
},
|
||||
{
|
||||
name: "bad token with nbf in the future",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
||||
claims.NotBefore = jwt.NewNumericDate(time.Date(3020, 2, 3, 4, 5, 6, 7, time.UTC))
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: current time .* before the nbf \(not before\) time: 3020-.*`,
|
||||
},
|
||||
{
|
||||
name: "bad token with exp in past",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
||||
claims.Expiry = jwt.NewNumericDate(time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC))
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: 0001-02-02 23:09:04 -0456 LMT\)`,
|
||||
},
|
||||
{
|
||||
name: "bad token without exp",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
||||
claims.Expiry = nil
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: 0001-01-01 00:00:00 \+0000 UTC\)`,
|
||||
},
|
||||
{
|
||||
name: "signing key is wrong",
|
||||
jwtSignature: func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string) {
|
||||
var err error
|
||||
*key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
require.NoError(t, err)
|
||||
*algo = jose.ES256
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: failed to verify signature: failed to verify id token signature`,
|
||||
},
|
||||
{
|
||||
name: "signing algo is unsupported",
|
||||
jwtSignature: func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string) {
|
||||
var err error
|
||||
*key, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
require.NoError(t, err)
|
||||
*algo = jose.ES384
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: id token signed with unsupported algorithm, expected \["RS256" "ES256"\] got "ES384"`,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
wellKnownClaims := jwt.Claims{
|
||||
Issuer: goodIssuer,
|
||||
Subject: goodSubject,
|
||||
Audience: []string{goodAudience},
|
||||
Expiry: jwt.NewNumericDate(time.Now().Add(time.Hour)),
|
||||
NotBefore: jwt.NewNumericDate(time.Now().Add(-time.Hour)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now().Add(-time.Hour)),
|
||||
}
|
||||
var groups interface{}
|
||||
if test.jwtClaims != nil {
|
||||
test.jwtClaims(&wellKnownClaims, &groups)
|
||||
}
|
||||
|
||||
var signingKey interface{} = goodECSigningKey
|
||||
signingAlgo := goodECSigningAlgo
|
||||
signingKID := goodECSigningKeyID
|
||||
if test.jwtSignature != nil {
|
||||
test.jwtSignature(&signingKey, &signingAlgo, &signingKID)
|
||||
}
|
||||
|
||||
jwt := createJWT(t, signingKey, signingAlgo, signingKID, &wellKnownClaims, groups)
|
||||
rsp, authenticated, err := a.AuthenticateToken(context.Background(), jwt)
|
||||
if test.wantErrorRegexp != "" {
|
||||
require.Error(t, err)
|
||||
require.Regexp(t, test.wantErrorRegexp, err.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.wantResponse, rsp)
|
||||
require.Equal(t, test.wantAuthenticated, authenticated)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func tlsSpecFromTLSConfig(tls *tls.Config) *auth1alpha1.TLSSpec {
|
||||
pemData := make([]byte, 0)
|
||||
for _, certificate := range tls.Certificates {
|
||||
for _, reallyCertificate := range certificate.Certificate {
|
||||
pemData = append(pemData, pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: reallyCertificate,
|
||||
})...)
|
||||
}
|
||||
}
|
||||
return &auth1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString(pemData),
|
||||
}
|
||||
}
|
||||
|
||||
func createJWT(
|
||||
t *testing.T,
|
||||
signingKey interface{},
|
||||
signingAlgo jose.SignatureAlgorithm,
|
||||
kid string,
|
||||
claims *jwt.Claims,
|
||||
groups interface{},
|
||||
) string {
|
||||
t.Helper()
|
||||
|
||||
sig, err := jose.NewSigner(
|
||||
jose.SigningKey{Algorithm: signingAlgo, Key: signingKey},
|
||||
(&jose.SignerOptions{}).WithType("JWT").WithHeader("kid", kid),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
builder := jwt.Signed(sig).Claims(claims)
|
||||
if groups != nil {
|
||||
builder = builder.Claims(map[string]interface{}{"groups": groups})
|
||||
}
|
||||
jwt, err := builder.CompactSerialize()
|
||||
require.NoError(t, err)
|
||||
|
||||
return jwt
|
||||
}
|
||||
|
||||
func newCacheValue(t *testing.T, spec auth1alpha1.JWTAuthenticatorSpec, wantClose bool) authncache.Value {
|
||||
ctrl := gomock.NewController(t)
|
||||
t.Cleanup(ctrl.Finish)
|
||||
tokenAuthenticatorCloser := mocktokenauthenticatorcloser.NewMockTokenAuthenticatorCloser(ctrl)
|
||||
|
||||
wantCloses := 0
|
||||
if wantClose {
|
||||
wantCloses++
|
||||
}
|
||||
tokenAuthenticatorCloser.EXPECT().Close().Times(wantCloses)
|
||||
|
||||
return &jwtAuthenticator{
|
||||
tokenAuthenticatorCloser: tokenAuthenticatorCloser,
|
||||
spec: &spec,
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package webhookcachecleaner implements a controller for garbage collecting webhook authenticators from an authenticator cache.
|
||||
package webhookcachecleaner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
authinformers "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions/authentication/v1alpha1"
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
)
|
||||
|
||||
// New instantiates a new controllerlib.Controller which will garbage collect webhooks from the provided Cache.
|
||||
func New(cache *authncache.Cache, webhooks authinformers.WebhookAuthenticatorInformer, log logr.Logger) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: "webhookcachecleaner-controller",
|
||||
Syncer: &controller{
|
||||
cache: cache,
|
||||
webhooks: webhooks,
|
||||
log: log.WithName("webhookcachecleaner-controller"),
|
||||
},
|
||||
},
|
||||
controllerlib.WithInformer(
|
||||
webhooks,
|
||||
pinnipedcontroller.MatchAnythingFilter(pinnipedcontroller.SingletonQueue()),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
cache *authncache.Cache
|
||||
webhooks authinformers.WebhookAuthenticatorInformer
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
func (c *controller) Sync(_ controllerlib.Context) error {
|
||||
webhooks, err := c.webhooks.Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list WebhookAuthenticators: %w", err)
|
||||
}
|
||||
|
||||
// Index the current webhooks by key.
|
||||
webhooksByKey := map[controllerlib.Key]*auth1alpha1.WebhookAuthenticator{}
|
||||
for _, webhook := range webhooks {
|
||||
key := controllerlib.Key{Namespace: webhook.Namespace, Name: webhook.Name}
|
||||
webhooksByKey[key] = webhook
|
||||
}
|
||||
|
||||
// Delete any entries from the cache which are no longer in the cluster.
|
||||
for _, key := range c.cache.Keys() {
|
||||
if key.APIGroup != auth1alpha1.SchemeGroupVersion.Group || key.Kind != "WebhookAuthenticator" {
|
||||
continue
|
||||
}
|
||||
if _, exists := webhooksByKey[controllerlib.Key{Namespace: key.Namespace, Name: key.Name}]; !exists {
|
||||
c.log.WithValues("webhook", klog.KRef(key.Namespace, key.Name)).Info("deleting webhook authenticator from cache")
|
||||
c.cache.Delete(key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package webhookcachecleaner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
authv1alpha "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
pinnipedfake "go.pinniped.dev/generated/1.19/client/concierge/clientset/versioned/fake"
|
||||
pinnipedinformers "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/testutil/testlogger"
|
||||
)
|
||||
|
||||
func TestController(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testKey1 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "WebhookAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-one",
|
||||
}
|
||||
testKey2 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "WebhookAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-two",
|
||||
}
|
||||
testKeyNonwebhook := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "SomeOtherAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-one",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
webhooks []runtime.Object
|
||||
initialCache map[authncache.Key]authncache.Value
|
||||
wantErr string
|
||||
wantLogs []string
|
||||
wantCacheKeys []authncache.Key
|
||||
}{
|
||||
{
|
||||
name: "no change",
|
||||
initialCache: map[authncache.Key]authncache.Value{testKey1: nil},
|
||||
webhooks: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testKey1.Namespace,
|
||||
Name: testKey1.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCacheKeys: []authncache.Key{testKey1},
|
||||
},
|
||||
{
|
||||
name: "authenticators not yet added",
|
||||
initialCache: nil,
|
||||
webhooks: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testKey1.Namespace,
|
||||
Name: testKey1.Name,
|
||||
},
|
||||
},
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testKey2.Namespace,
|
||||
Name: testKey2.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCacheKeys: []authncache.Key{},
|
||||
},
|
||||
{
|
||||
name: "successful cleanup",
|
||||
initialCache: map[authncache.Key]authncache.Value{
|
||||
testKey1: nil,
|
||||
testKey2: nil,
|
||||
testKeyNonwebhook: nil,
|
||||
},
|
||||
webhooks: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testKey1.Namespace,
|
||||
Name: testKey1.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`webhookcachecleaner-controller "level"=0 "msg"="deleting webhook authenticator from cache" "webhook"={"name":"test-name-two","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheKeys: []authncache.Key{testKey1, testKeyNonwebhook},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.webhooks...)
|
||||
informers := pinnipedinformers.NewSharedInformerFactory(fakeClient, 0)
|
||||
cache := authncache.New()
|
||||
for k, v := range tt.initialCache {
|
||||
cache.Store(k, v)
|
||||
}
|
||||
testLog := testlogger.New(t)
|
||||
|
||||
controller := New(cache, informers.Authentication().V1alpha1().WebhookAuthenticators(), testLog)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
informers.Start(ctx.Done())
|
||||
controllerlib.TestRunSynchronously(t, controller)
|
||||
|
||||
syncCtx := controllerlib.Context{
|
||||
Context: ctx,
|
||||
Key: controllerlib.Key{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-one",
|
||||
},
|
||||
}
|
||||
|
||||
if err := controllerlib.TestSync(t, controller, syncCtx); tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.Equal(t, tt.wantLogs, testLog.Lines())
|
||||
require.ElementsMatch(t, tt.wantCacheKeys, cache.Keys())
|
||||
})
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
package webhookcachefiller
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -23,6 +22,7 @@ import (
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
authinformers "go.pinniped.dev/generated/1.19/client/concierge/informers/externalversions/authentication/v1alpha1"
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
pinnipedauthenticator "go.pinniped.dev/internal/controller/authenticator"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
)
|
||||
@ -92,7 +92,7 @@ func newWebhookAuthenticator(
|
||||
defer func() { _ = os.Remove(temp.Name()) }()
|
||||
|
||||
cluster := &clientcmdapi.Cluster{Server: spec.Endpoint}
|
||||
cluster.CertificateAuthorityData, err = getCABundle(spec.TLS)
|
||||
cluster.CertificateAuthorityData, err = pinnipedauthenticator.CABundle(spec.TLS)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid TLS configuration: %w", err)
|
||||
}
|
||||
@ -121,10 +121,3 @@ func newWebhookAuthenticator(
|
||||
|
||||
return webhook.New(temp.Name(), version, implicitAuds, customDial)
|
||||
}
|
||||
|
||||
func getCABundle(spec *auth1alpha1.TLSSpec) ([]byte, error) {
|
||||
if spec == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return base64.StdEncoding.DecodeString(spec.CertificateAuthorityData)
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ import (
|
||||
"go.pinniped.dev/internal/config/concierge"
|
||||
"go.pinniped.dev/internal/controller/apicerts"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controller/authenticator/webhookcachecleaner"
|
||||
"go.pinniped.dev/internal/controller/authenticator/cachecleaner"
|
||||
"go.pinniped.dev/internal/controller/authenticator/jwtcachefiller"
|
||||
"go.pinniped.dev/internal/controller/authenticator/webhookcachefiller"
|
||||
"go.pinniped.dev/internal/controller/issuerconfig"
|
||||
"go.pinniped.dev/internal/controller/kubecertagent"
|
||||
@ -238,9 +239,18 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
|
||||
singletonWorker,
|
||||
).
|
||||
WithController(
|
||||
webhookcachecleaner.New(
|
||||
jwtcachefiller.New(
|
||||
c.AuthenticatorCache,
|
||||
informers.installationNamespacePinniped.Authentication().V1alpha1().JWTAuthenticators(),
|
||||
klogr.New(),
|
||||
),
|
||||
singletonWorker,
|
||||
).
|
||||
WithController(
|
||||
cachecleaner.New(
|
||||
c.AuthenticatorCache,
|
||||
informers.installationNamespacePinniped.Authentication().V1alpha1().WebhookAuthenticators(),
|
||||
informers.installationNamespacePinniped.Authentication().V1alpha1().JWTAuthenticators(),
|
||||
klogr.New(),
|
||||
),
|
||||
singletonWorker,
|
||||
|
21
internal/mocks/mocktokenauthenticatorcloser/generate.go
Normal file
21
internal/mocks/mocktokenauthenticatorcloser/generate.go
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mocktokenauthenticatorcloser
|
||||
|
||||
import (
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
|
||||
pinnipedauthenticator "go.pinniped.dev/internal/controller/authenticator"
|
||||
)
|
||||
|
||||
//go:generate go run -v github.com/golang/mock/mockgen -destination=mocktokenauthenticatorcloser.go -package=mocktokenauthenticatorcloser -copyright_file=../../../hack/header.txt . TokenAuthenticatorCloser
|
||||
|
||||
// TokenAuthenticatorCloser is a type that can authenticate tokens and be closed idempotently.
|
||||
//
|
||||
// This type is slightly different from io.Closer, because io.Closer can return an error and is not
|
||||
// necessarily idempotent.
|
||||
type TokenAuthenticatorCloser interface {
|
||||
authenticator.Token
|
||||
pinnipedauthenticator.Closer
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: go.pinniped.dev/internal/mocks/mocktokenauthenticatorcloser (interfaces: TokenAuthenticatorCloser)
|
||||
|
||||
// Package mocktokenauthenticatorcloser is a generated GoMock package.
|
||||
package mocktokenauthenticatorcloser
|
||||
|
||||
import (
|
||||
context "context"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
authenticator "k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockTokenAuthenticatorCloser is a mock of TokenAuthenticatorCloser interface
|
||||
type MockTokenAuthenticatorCloser struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTokenAuthenticatorCloserMockRecorder
|
||||
}
|
||||
|
||||
// MockTokenAuthenticatorCloserMockRecorder is the mock recorder for MockTokenAuthenticatorCloser
|
||||
type MockTokenAuthenticatorCloserMockRecorder struct {
|
||||
mock *MockTokenAuthenticatorCloser
|
||||
}
|
||||
|
||||
// NewMockTokenAuthenticatorCloser creates a new mock instance
|
||||
func NewMockTokenAuthenticatorCloser(ctrl *gomock.Controller) *MockTokenAuthenticatorCloser {
|
||||
mock := &MockTokenAuthenticatorCloser{ctrl: ctrl}
|
||||
mock.recorder = &MockTokenAuthenticatorCloserMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockTokenAuthenticatorCloser) EXPECT() *MockTokenAuthenticatorCloserMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AuthenticateToken mocks base method
|
||||
func (m *MockTokenAuthenticatorCloser) AuthenticateToken(arg0 context.Context, arg1 string) (*authenticator.Response, bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AuthenticateToken", arg0, arg1)
|
||||
ret0, _ := ret[0].(*authenticator.Response)
|
||||
ret1, _ := ret[1].(bool)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// AuthenticateToken indicates an expected call of AuthenticateToken
|
||||
func (mr *MockTokenAuthenticatorCloserMockRecorder) AuthenticateToken(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthenticateToken", reflect.TypeOf((*MockTokenAuthenticatorCloser)(nil).AuthenticateToken), arg0, arg1)
|
||||
}
|
||||
|
||||
// Close mocks base method
|
||||
func (m *MockTokenAuthenticatorCloser) Close() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Close")
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close
|
||||
func (mr *MockTokenAuthenticatorCloserMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTokenAuthenticatorCloser)(nil).Close))
|
||||
}
|
@ -79,7 +79,7 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
|
||||
|
||||
user, err := r.authenticator.AuthenticateTokenCredentialRequest(ctx, credentialRequest)
|
||||
if err != nil {
|
||||
traceFailureWithError(t, "webhook authentication", err)
|
||||
traceFailureWithError(t, "token authentication", err)
|
||||
return failureResponse(), nil
|
||||
}
|
||||
if user == nil || user.GetName() == "" {
|
||||
|
@ -145,7 +145,7 @@ func TestCreate(t *testing.T) {
|
||||
response, err := callCreate(context.Background(), storage, req)
|
||||
|
||||
requireSuccessfulResponseWithAuthenticationFailureMessage(t, err, response)
|
||||
requireOneLogStatement(r, logger, `"failure" failureType:webhook authentication,msg:some webhook error`)
|
||||
requireOneLogStatement(r, logger, `"failure" failureType:token authentication,msg:some webhook error`)
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenWebhookReturnsAnEmptyUsername", func() {
|
||||
|
@ -114,17 +114,93 @@ func TestCLILoginOIDC(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// Start the browser driver.
|
||||
page := browsertest.Open(t)
|
||||
|
||||
// Build pinniped CLI.
|
||||
t.Logf("building CLI binary")
|
||||
pinnipedExe := buildPinnipedCLI(t)
|
||||
|
||||
// Run "pinniped login oidc" to get an ExecCredential struct with an OIDC ID token.
|
||||
credOutput, sessionCachePath := runPinniedLoginOIDC(ctx, t, pinnipedExe)
|
||||
|
||||
// Assert some properties of the ExecCredential.
|
||||
t.Logf("validating ExecCredential")
|
||||
require.NotNil(t, credOutput.Status)
|
||||
require.Empty(t, credOutput.Status.ClientKeyData)
|
||||
require.Empty(t, credOutput.Status.ClientCertificateData)
|
||||
|
||||
// There should be at least 1 minute of remaining expiration (probably more).
|
||||
require.NotNil(t, credOutput.Status.ExpirationTimestamp)
|
||||
ttl := time.Until(credOutput.Status.ExpirationTimestamp.Time)
|
||||
require.Greater(t, ttl.Milliseconds(), (1 * time.Minute).Milliseconds())
|
||||
|
||||
// Assert some properties about the token, which should be a valid JWT.
|
||||
require.NotEmpty(t, credOutput.Status.Token)
|
||||
jws, err := jose.ParseSigned(credOutput.Status.Token)
|
||||
require.NoError(t, err)
|
||||
claims := map[string]interface{}{}
|
||||
require.NoError(t, json.Unmarshal(jws.UnsafePayloadWithoutVerification(), &claims))
|
||||
require.Equal(t, env.CLITestUpstream.Issuer, claims["iss"])
|
||||
require.Equal(t, env.CLITestUpstream.ClientID, claims["aud"])
|
||||
require.Equal(t, env.CLITestUpstream.Username, claims["email"])
|
||||
require.NotEmpty(t, claims["nonce"])
|
||||
|
||||
// Run the CLI again with the same session cache and login parameters.
|
||||
t.Logf("starting second CLI subprocess to test session caching")
|
||||
cmd2Output, err := oidcLoginCommand(ctx, t, pinnipedExe, sessionCachePath).CombinedOutput()
|
||||
require.NoError(t, err, string(cmd2Output))
|
||||
|
||||
// Expect the CLI to output the same ExecCredential in JSON format.
|
||||
t.Logf("validating second ExecCredential")
|
||||
var credOutput2 clientauthenticationv1beta1.ExecCredential
|
||||
require.NoErrorf(t, json.Unmarshal(cmd2Output, &credOutput2),
|
||||
"command returned something other than an ExecCredential:\n%s", string(cmd2Output))
|
||||
require.Equal(t, credOutput, credOutput2)
|
||||
|
||||
// Overwrite the cache entry to remove the access and ID tokens.
|
||||
t.Logf("overwriting cache to remove valid ID token")
|
||||
cache := filesession.New(sessionCachePath)
|
||||
cacheKey := oidcclient.SessionCacheKey{
|
||||
Issuer: env.CLITestUpstream.Issuer,
|
||||
ClientID: env.CLITestUpstream.ClientID,
|
||||
Scopes: []string{"email", "offline_access", "openid", "profile"},
|
||||
RedirectURI: strings.ReplaceAll(env.CLITestUpstream.CallbackURL, "127.0.0.1", "localhost"),
|
||||
}
|
||||
cached := cache.GetToken(cacheKey)
|
||||
require.NotNil(t, cached)
|
||||
require.NotNil(t, cached.RefreshToken)
|
||||
require.NotEmpty(t, cached.RefreshToken.Token)
|
||||
cached.IDToken = nil
|
||||
cached.AccessToken = nil
|
||||
cache.PutToken(cacheKey, cached)
|
||||
|
||||
// Run the CLI a third time with the same session cache and login parameters.
|
||||
t.Logf("starting third CLI subprocess to test refresh flow")
|
||||
cmd3Output, err := oidcLoginCommand(ctx, t, pinnipedExe, sessionCachePath).CombinedOutput()
|
||||
require.NoError(t, err, string(cmd2Output))
|
||||
|
||||
// Expect the CLI to output a new ExecCredential in JSON format (different from the one returned the first two times).
|
||||
t.Logf("validating third ExecCredential")
|
||||
var credOutput3 clientauthenticationv1beta1.ExecCredential
|
||||
require.NoErrorf(t, json.Unmarshal(cmd3Output, &credOutput3),
|
||||
"command returned something other than an ExecCredential:\n%s", string(cmd2Output))
|
||||
require.NotEqual(t, credOutput2.Status.Token, credOutput3.Status.Token)
|
||||
}
|
||||
|
||||
func runPinniedLoginOIDC(
|
||||
ctx context.Context,
|
||||
t *testing.T,
|
||||
pinnipedExe string,
|
||||
) (clientauthenticationv1beta1.ExecCredential, string) {
|
||||
t.Helper()
|
||||
|
||||
env := library.IntegrationEnv(t)
|
||||
|
||||
// Make a temp directory to hold the session cache for this test.
|
||||
sessionCachePath := testutil.TempDir(t) + "/sessions.yaml"
|
||||
|
||||
// Start the CLI running the "alpha login oidc [...]" command with stdout/stderr connected to pipes.
|
||||
// Start the browser driver.
|
||||
page := browsertest.Open(t)
|
||||
|
||||
// Start the CLI running the "login oidc [...]" command with stdout/stderr connected to pipes.
|
||||
cmd := oidcLoginCommand(ctx, t, pinnipedExe, sessionCachePath)
|
||||
stderr, err := cmd.StderrPipe()
|
||||
require.NoError(t, err)
|
||||
@ -221,68 +297,7 @@ func TestCLILoginOIDC(t *testing.T) {
|
||||
case credOutput = <-credOutputChan:
|
||||
}
|
||||
|
||||
// Assert some properties of the ExecCredential.
|
||||
t.Logf("validating ExecCredential")
|
||||
require.NotNil(t, credOutput.Status)
|
||||
require.Empty(t, credOutput.Status.ClientKeyData)
|
||||
require.Empty(t, credOutput.Status.ClientCertificateData)
|
||||
|
||||
// There should be at least 1 minute of remaining expiration (probably more).
|
||||
require.NotNil(t, credOutput.Status.ExpirationTimestamp)
|
||||
ttl := time.Until(credOutput.Status.ExpirationTimestamp.Time)
|
||||
require.Greater(t, ttl.Milliseconds(), (1 * time.Minute).Milliseconds())
|
||||
|
||||
// Assert some properties about the token, which should be a valid JWT.
|
||||
require.NotEmpty(t, credOutput.Status.Token)
|
||||
jws, err := jose.ParseSigned(credOutput.Status.Token)
|
||||
require.NoError(t, err)
|
||||
claims := map[string]interface{}{}
|
||||
require.NoError(t, json.Unmarshal(jws.UnsafePayloadWithoutVerification(), &claims))
|
||||
require.Equal(t, env.CLITestUpstream.Issuer, claims["iss"])
|
||||
require.Equal(t, env.CLITestUpstream.ClientID, claims["aud"])
|
||||
require.Equal(t, env.CLITestUpstream.Username, claims["email"])
|
||||
require.NotEmpty(t, claims["nonce"])
|
||||
|
||||
// Run the CLI again with the same session cache and login parameters.
|
||||
t.Logf("starting second CLI subprocess to test session caching")
|
||||
cmd2Output, err := oidcLoginCommand(ctx, t, pinnipedExe, sessionCachePath).CombinedOutput()
|
||||
require.NoError(t, err, string(cmd2Output))
|
||||
|
||||
// Expect the CLI to output the same ExecCredential in JSON format.
|
||||
t.Logf("validating second ExecCredential")
|
||||
var credOutput2 clientauthenticationv1beta1.ExecCredential
|
||||
require.NoErrorf(t, json.Unmarshal(cmd2Output, &credOutput2),
|
||||
"command returned something other than an ExecCredential:\n%s", string(cmd2Output))
|
||||
require.Equal(t, credOutput, credOutput2)
|
||||
|
||||
// Overwrite the cache entry to remove the access and ID tokens.
|
||||
t.Logf("overwriting cache to remove valid ID token")
|
||||
cache := filesession.New(sessionCachePath)
|
||||
cacheKey := oidcclient.SessionCacheKey{
|
||||
Issuer: env.CLITestUpstream.Issuer,
|
||||
ClientID: env.CLITestUpstream.ClientID,
|
||||
Scopes: []string{"email", "offline_access", "openid", "profile"},
|
||||
RedirectURI: strings.ReplaceAll(env.CLITestUpstream.CallbackURL, "127.0.0.1", "localhost"),
|
||||
}
|
||||
cached := cache.GetToken(cacheKey)
|
||||
require.NotNil(t, cached)
|
||||
require.NotNil(t, cached.RefreshToken)
|
||||
require.NotEmpty(t, cached.RefreshToken.Token)
|
||||
cached.IDToken = nil
|
||||
cached.AccessToken = nil
|
||||
cache.PutToken(cacheKey, cached)
|
||||
|
||||
// Run the CLI a third time with the same session cache and login parameters.
|
||||
t.Logf("starting third CLI subprocess to test refresh flow")
|
||||
cmd3Output, err := oidcLoginCommand(ctx, t, pinnipedExe, sessionCachePath).CombinedOutput()
|
||||
require.NoError(t, err, string(cmd2Output))
|
||||
|
||||
// Expect the CLI to output a new ExecCredential in JSON format (different from the one returned the first two times).
|
||||
t.Logf("validating third ExecCredential")
|
||||
var credOutput3 clientauthenticationv1beta1.ExecCredential
|
||||
require.NoErrorf(t, json.Unmarshal(cmd3Output, &credOutput3),
|
||||
"command returned something other than an ExecCredential:\n%s", string(cmd2Output))
|
||||
require.NotEqual(t, credOutput2.Status.Token, credOutput3.Status.Token)
|
||||
return credOutput, sessionCachePath
|
||||
}
|
||||
|
||||
func readAndExpectEmpty(r io.Reader) (err error) {
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
jwtpkg "gopkg.in/square/go-jose.v2/jwt"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -44,48 +45,89 @@ func TestSuccessfulCredentialRequest(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
testWebhook := library.CreateTestWebhookAuthenticator(ctx, t)
|
||||
tests := []struct {
|
||||
name string
|
||||
authenticator func(t *testing.T) corev1.TypedLocalObjectReference
|
||||
token func(t *testing.T) (token string, username string, groups []string)
|
||||
}{
|
||||
{
|
||||
name: "webhook",
|
||||
authenticator: func(t *testing.T) corev1.TypedLocalObjectReference {
|
||||
return library.CreateTestWebhookAuthenticator(ctx, t)
|
||||
},
|
||||
token: func(t *testing.T) (string, string, []string) {
|
||||
return library.IntegrationEnv(t).TestUser.Token, env.TestUser.ExpectedUsername, env.TestUser.ExpectedGroups
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jwt authenticator",
|
||||
authenticator: func(t *testing.T) corev1.TypedLocalObjectReference {
|
||||
return library.CreateTestJWTAuthenticator(ctx, t)
|
||||
},
|
||||
token: func(t *testing.T) (string, string, []string) {
|
||||
pinnipedExe := buildPinnipedCLI(t)
|
||||
credOutput, _ := runPinniedLoginOIDC(ctx, t, pinnipedExe)
|
||||
token := credOutput.Status.Token
|
||||
|
||||
var response *loginv1alpha1.TokenCredentialRequest
|
||||
successfulResponse := func() bool {
|
||||
var err error
|
||||
response, err = makeRequest(ctx, t, validCredentialRequestSpecWithRealToken(t, testWebhook))
|
||||
require.NoError(t, err, "the request should never fail at the HTTP level")
|
||||
return response.Status.Credential != nil
|
||||
// By default, the JWTAuthenticator expects the username to be in the "sub" claim and the
|
||||
// groups to be in the "groups" claim.
|
||||
username, groups := getJWTSubAndGroupsClaims(t, token)
|
||||
|
||||
return credOutput.Status.Token, username, groups
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.Eventually(t, successfulResponse, 10*time.Second, 500*time.Millisecond)
|
||||
require.NotNil(t, response)
|
||||
require.NotNil(t, response.Status.Credential)
|
||||
require.Empty(t, response.Status.Message)
|
||||
require.Empty(t, response.Spec)
|
||||
require.Empty(t, response.Status.Credential.Token)
|
||||
require.NotEmpty(t, response.Status.Credential.ClientCertificateData)
|
||||
require.Equal(t, env.TestUser.ExpectedUsername, getCommonName(t, response.Status.Credential.ClientCertificateData))
|
||||
require.ElementsMatch(t, env.TestUser.ExpectedGroups, getOrganizations(t, response.Status.Credential.ClientCertificateData))
|
||||
require.NotEmpty(t, response.Status.Credential.ClientKeyData)
|
||||
require.NotNil(t, response.Status.Credential.ExpirationTimestamp)
|
||||
require.InDelta(t, 5*time.Minute, time.Until(response.Status.Credential.ExpirationTimestamp.Time), float64(time.Minute))
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
authenticator := test.authenticator(t)
|
||||
token, username, groups := test.token(t)
|
||||
|
||||
// Create a client using the admin kubeconfig.
|
||||
adminClient := library.NewClientset(t)
|
||||
var response *loginv1alpha1.TokenCredentialRequest
|
||||
successfulResponse := func() bool {
|
||||
var err error
|
||||
response, err = makeRequest(ctx, t, loginv1alpha1.TokenCredentialRequestSpec{
|
||||
Token: token,
|
||||
Authenticator: authenticator,
|
||||
})
|
||||
require.NoError(t, err, "the request should never fail at the HTTP level")
|
||||
return response.Status.Credential != nil
|
||||
}
|
||||
assert.Eventually(t, successfulResponse, 10*time.Second, 500*time.Millisecond)
|
||||
require.NotNil(t, response)
|
||||
require.Emptyf(t, response.Status.Message, "value is: %q", safeDerefStringPtr(response.Status.Message))
|
||||
require.NotNil(t, response.Status.Credential)
|
||||
require.Empty(t, response.Spec)
|
||||
require.Empty(t, response.Status.Credential.Token)
|
||||
require.NotEmpty(t, response.Status.Credential.ClientCertificateData)
|
||||
require.Equal(t, username, getCommonName(t, response.Status.Credential.ClientCertificateData))
|
||||
require.ElementsMatch(t, groups, getOrganizations(t, response.Status.Credential.ClientCertificateData))
|
||||
require.NotEmpty(t, response.Status.Credential.ClientKeyData)
|
||||
require.NotNil(t, response.Status.Credential.ExpirationTimestamp)
|
||||
require.InDelta(t, 5*time.Minute, time.Until(response.Status.Credential.ExpirationTimestamp.Time), float64(time.Minute))
|
||||
|
||||
// Create a client using the certificate from the CredentialRequest.
|
||||
clientWithCertFromCredentialRequest := library.NewClientsetWithCertAndKey(
|
||||
t,
|
||||
response.Status.Credential.ClientCertificateData,
|
||||
response.Status.Credential.ClientKeyData,
|
||||
)
|
||||
// Create a client using the admin kubeconfig.
|
||||
adminClient := library.NewClientset(t)
|
||||
|
||||
t.Run(
|
||||
"access as user",
|
||||
library.AccessAsUserTest(ctx, adminClient, env.TestUser.ExpectedUsername, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
for _, group := range env.TestUser.ExpectedGroups {
|
||||
group := group
|
||||
t.Run(
|
||||
"access as group "+group,
|
||||
library.AccessAsGroupTest(ctx, adminClient, group, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
// Create a client using the certificate from the CredentialRequest.
|
||||
clientWithCertFromCredentialRequest := library.NewClientsetWithCertAndKey(
|
||||
t,
|
||||
response.Status.Credential.ClientCertificateData,
|
||||
response.Status.Credential.ClientKeyData,
|
||||
)
|
||||
|
||||
t.Run(
|
||||
"access as user",
|
||||
library.AccessAsUserTest(ctx, adminClient, username, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
for _, group := range groups {
|
||||
group := group
|
||||
t.Run(
|
||||
"access as group "+group,
|
||||
library.AccessAsGroupTest(ctx, adminClient, group, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,3 +225,26 @@ func getOrganizations(t *testing.T, certPEM string) []string {
|
||||
|
||||
return cert.Subject.Organization
|
||||
}
|
||||
|
||||
func safeDerefStringPtr(s *string) string {
|
||||
if s == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return *s
|
||||
}
|
||||
|
||||
func getJWTSubAndGroupsClaims(t *testing.T, jwt string) (string, []string) {
|
||||
t.Helper()
|
||||
|
||||
token, err := jwtpkg.ParseSigned(jwt)
|
||||
require.NoError(t, err)
|
||||
|
||||
var claims struct {
|
||||
Sub string `json:"sub"`
|
||||
Groups []string `json:"groups"`
|
||||
}
|
||||
err = token.UnsafeClaimsWithoutVerification(&claims)
|
||||
require.NoError(t, err)
|
||||
|
||||
return claims.Sub, claims.Groups
|
||||
}
|
||||
|
@ -162,6 +162,14 @@ func TestGetAPIResourceList(t *testing.T) {
|
||||
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
||||
Categories: []string{"pinniped", "pinniped-authenticator", "pinniped-authenticators"},
|
||||
},
|
||||
{
|
||||
Name: "jwtauthenticators",
|
||||
SingularName: "jwtauthenticator",
|
||||
Namespaced: true,
|
||||
Kind: "JWTAuthenticator",
|
||||
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
||||
Categories: []string{"pinniped", "pinniped-authenticator", "pinniped-authenticators"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -6,6 +6,7 @@ package library
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -163,6 +164,51 @@ func CreateTestWebhookAuthenticator(ctx context.Context, t *testing.T) corev1.Ty
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTestJWTAuthenticator creates and returns a test JWTAuthenticator in
|
||||
// $PINNIPED_TEST_CONCIERGE_NAMESPACE, which will be automatically deleted at the end of the current
|
||||
// test's lifetime. It returns a corev1.TypedLocalObjectReference which describes the test JWT
|
||||
// authenticator within the test namespace.
|
||||
//
|
||||
// CreateTestJWTAuthenticator gets the OIDC issuer info from IntegrationEnv().CLITestUpstream.
|
||||
func CreateTestJWTAuthenticator(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
t.Helper()
|
||||
testEnv := IntegrationEnv(t)
|
||||
|
||||
client := NewConciergeClientset(t)
|
||||
jwtAuthenticators := client.AuthenticationV1alpha1().JWTAuthenticators(testEnv.ConciergeNamespace)
|
||||
|
||||
createContext, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
jwtAuthenticator, err := jwtAuthenticators.Create(createContext, &auth1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: testObjectMeta(t, "jwt-authenticator"),
|
||||
Spec: auth1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: testEnv.CLITestUpstream.Issuer,
|
||||
Audience: testEnv.CLITestUpstream.ClientID,
|
||||
TLS: &auth1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(testEnv.CLITestUpstream.CABundle)),
|
||||
},
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
require.NoError(t, err, "could not create test JWTAuthenticator")
|
||||
t.Logf("created test JWTAuthenticator %s/%s", jwtAuthenticator.Namespace, jwtAuthenticator.Name)
|
||||
|
||||
t.Cleanup(func() {
|
||||
t.Helper()
|
||||
t.Logf("cleaning up test JWTAuthenticator %s/%s", jwtAuthenticator.Namespace, jwtAuthenticator.Name)
|
||||
deleteCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
err := jwtAuthenticators.Delete(deleteCtx, jwtAuthenticator.Name, metav1.DeleteOptions{})
|
||||
require.NoErrorf(t, err, "could not cleanup test JWTAuthenticator %s/%s", jwtAuthenticator.Namespace, jwtAuthenticator.Name)
|
||||
})
|
||||
|
||||
return corev1.TypedLocalObjectReference{
|
||||
APIGroup: &auth1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "JWTAuthenticator",
|
||||
Name: jwtAuthenticator.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTestOIDCProvider creates and returns a test OIDCProvider in
|
||||
// $PINNIPED_TEST_SUPERVISOR_NAMESPACE, which will be automatically deleted at the end of the
|
||||
// current test's lifetime. It generates a random, valid, issuer for the OIDCProvider.
|
||||
|
Loading…
Reference in New Issue
Block a user