![Ryan Richard](/assets/img/avatar_default.png)
- Add `AllowPasswordGrant` boolean field to OIDCIdentityProvider's spec - The oidc upstream watcher controller copies the value of `AllowPasswordGrant` into the configuration of the cached provider - Add password grant to the UpstreamOIDCIdentityProviderI interface which is implemented by the cached provider instance for use in the authorization endpoint - Enhance the IDP discovery endpoint to return the supported "flows" for each IDP ("cli_password" and/or "browser_authcode") - Enhance `pinniped get kubeconfig` to help the user choose the desired flow for the selected IDP, and to write the flow into the resulting kubeconfg - Enhance `pinniped login oidc` to have a flow flag to tell it which client-side flow it should use for auth (CLI-based or browser-based) - In the Dex config, allow the resource owner password grant, which Dex implements to also return ID tokens, for use in integration tests - Enhance the authorize endpoint to perform password grant when requested by the incoming headers. This commit does not include unit tests for the enhancements to the authorize endpoint, which will come in the next commit - Extract some shared helpers from the callback endpoint to share the code with the authorize endpoint - Add new integration tests
2812 lines
111 KiB
Go
2812 lines
111 KiB
Go
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
kubetesting "k8s.io/client-go/testing"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
|
|
conciergev1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
|
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
|
conciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
|
fakeconciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake"
|
|
"go.pinniped.dev/internal/certauthority"
|
|
"go.pinniped.dev/internal/here"
|
|
"go.pinniped.dev/internal/testutil"
|
|
"go.pinniped.dev/internal/testutil/testlogger"
|
|
)
|
|
|
|
func TestGetKubeconfig(t *testing.T) {
|
|
testOIDCCA, err := certauthority.New("Test CA", 1*time.Hour)
|
|
require.NoError(t, err)
|
|
tmpdir := testutil.TempDir(t)
|
|
testOIDCCABundlePath := filepath.Join(tmpdir, "testca.pem")
|
|
require.NoError(t, ioutil.WriteFile(testOIDCCABundlePath, testOIDCCA.Bundle(), 0600))
|
|
|
|
testConciergeCA, err := certauthority.New("Test Concierge CA", 1*time.Hour)
|
|
require.NoError(t, err)
|
|
testConciergeCABundlePath := filepath.Join(tmpdir, "testconciergeca.pem")
|
|
require.NoError(t, ioutil.WriteFile(testConciergeCABundlePath, testConciergeCA.Bundle(), 0600))
|
|
|
|
credentialIssuer := func() runtime.Object {
|
|
return &configv1alpha1.CredentialIssuer{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
|
|
Status: configv1alpha1.CredentialIssuerStatus{
|
|
Strategies: []configv1alpha1.CredentialIssuerStrategy{{
|
|
Type: configv1alpha1.KubeClusterSigningCertificateStrategyType,
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: configv1alpha1.FetchedKeyStrategyReason,
|
|
Frontend: &configv1alpha1.CredentialIssuerFrontend{
|
|
Type: configv1alpha1.TokenCredentialRequestAPIFrontendType,
|
|
TokenCredentialRequestAPIInfo: &configv1alpha1.TokenCredentialRequestAPIInfo{
|
|
Server: "https://concierge-endpoint.example.com",
|
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString(testConciergeCA.Bundle()),
|
|
},
|
|
},
|
|
}},
|
|
},
|
|
}
|
|
}
|
|
|
|
jwtAuthenticator := func(issuerCABundle string, issuerURL string) runtime.Object {
|
|
return &conciergev1alpha1.JWTAuthenticator{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"},
|
|
Spec: conciergev1alpha1.JWTAuthenticatorSpec{
|
|
Issuer: issuerURL,
|
|
Audience: "test-audience",
|
|
TLS: &conciergev1alpha1.TLSSpec{
|
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(issuerCABundle)),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
happyOIDCDiscoveryResponse := func(issuerURL string) string {
|
|
return here.Docf(`{
|
|
"issuer": "%s",
|
|
"other-key": "other-value",
|
|
"discovery.supervisor.pinniped.dev/v1alpha1": {
|
|
"pinniped_identity_providers_endpoint": "%s/v1alpha1/pinniped_identity_providers"
|
|
},
|
|
"another-key": "another-value"
|
|
}`, issuerURL, issuerURL)
|
|
}
|
|
|
|
onlyIssuerOIDCDiscoveryResponse := func(issuerURL string) string {
|
|
return here.Docf(`{
|
|
"issuer": "%s",
|
|
"other-key": "other-value"
|
|
}`, issuerURL)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
args func(string, string) []string
|
|
env map[string]string
|
|
getPathToSelfErr error
|
|
getClientsetErr error
|
|
conciergeObjects func(string, string) []runtime.Object
|
|
conciergeReactions []kubetesting.Reactor
|
|
oidcDiscoveryResponse func(string) string
|
|
oidcDiscoveryStatusCode int
|
|
idpsDiscoveryResponse string
|
|
idpsDiscoveryStatusCode int
|
|
wantLogs func(string, string) []string
|
|
wantError bool
|
|
wantStdout func(string, string) string
|
|
wantStderr func(string, string) string
|
|
wantOptionsCount int
|
|
wantAPIGroupSuffix string
|
|
}{
|
|
{
|
|
name: "help flag passed",
|
|
args: func(issuerCABundle string, issuerURL string) []string { return []string{"--help"} },
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Doc(`
|
|
Generate a Pinniped-based kubeconfig for a cluster
|
|
|
|
Usage:
|
|
kubeconfig [flags]
|
|
|
|
Flags:
|
|
--concierge-api-group-suffix string Concierge API group suffix (default "pinniped.dev")
|
|
--concierge-authenticator-name string Concierge authenticator name (default: autodiscover)
|
|
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover)
|
|
--concierge-ca-bundle path Path to TLS certificate authority bundle (PEM format, optional, can be repeated) to use when connecting to the Concierge
|
|
--concierge-credential-issuer string Concierge CredentialIssuer object to use for autodiscovery (default: autodiscover)
|
|
--concierge-endpoint string API base for the Concierge endpoint
|
|
--concierge-mode mode Concierge mode of operation (default TokenCredentialRequestAPI)
|
|
--concierge-skip-wait Skip waiting for any pending Concierge strategies to become ready (default: false)
|
|
--credential-cache string Path to cluster-specific credentials cache
|
|
--generated-name-suffix string Suffix to append to generated cluster, context, user kubeconfig entries (default "-pinniped")
|
|
-h, --help help for kubeconfig
|
|
--kubeconfig string Path to kubeconfig file
|
|
--kubeconfig-context string Kubeconfig context name (default: current active context)
|
|
--no-concierge Generate a configuration which does not use the Concierge, but sends the credential to the cluster directly
|
|
--oidc-ca-bundle path Path to TLS certificate authority bundle (PEM format, optional, can be repeated)
|
|
--oidc-client-id string OpenID Connect client ID (default: autodiscover) (default "pinniped-cli")
|
|
--oidc-issuer string OpenID Connect issuer URL (default: autodiscover)
|
|
--oidc-listen-port uint16 TCP port for localhost listener (authorization code flow only)
|
|
--oidc-request-audience string Request a token with an alternate audience using RFC8693 token exchange
|
|
--oidc-scopes strings OpenID Connect scopes to request during login (default [offline_access,openid,pinniped:request-audience])
|
|
--oidc-session-cache string Path to OpenID Connect session cache file
|
|
--oidc-skip-browser During OpenID Connect login, skip opening the browser (just print the URL)
|
|
-o, --output string Output file path (default: stdout)
|
|
--skip-validation Skip final validation of the kubeconfig (default: false)
|
|
--static-token string Instead of doing an OIDC-based login, specify a static token
|
|
--static-token-env string Instead of doing an OIDC-based login, read a static token from the environment
|
|
--timeout duration Timeout for autodiscovery and validation (default 10m0s)
|
|
--upstream-identity-provider-flow string The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. 'cli_password', 'browser_authcode')
|
|
--upstream-identity-provider-name string The name of the upstream identity provider used during login with a Supervisor
|
|
--upstream-identity-provider-type string The type of the upstream identity provider used during login with a Supervisor (e.g. 'oidc', 'ldap')
|
|
`)
|
|
},
|
|
},
|
|
{
|
|
name: "invalid OIDC CA bundle path",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--oidc-ca-bundle", "./does/not/exist",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: invalid argument "./does/not/exist" for "--oidc-ca-bundle" flag: could not read CA bundle path: open ./does/not/exist: no such file or directory` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid Concierge CA bundle",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--concierge-ca-bundle", "./does/not/exist",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: invalid argument "./does/not/exist" for "--concierge-ca-bundle" flag: could not read CA bundle path: open ./does/not/exist: no such file or directory` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid kubeconfig path",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./does/not/exist",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not load --kubeconfig: stat ./does/not/exist: no such file or directory` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid kubeconfig context, missing",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--kubeconfig-context", "invalid",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not load --kubeconfig/--kubeconfig-context: no such context "invalid"` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid kubeconfig context, missing cluster",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--kubeconfig-context", "invalid-context-no-such-cluster",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not load --kubeconfig/--kubeconfig-context: no such cluster "invalid-cluster"` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid kubeconfig context, missing user",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--kubeconfig-context", "invalid-context-no-such-user",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not load --kubeconfig/--kubeconfig-context: no such user "invalid-user"` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "clientset creation failure",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
getClientsetErr: fmt.Errorf("some kube error"),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not configure Kubernetes client: some kube error` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "no credentialissuers",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no CredentialIssuers were found` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "credentialissuer not found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--concierge-credential-issuer", "does-not-exist",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: credentialissuers.config.concierge.pinniped.dev "does-not-exist" not found` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "webhook authenticator not found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--concierge-authenticator-type", "webhook",
|
|
"--concierge-authenticator-name", "test-authenticator",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: webhookauthenticators.authentication.concierge.pinniped.dev "test-authenticator" not found` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "JWT authenticator not found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--concierge-authenticator-type", "jwt",
|
|
"--concierge-authenticator-name", "test-authenticator",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: jwtauthenticators.authentication.concierge.pinniped.dev "test-authenticator" not found` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid authenticator type",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--concierge-authenticator-type", "invalid",
|
|
"--concierge-authenticator-name", "test-authenticator",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: invalid authenticator type "invalid", supported values are "webhook" and "jwt"` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "fail to autodetect authenticator, listing jwtauthenticators fails",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
}
|
|
},
|
|
conciergeReactions: []kubetesting.Reactor{
|
|
&kubetesting.SimpleReactor{
|
|
Verb: "*",
|
|
Resource: "jwtauthenticators",
|
|
Reaction: func(kubetesting.Action) (bool, runtime.Object, error) {
|
|
return true, nil, fmt.Errorf("some list error")
|
|
},
|
|
},
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: failed to list JWTAuthenticator objects for autodiscovery: some list error` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "fail to autodetect authenticator, listing webhookauthenticators fails",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
}
|
|
},
|
|
conciergeReactions: []kubetesting.Reactor{
|
|
&kubetesting.SimpleReactor{
|
|
Verb: "*",
|
|
Resource: "webhookauthenticators",
|
|
Reaction: func(kubetesting.Action) (bool, runtime.Object, error) {
|
|
return true, nil, fmt.Errorf("some list error")
|
|
},
|
|
},
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: failed to list WebhookAuthenticator objects for autodiscovery: some list error` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "fail to autodetect authenticator, none found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no authenticators were found` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "fail to autodetect authenticator, multiple found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}},
|
|
&conciergev1alpha1.JWTAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator-1"}},
|
|
&conciergev1alpha1.JWTAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator-2"}},
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator-3"}},
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator-4"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="found JWTAuthenticator" "name"="test-authenticator-1"`,
|
|
`"level"=0 "msg"="found JWTAuthenticator" "name"="test-authenticator-2"`,
|
|
`"level"=0 "msg"="found WebhookAuthenticator" "name"="test-authenticator-3"`,
|
|
`"level"=0 "msg"="found WebhookAuthenticator" "name"="test-authenticator-4"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: multiple authenticators were found, so the --concierge-authenticator-type/--concierge-authenticator-name flags must be specified` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "autodetect webhook authenticator, bad credential issuer with only failing strategy",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
|
|
Status: configv1alpha1.CredentialIssuerStatus{
|
|
Strategies: []configv1alpha1.CredentialIssuerStrategy{{
|
|
Type: "SomeType",
|
|
Status: configv1alpha1.ErrorStrategyStatus,
|
|
Reason: "SomeReason",
|
|
Message: "Some message",
|
|
}},
|
|
},
|
|
},
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="found CredentialIssuer strategy" "message"="Some message" "reason"="SomeReason" "status"="Error" "type"="SomeType"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not autodiscover --concierge-mode` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "autodetect webhook authenticator, bad credential issuer with invalid impersonation CA",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
|
|
Status: configv1alpha1.CredentialIssuerStatus{
|
|
Strategies: []configv1alpha1.CredentialIssuerStrategy{
|
|
{
|
|
Type: "SomeBrokenType",
|
|
Status: configv1alpha1.ErrorStrategyStatus,
|
|
Reason: "SomeFailureReason",
|
|
Message: "Some error message",
|
|
LastUpdateTime: metav1.Now(),
|
|
},
|
|
{
|
|
Type: "SomeUnknownType",
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: "SomeReason",
|
|
Message: "Some error message",
|
|
LastUpdateTime: metav1.Now(),
|
|
Frontend: &configv1alpha1.CredentialIssuerFrontend{
|
|
Type: "SomeUnknownFrontendType",
|
|
},
|
|
},
|
|
{
|
|
Type: "SomeType",
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: "SomeReason",
|
|
Message: "Some message",
|
|
LastUpdateTime: metav1.Now(),
|
|
Frontend: &configv1alpha1.CredentialIssuerFrontend{
|
|
Type: configv1alpha1.ImpersonationProxyFrontendType,
|
|
ImpersonationProxyInfo: &configv1alpha1.ImpersonationProxyInfo{
|
|
Endpoint: "https://impersonation-endpoint",
|
|
CertificateAuthorityData: "invalid-base-64",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in impersonation proxy mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://impersonation-endpoint"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: autodiscovered Concierge CA bundle is invalid: illegal base64 data at input byte 7` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "autodetect webhook authenticator, missing --oidc-issuer",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered WebhookAuthenticator" "name"="test-authenticator"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not autodiscover --oidc-issuer and none was provided` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "autodetect JWT authenticator, invalid TLS bundle",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
|
|
Status: configv1alpha1.CredentialIssuerStatus{
|
|
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{
|
|
Server: "https://concierge-endpoint",
|
|
CertificateAuthorityData: "ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==",
|
|
},
|
|
Strategies: []configv1alpha1.CredentialIssuerStrategy{{
|
|
Type: configv1alpha1.KubeClusterSigningCertificateStrategyType,
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: configv1alpha1.FetchedKeyStrategyReason,
|
|
Message: "Successfully fetched key",
|
|
LastUpdateTime: metav1.Now(),
|
|
// Simulate a previous version of CredentialIssuer that's missing this Frontend field.
|
|
Frontend: nil,
|
|
}},
|
|
},
|
|
},
|
|
&conciergev1alpha1.JWTAuthenticator{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"},
|
|
Spec: conciergev1alpha1.JWTAuthenticatorSpec{
|
|
Issuer: issuerURL,
|
|
Audience: "some-test-audience",
|
|
TLS: &conciergev1alpha1.TLSSpec{
|
|
CertificateAuthorityData: "invalid-base64",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="some-test-audience"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: tried to autodiscover --oidc-ca-bundle, but JWTAuthenticator test-authenticator has invalid spec.tls.certificateAuthorityData: illegal base64 data at input byte 7` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "fail to get self-path",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
}
|
|
},
|
|
getPathToSelfErr: fmt.Errorf("some OS error"),
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: onlyIssuerOIDCDiscoveryResponse,
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: could not determine the Pinniped executable path: some OS error` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid static token flags",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--static-token", "test-token",
|
|
"--static-token-env", "TEST_TOKEN",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered WebhookAuthenticator" "name"="test-authenticator"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: only one of --static-token and --static-token-env can be specified` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "invalid API group suffix",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--concierge-api-group-suffix", ".starts.with.dot",
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: invalid API group suffix: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "when OIDC discovery document 400s",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryStatusCode: http.StatusBadRequest,
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return "Error: while fetching OIDC discovery data from issuer: 400 Bad Request: {}\n"
|
|
},
|
|
},
|
|
{
|
|
name: "when OIDC discovery document lists the wrong issuer",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: func(issuerURL string) string {
|
|
return here.Doc(`{
|
|
"issuer": "https://wrong-issuer.com"
|
|
}`)
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return fmt.Sprintf(
|
|
"Error: while fetching OIDC discovery data from issuer: oidc: issuer did not match the issuer returned by provider, expected \"%s\" got \"https://wrong-issuer.com\"\n",
|
|
issuerURL)
|
|
},
|
|
},
|
|
{
|
|
name: "when IDP discovery document returns any error",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryStatusCode: http.StatusBadRequest,
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return "Error: unable to fetch IDP discovery data from issuer: unexpected http response status: 400 Bad Request\n"
|
|
},
|
|
},
|
|
{
|
|
name: "when IDP discovery document contains multiple IDPs and no name or type flags are given",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"},
|
|
{"name": "some-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: multiple Supervisor upstream identity providers were found, ` +
|
|
`so the --upstream-identity-provider-name/--upstream-identity-provider-type flags must be specified. ` +
|
|
`Found these upstreams: [{"name":"some-ldap-idp","type":"ldap"},{"name":"some-oidc-idp","type":"oidc"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "when OIDC discovery document is not valid JSON",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: func(issuerURL string) string {
|
|
return "this is not valid JSON"
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return "Error: while fetching OIDC discovery data from issuer: oidc: failed to decode provider discovery object: got Content-Type = application/json, but could not unmarshal as JSON: invalid character 'h' in literal true (expecting 'r')\n"
|
|
},
|
|
},
|
|
{
|
|
name: "when IDP discovery document is not valid JSON",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: "this is not valid JSON",
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return "Error: unable to fetch IDP discovery data from issuer: could not parse response JSON: invalid character 'h' in literal true (expecting 'r')\n"
|
|
},
|
|
},
|
|
{
|
|
name: "when tls information is missing from jwtauthenticator, errors because OIDC discovery fails",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
&conciergev1alpha1.JWTAuthenticator{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"},
|
|
Spec: conciergev1alpha1.JWTAuthenticatorSpec{
|
|
Issuer: issuerURL,
|
|
Audience: "test-audience",
|
|
},
|
|
},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return fmt.Sprintf("Error: while fetching OIDC discovery data from issuer: Get \"%s/.well-known/openid-configuration\": x509: certificate signed by unknown authority\n", issuerURL)
|
|
},
|
|
},
|
|
{
|
|
name: "when the issuer url is bad",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--oidc-issuer", "https%://bad-issuer-url", // this url cannot be parsed
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
&conciergev1alpha1.JWTAuthenticator{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"},
|
|
Spec: conciergev1alpha1.JWTAuthenticatorSpec{
|
|
Issuer: issuerURL,
|
|
Audience: "test-audience",
|
|
},
|
|
},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: while fetching OIDC discovery data from issuer: parse "https%://bad-issuer-url/.well-known/openid-configuration": first path segment in URL cannot contain colon` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "when the IDP discovery url is bad",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: func(issuerURL string) string {
|
|
return here.Docf(`{
|
|
"issuer": "%s",
|
|
"discovery.supervisor.pinniped.dev/v1alpha1": {
|
|
"pinniped_identity_providers_endpoint": "https%%://illegal_url"
|
|
}
|
|
}`, issuerURL)
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: while forming request to IDP discovery URL: parse "https%://illegal_url": first path segment in URL cannot contain colon` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery does not find matching IDP when name and type are both specified",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-name", "does-not-exist-idp",
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"},
|
|
{"name": "some-other-ldap-idp", "type": "ldap"}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no Supervisor upstream identity providers with name "does-not-exist-idp" of type "ldap" were found.` +
|
|
` Found these upstreams: [{"name":"some-ldap-idp","type":"ldap"},{"name":"some-other-ldap-idp","type":"ldap"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery fails to resolve ambiguity when type is specified but name is not",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"},
|
|
{"name": "some-other-ldap-idp", "type": "ldap"},
|
|
{"name": "some-oidc-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: multiple Supervisor upstream identity providers of type "ldap" were found,` +
|
|
` so the --upstream-identity-provider-name flag must be specified.` +
|
|
` Found these upstreams: [{"name":"some-ldap-idp","type":"ldap"},{"name":"some-other-ldap-idp","type":"ldap"},{"name":"some-oidc-idp","type":"oidc"},{"name":"some-other-oidc-idp","type":"oidc"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery fails to resolve ambiguity when name is specified but type is not",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-name", "my-idp",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "my-idp", "type": "ldap"},
|
|
{"name": "my-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: multiple Supervisor upstream identity providers with name "my-idp" were found,` +
|
|
` so the --upstream-identity-provider-type flag must be specified.` +
|
|
` Found these upstreams: [{"name":"my-idp","type":"ldap"},{"name":"my-idp","type":"oidc"},{"name":"some-other-oidc-idp","type":"oidc"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery fails to find any matching IDPs when type is specified but name is not",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-oidc-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no Supervisor upstream identity providers of type "ldap" were found.` +
|
|
` Found these upstreams: [{"name":"some-oidc-idp","type":"oidc"},{"name":"some-other-oidc-idp","type":"oidc"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery fails to find any matching IDPs when type is specified but name is not and there is only one IDP found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no Supervisor upstream identity providers of type "ldap" were found.` +
|
|
` Found these upstreams: [{"name":"some-oidc-idp","type":"oidc"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery fails to find any matching IDPs when name is specified but type is not",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-name", "my-nonexistent-idp",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-oidc-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no Supervisor upstream identity providers with name "my-nonexistent-idp" were found.` +
|
|
` Found these upstreams: [{"name":"some-oidc-idp","type":"oidc"},{"name":"some-other-oidc-idp","type":"oidc"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery fails to find any matching IDPs when name is specified but type is not and there is only one IDP found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-name", "my-nonexistent-idp",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no Supervisor upstream identity providers with name "my-nonexistent-idp" were found.` +
|
|
` Found these upstreams: [{"name":"some-oidc-idp","type":"oidc"}]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery when flow is specified but it does not match any flow returned by discovery",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-flow", "my-nonexistent-flow",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-oidc-idp", "type": "oidc", "flows": ["non-matching-flow-1", "non-matching-flow-2"]}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: no client flow "my-nonexistent-flow" for Supervisor upstream identity provider "some-oidc-idp" of type "oidc" were found.` +
|
|
` Found these flows: [non-matching-flow-1 non-matching-flow-2]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery when no flow is specified and more than one flow is returned by discovery",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-oidc-idp", "type": "oidc", "flows": ["flow1", "flow2"]}
|
|
]
|
|
}`),
|
|
wantError: true,
|
|
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
|
return `Error: multiple client flows for Supervisor upstream identity provider "some-oidc-idp" of type "oidc" were found, so the --upstream-identity-provider-flow flag must be specified.` +
|
|
` Found these flows: [flow1 flow2]` + "\n"
|
|
},
|
|
},
|
|
{
|
|
name: "valid static token",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--static-token", "test-token",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered WebhookAuthenticator" "name"="test-authenticator"`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Doc(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- static
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=webhook
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --token=test-token
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`)
|
|
},
|
|
},
|
|
{
|
|
name: "valid static token from env var",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--static-token-env", "TEST_TOKEN",
|
|
"--skip-validation",
|
|
"--credential-cache", "",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
|
|
}
|
|
},
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered WebhookAuthenticator" "name"="test-authenticator"`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Doc(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- static
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=webhook
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --credential-cache=
|
|
- --token-env=TEST_TOKEN
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`)
|
|
},
|
|
},
|
|
{
|
|
name: "autodetect JWT authenticator",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: onlyIssuerOIDCDiscoveryResponse,
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
|
|
name: "autodetect nothing, set a bunch of options",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--concierge-credential-issuer", "test-credential-issuer",
|
|
"--concierge-api-group-suffix", "tuna.io",
|
|
"--concierge-authenticator-type", "webhook",
|
|
"--concierge-authenticator-name", "test-authenticator",
|
|
"--concierge-mode", "TokenCredentialRequestAPI",
|
|
"--concierge-endpoint", "https://explicit-concierge-endpoint.example.com",
|
|
"--concierge-ca-bundle", testConciergeCABundlePath,
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-skip-browser",
|
|
"--oidc-skip-listen",
|
|
"--oidc-listen-port", "1234",
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--oidc-session-cache", "/path/to/cache/dir/sessions.yaml",
|
|
"--oidc-debug-session-cache",
|
|
"--oidc-request-audience", "test-audience",
|
|
"--skip-validation",
|
|
"--generated-name-suffix", "-sso",
|
|
"--credential-cache", "/path/to/cache/dir/credentials.yaml",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: onlyIssuerOIDCDiscoveryResponse,
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string { return nil },
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: %s
|
|
server: https://explicit-concierge-endpoint.example.com
|
|
name: kind-cluster-sso
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-sso
|
|
user: kind-user-sso
|
|
name: kind-context-sso
|
|
current-context: kind-context-sso
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-sso
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=tuna.io
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=webhook
|
|
- --concierge-endpoint=https://explicit-concierge-endpoint.example.com
|
|
- --concierge-ca-bundle-data=%s
|
|
- --credential-cache=/path/to/cache/dir/credentials.yaml
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --skip-browser
|
|
- --skip-listen
|
|
- --listen-port=1234
|
|
- --ca-bundle-data=%s
|
|
- --session-cache=/path/to/cache/dir/sessions.yaml
|
|
- --debug-session-cache
|
|
- --request-audience=test-audience
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
base64.StdEncoding.EncodeToString(testConciergeCA.Bundle()),
|
|
base64.StdEncoding.EncodeToString(testConciergeCA.Bundle()),
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)),
|
|
)
|
|
},
|
|
wantAPIGroupSuffix: "tuna.io",
|
|
},
|
|
{
|
|
name: "configure impersonation proxy with autodiscovered JWT authenticator",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--concierge-mode", "ImpersonationProxy",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
|
|
Status: configv1alpha1.CredentialIssuerStatus{
|
|
Strategies: []configv1alpha1.CredentialIssuerStrategy{
|
|
// This TokenCredentialRequestAPI strategy would normally be chosen, but
|
|
// --concierge-mode=ImpersonationProxy should force it to be skipped.
|
|
{
|
|
Type: "SomeType",
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: "SomeReason",
|
|
Message: "Some message",
|
|
LastUpdateTime: metav1.Now(),
|
|
Frontend: &configv1alpha1.CredentialIssuerFrontend{
|
|
Type: configv1alpha1.TokenCredentialRequestAPIFrontendType,
|
|
TokenCredentialRequestAPIInfo: &configv1alpha1.TokenCredentialRequestAPIInfo{
|
|
Server: "https://token-credential-request-api-endpoint.test",
|
|
CertificateAuthorityData: "dGVzdC10Y3ItYXBpLWNh",
|
|
},
|
|
},
|
|
},
|
|
// The endpoint and CA from this impersonation proxy strategy should be autodiscovered.
|
|
{
|
|
Type: "SomeOtherType",
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: "SomeOtherReason",
|
|
Message: "Some other message",
|
|
LastUpdateTime: metav1.Now(),
|
|
Frontend: &configv1alpha1.CredentialIssuerFrontend{
|
|
Type: configv1alpha1.ImpersonationProxyFrontendType,
|
|
ImpersonationProxyInfo: &configv1alpha1.ImpersonationProxyInfo{
|
|
Endpoint: "https://impersonation-proxy-endpoint.test",
|
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString(testConciergeCA.Bundle()),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: onlyIssuerOIDCDiscoveryResponse,
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://impersonation-proxy-endpoint.test"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=1`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: %s
|
|
server: https://impersonation-proxy-endpoint.test
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://impersonation-proxy-endpoint.test
|
|
- --concierge-ca-bundle-data=%s
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
base64.StdEncoding.EncodeToString(testConciergeCA.Bundle()),
|
|
base64.StdEncoding.EncodeToString(testConciergeCA.Bundle()),
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)),
|
|
)
|
|
},
|
|
},
|
|
{
|
|
name: "autodetect impersonation proxy with auto-discovered JWT authenticator",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
&configv1alpha1.CredentialIssuer{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
|
|
Status: configv1alpha1.CredentialIssuerStatus{
|
|
Strategies: []configv1alpha1.CredentialIssuerStrategy{
|
|
{
|
|
Type: "SomeType",
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: "SomeReason",
|
|
Message: "Some message",
|
|
LastUpdateTime: metav1.Now(),
|
|
Frontend: &configv1alpha1.CredentialIssuerFrontend{
|
|
Type: configv1alpha1.ImpersonationProxyFrontendType,
|
|
ImpersonationProxyInfo: &configv1alpha1.ImpersonationProxyInfo{
|
|
Endpoint: "https://impersonation-proxy-endpoint.test",
|
|
CertificateAuthorityData: "dGVzdC1jb25jaWVyZ2UtY2E=",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Type: "SomeOtherType",
|
|
Status: configv1alpha1.SuccessStrategyStatus,
|
|
Reason: "SomeOtherReason",
|
|
Message: "Some other message",
|
|
LastUpdateTime: metav1.Now(),
|
|
Frontend: &configv1alpha1.CredentialIssuerFrontend{
|
|
Type: configv1alpha1.ImpersonationProxyFrontendType,
|
|
ImpersonationProxyInfo: &configv1alpha1.ImpersonationProxyInfo{
|
|
Endpoint: "https://some-other-impersonation-endpoint",
|
|
CertificateAuthorityData: "dGVzdC1jb25jaWVyZ2UtY2E=",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: onlyIssuerOIDCDiscoveryResponse,
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in impersonation proxy mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://impersonation-proxy-endpoint.test"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: dGVzdC1jb25jaWVyZ2UtY2E=
|
|
server: https://impersonation-proxy-endpoint.test
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://impersonation-proxy-endpoint.test
|
|
- --concierge-ca-bundle-data=dGVzdC1jb25jaWVyZ2UtY2E=
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "Find LDAP IDP in IDP discovery document, output ldap related flags",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"}
|
|
]
|
|
}`),
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "Find OIDC IDP in IDP discovery document, output oidc related flags",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
- --upstream-identity-provider-name=some-oidc-idp
|
|
- --upstream-identity-provider-type=oidc
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "empty IDP list in IDP discovery document",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": []
|
|
}`),
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "Supervisor discovery section is not listed in OIDC discovery document",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: onlyIssuerOIDCDiscoveryResponse,
|
|
idpsDiscoveryStatusCode: http.StatusBadRequest, // IDPs endpoint shouldn't be called by this test
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "IDP discovery endpoint is not listed in OIDC discovery document within the Supervisor discovery section",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: func(issuerURL string) string {
|
|
return here.Docf(`{
|
|
"issuer": "%s",
|
|
"discovery.supervisor.pinniped.dev/v1alpha1": {
|
|
"wrong-key": "some-value"
|
|
}
|
|
}`, issuerURL)
|
|
},
|
|
idpsDiscoveryStatusCode: http.StatusBadRequest, // IDP discovery endpoint shouldn't be called by this test
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "when all upstream IDP related flags are sent, pass them through without performing IDP discovery",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--upstream-identity-provider-name=some-oidc-idp",
|
|
"--upstream-identity-provider-type=oidc",
|
|
"--upstream-identity-provider-flow=foobar",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryStatusCode: http.StatusNotFound, // should not get called by the client in this case
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
- --upstream-identity-provider-name=some-oidc-idp
|
|
- --upstream-identity-provider-type=oidc
|
|
- --upstream-identity-provider-flow=foobar
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "when all upstream IDP related flags are sent, pass them through even when IDP discovery shows a different IDP",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--upstream-identity-provider-name=some-oidc-idp",
|
|
"--upstream-identity-provider-type=oidc",
|
|
"--upstream-identity-provider-flow=foobar",
|
|
}
|
|
},
|
|
conciergeObjects: func(issuerCABundle string, issuerURL string) []runtime.Object {
|
|
return []runtime.Object{
|
|
credentialIssuer(),
|
|
jwtAuthenticator(issuerCABundle, issuerURL),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-other-ldap-idp", "type": "ldap"}
|
|
]
|
|
}`),
|
|
wantLogs: func(issuerCABundle string, issuerURL string) []string {
|
|
return []string{
|
|
`"level"=0 "msg"="discovered CredentialIssuer" "name"="test-credential-issuer"`,
|
|
`"level"=0 "msg"="discovered Concierge operating in TokenCredentialRequest API mode"`,
|
|
`"level"=0 "msg"="discovered Concierge endpoint" "endpoint"="https://fake-server-url-value"`,
|
|
`"level"=0 "msg"="discovered Concierge certificate authority bundle" "roots"=0`,
|
|
`"level"=0 "msg"="discovered JWTAuthenticator" "name"="test-authenticator"`,
|
|
fmt.Sprintf(`"level"=0 "msg"="discovered OIDC issuer" "issuer"="%s"`, issuerURL),
|
|
`"level"=0 "msg"="discovered OIDC audience" "audience"="test-audience"`,
|
|
`"level"=0 "msg"="discovered OIDC CA bundle" "roots"=1`,
|
|
}
|
|
},
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --enable-concierge
|
|
- --concierge-api-group-suffix=pinniped.dev
|
|
- --concierge-authenticator-name=test-authenticator
|
|
- --concierge-authenticator-type=jwt
|
|
- --concierge-endpoint=https://fake-server-url-value
|
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --request-audience=test-audience
|
|
- --upstream-identity-provider-name=some-oidc-idp
|
|
- --upstream-identity-provider-type=oidc
|
|
- --upstream-identity-provider-flow=foobar
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery still works when --no-concierge is used",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"}
|
|
]
|
|
}`),
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery resolves ambiguity when type is specified but name is not",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"},
|
|
{"name": "some-oidc-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery resolves ambiguity when name is specified but type is not",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-name", "some-ldap-idp",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"},
|
|
{"name": "some-oidc-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery when both name and type are specified but flow is not and a matching IDP is found",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-name", "some-ldap-idp",
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"},
|
|
{"name": "some-oidc-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery when flow is specified and no flows were returned by discovery uses the specified flow",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-flow", "foobar",
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap"},
|
|
{"name": "some-oidc-idp", "type": "oidc"},
|
|
{"name": "some-other-oidc-idp", "type": "oidc"}
|
|
]
|
|
}`),
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
- --upstream-identity-provider-flow=foobar
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery when flow is specified and it matches a flow returned by discovery uses the specified flow",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-flow", "cli_password",
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap", "flows": ["some_flow", "cli_password", "some_other_flow"]}
|
|
]
|
|
}`),
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
- --upstream-identity-provider-flow=cli_password
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
{
|
|
name: "supervisor upstream IDP discovery when no flow is specified but there is only one flow returned by discovery uses the discovered flow",
|
|
args: func(issuerCABundle string, issuerURL string) []string {
|
|
f := testutil.WriteStringToTempFile(t, "testca-*.pem", issuerCABundle)
|
|
return []string{
|
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
|
"--skip-validation",
|
|
"--no-concierge",
|
|
"--oidc-issuer", issuerURL,
|
|
"--oidc-ca-bundle", f.Name(),
|
|
"--upstream-identity-provider-type", "ldap",
|
|
}
|
|
},
|
|
oidcDiscoveryResponse: happyOIDCDiscoveryResponse,
|
|
idpsDiscoveryResponse: here.Docf(`{
|
|
"pinniped_identity_providers": [
|
|
{"name": "some-ldap-idp", "type": "ldap", "flows": ["cli_password"]}
|
|
]
|
|
}`),
|
|
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
|
return here.Docf(`
|
|
apiVersion: v1
|
|
clusters:
|
|
- cluster:
|
|
certificate-authority-data: ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
|
server: https://fake-server-url-value
|
|
name: kind-cluster-pinniped
|
|
contexts:
|
|
- context:
|
|
cluster: kind-cluster-pinniped
|
|
user: kind-user-pinniped
|
|
name: kind-context-pinniped
|
|
current-context: kind-context-pinniped
|
|
kind: Config
|
|
preferences: {}
|
|
users:
|
|
- name: kind-user-pinniped
|
|
user:
|
|
exec:
|
|
apiVersion: client.authentication.k8s.io/v1beta1
|
|
args:
|
|
- login
|
|
- oidc
|
|
- --issuer=%s
|
|
- --client-id=pinniped-cli
|
|
- --scopes=offline_access,openid,pinniped:request-audience
|
|
- --ca-bundle-data=%s
|
|
- --upstream-identity-provider-name=some-ldap-idp
|
|
- --upstream-identity-provider-type=ldap
|
|
- --upstream-identity-provider-flow=cli_password
|
|
command: '.../path/to/pinniped'
|
|
env: []
|
|
provideClusterInfo: true
|
|
`,
|
|
issuerURL,
|
|
base64.StdEncoding.EncodeToString([]byte(issuerCABundle)))
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var issuerEndpointPtr *string
|
|
issuerCABundle, issuerEndpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("content-type", "application/json")
|
|
switch r.URL.Path {
|
|
case "/.well-known/openid-configuration":
|
|
jsonResponseBody := "{}"
|
|
if tt.oidcDiscoveryResponse != nil {
|
|
jsonResponseBody = tt.oidcDiscoveryResponse(*issuerEndpointPtr)
|
|
}
|
|
if tt.oidcDiscoveryStatusCode == 0 {
|
|
tt.oidcDiscoveryStatusCode = http.StatusOK
|
|
}
|
|
w.WriteHeader(tt.oidcDiscoveryStatusCode)
|
|
_, err = w.Write([]byte(jsonResponseBody))
|
|
require.NoError(t, err)
|
|
case "/v1alpha1/pinniped_identity_providers":
|
|
jsonResponseBody := tt.idpsDiscoveryResponse
|
|
if tt.idpsDiscoveryResponse == "" {
|
|
jsonResponseBody = "{}"
|
|
}
|
|
if tt.idpsDiscoveryStatusCode == 0 {
|
|
tt.idpsDiscoveryStatusCode = http.StatusOK
|
|
}
|
|
w.WriteHeader(tt.idpsDiscoveryStatusCode)
|
|
_, err = w.Write([]byte(jsonResponseBody))
|
|
require.NoError(t, err)
|
|
default:
|
|
t.Fatalf("tried to call issuer at a path that wasn't one of the expected discovery endpoints.")
|
|
}
|
|
})
|
|
issuerEndpointPtr = &issuerEndpoint
|
|
|
|
testLog := testlogger.New(t)
|
|
cmd := kubeconfigCommand(kubeconfigDeps{
|
|
getPathToSelf: func() (string, error) {
|
|
if tt.getPathToSelfErr != nil {
|
|
return "", tt.getPathToSelfErr
|
|
}
|
|
return ".../path/to/pinniped", nil
|
|
},
|
|
getClientset: func(clientConfig clientcmd.ClientConfig, apiGroupSuffix string) (conciergeclientset.Interface, error) {
|
|
if tt.wantAPIGroupSuffix == "" {
|
|
require.Equal(t, "pinniped.dev", apiGroupSuffix) // "pinniped.dev" = api group suffix default
|
|
} else {
|
|
require.Equal(t, tt.wantAPIGroupSuffix, apiGroupSuffix)
|
|
}
|
|
if tt.getClientsetErr != nil {
|
|
return nil, tt.getClientsetErr
|
|
}
|
|
fake := fakeconciergeclientset.NewSimpleClientset()
|
|
if tt.conciergeObjects != nil {
|
|
fake = fakeconciergeclientset.NewSimpleClientset(tt.conciergeObjects(issuerCABundle, issuerEndpoint)...)
|
|
}
|
|
if len(tt.conciergeReactions) > 0 {
|
|
fake.ReactionChain = append(tt.conciergeReactions, fake.ReactionChain...)
|
|
}
|
|
return fake, nil
|
|
},
|
|
log: testLog,
|
|
})
|
|
require.NotNil(t, cmd)
|
|
|
|
var stdout, stderr bytes.Buffer
|
|
cmd.SetOut(&stdout)
|
|
cmd.SetErr(&stderr)
|
|
|
|
cmd.SetArgs(tt.args(issuerCABundle, issuerEndpoint))
|
|
|
|
err := cmd.Execute()
|
|
if tt.wantError {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
var expectedLogs []string
|
|
if tt.wantLogs != nil {
|
|
expectedLogs = tt.wantLogs(issuerCABundle, issuerEndpoint)
|
|
}
|
|
testLog.Expect(expectedLogs)
|
|
|
|
expectedStdout := ""
|
|
if tt.wantStdout != nil {
|
|
expectedStdout = tt.wantStdout(issuerCABundle, issuerEndpoint)
|
|
}
|
|
require.Equal(t, expectedStdout, stdout.String(), "unexpected stdout")
|
|
|
|
expectedStderr := ""
|
|
if tt.wantStderr != nil {
|
|
expectedStderr = tt.wantStderr(issuerCABundle, issuerEndpoint)
|
|
}
|
|
require.Equal(t, expectedStderr, stderr.String(), "unexpected stderr")
|
|
})
|
|
}
|
|
}
|