Merge pull request #1389 from vmware-tanzu/error_assertions
Accept both old and new cert error strings on MacOS in test assertions
This commit is contained in:
commit
d2afdfaf9a
@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
@ -107,7 +107,7 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
wantLogs func(string, string) []string
|
||||
wantError bool
|
||||
wantStdout func(string, string) string
|
||||
wantStderr func(string, string) string
|
||||
wantStderr func(string, string) testutil.RequireErrorStringFunc
|
||||
wantOptionsCount int
|
||||
wantAPIGroupSuffix string
|
||||
}{
|
||||
@ -164,8 +164,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -177,8 +177,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -189,8 +189,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not load --kubeconfig: stat ./does/not/exist: no such file or directory` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -202,8 +202,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: could not load --kubeconfig/--kubeconfig-context: no such context "invalid"` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not load --kubeconfig/--kubeconfig-context: no such context "invalid"` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -215,8 +215,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: could not load --kubeconfig/--kubeconfig-context: no such cluster "invalid-cluster"` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not load --kubeconfig/--kubeconfig-context: no such cluster "invalid-cluster"` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -228,8 +228,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: could not load --kubeconfig/--kubeconfig-context: no such user "invalid-user"` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not load --kubeconfig/--kubeconfig-context: no such user "invalid-user"` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -241,8 +241,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not configure Kubernetes client: some kube error` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -253,8 +253,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: no CredentialIssuers were found` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: no CredentialIssuers were found` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -271,8 +271,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: credentialissuers.config.concierge.pinniped.dev "does-not-exist" not found` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: credentialissuers.config.concierge.pinniped.dev "does-not-exist" not found` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -295,8 +295,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: webhookauthenticators.authentication.concierge.pinniped.dev "test-authenticator" not found` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: webhookauthenticators.authentication.concierge.pinniped.dev "test-authenticator" not found` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -319,8 +319,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: jwtauthenticators.authentication.concierge.pinniped.dev "test-authenticator" not found` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: jwtauthenticators.authentication.concierge.pinniped.dev "test-authenticator" not found` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -343,8 +343,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: invalid authenticator type "invalid", supported values are "webhook" and "jwt"` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: invalid authenticator type "invalid", supported values are "webhook" and "jwt"` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -374,8 +374,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: failed to list JWTAuthenticator objects for autodiscovery: some list error` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: failed to list JWTAuthenticator objects for autodiscovery: some list error` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -405,8 +405,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: failed to list WebhookAuthenticator objects for autodiscovery: some list error` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: failed to list WebhookAuthenticator objects for autodiscovery: some list error` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -427,8 +427,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: no authenticators were found` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: no authenticators were found` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -457,8 +457,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: multiple authenticators were found, so the --concierge-authenticator-type/--concierge-authenticator-name flags must be specified` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -491,8 +491,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: could not autodiscover --concierge-mode` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not autodiscover --concierge-mode` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -553,8 +553,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: autodiscovered Concierge CA bundle is invalid: illegal base64 data at input byte 7` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -580,8 +580,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: could not autodiscover --oidc-issuer and none was provided` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not autodiscover --oidc-issuer and none was provided` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -635,8 +635,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: tried to autodiscover --oidc-ca-bundle, but JWTAuthenticator test-authenticator has invalid spec.tls.certificateAuthorityData: illegal base64 data at input byte 7` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -675,8 +675,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: request audience is not allowed to include the substring '.pinniped.dev': some-test-audience.pinniped.dev-invalid-substring` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: request audience is not allowed to include the substring '.pinniped.dev': some-test-audience.pinniped.dev-invalid-substring` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -706,8 +706,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: request audience is not allowed to include the substring '.pinniped.dev': some-test-audience.pinniped.dev-invalid-substring` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: request audience is not allowed to include the substring '.pinniped.dev': some-test-audience.pinniped.dev-invalid-substring` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -738,8 +738,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: could not determine the Pinniped executable path: some OS error` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: could not determine the Pinniped executable path: some OS error` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -767,8 +767,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: only one of --static-token and --static-token-env can be specified` + "\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: only one of --static-token and --static-token-env can be specified` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -779,8 +779,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -811,8 +811,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return "Error: while fetching OIDC discovery data from issuer: 400 Bad Request: {}\n"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString("Error: while fetching OIDC discovery data from issuer: 400 Bad Request: {}\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -847,8 +847,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return fmt.Sprintf(
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantSprintfErrorString(
|
||||
"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)
|
||||
},
|
||||
@ -882,8 +882,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString("Error: unable to fetch IDP discovery data from issuer: unexpected http response status: 400 Bad Request\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -920,10 +920,10 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: multiple Supervisor upstream identity providers were found, ` +
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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"
|
||||
`Found these upstreams: [{"name":"some-ldap-idp","type":"ldap"},{"name":"some-oidc-idp","type":"oidc"}]` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -956,8 +956,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString("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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -989,8 +989,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString("Error: unable to fetch IDP discovery data from issuer: could not parse response JSON: invalid character 'h' in literal true (expecting 'r')\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1025,8 +1025,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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\": %s\n", issuerURL, testutil.X509UntrustedCertError("Acme Co"))
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantX509UntrustedCertErrorString(fmt.Sprintf("Error: while fetching OIDC discovery data from issuer: Get \"%s/.well-known/openid-configuration\": %%s\n", issuerURL), "Acme Co")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1063,8 +1063,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1102,8 +1102,8 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: while forming request to IDP discovery URL: parse "https%://illegal_url": first path segment in URL cannot contain colon` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1128,9 +1128,9 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1156,10 +1156,10 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: multiple Supervisor upstream identity providers of type "ldap" were found,` +
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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"
|
||||
` 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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1184,10 +1184,10 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
wantError: true,
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) string {
|
||||
return `Error: multiple Supervisor upstream identity providers with name "my-idp" were found,` +
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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"
|
||||
` Found these upstreams: [{"name":"my-idp","type":"ldap"},{"name":"my-idp","type":"oidc"},{"name":"some-other-oidc-idp","type":"oidc"}]` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1211,9 +1211,9 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1236,9 +1236,9 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: no Supervisor upstream identity providers of type "ldap" were found.` +
|
||||
` Found these upstreams: [{"name":"some-oidc-idp","type":"oidc"}]` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1262,9 +1262,9 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1287,9 +1287,9 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`Error: no Supervisor upstream identity providers with name "my-nonexistent-idp" were found.` +
|
||||
` Found these upstreams: [{"name":"some-oidc-idp","type":"oidc"}]` + "\n")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1312,9 +1312,9 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
]
|
||||
}`),
|
||||
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"
|
||||
wantStderr: func(issuerCABundle string, issuerURL string) testutil.RequireErrorStringFunc {
|
||||
return testutil.WantExactErrorString(`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")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -3015,11 +3015,12 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
require.Equal(t, expectedStdout, stdout.String(), "unexpected stdout")
|
||||
|
||||
expectedStderr := ""
|
||||
actualStderr := stderr.String()
|
||||
if tt.wantStderr != nil {
|
||||
expectedStderr = tt.wantStderr(issuerCABundle, issuerEndpoint)
|
||||
testutil.RequireErrorString(t, actualStderr, tt.wantStderr(issuerCABundle, issuerEndpoint))
|
||||
} else {
|
||||
require.Empty(t, actualStderr, "unexpected stderr")
|
||||
}
|
||||
require.Equal(t, expectedStderr, stderr.String(), "unexpected stderr")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -124,7 +124,6 @@ require (
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.0 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.6.4 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.5 // indirect
|
||||
|
1
go.sum
1
go.sum
@ -537,7 +537,6 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package jwtcachefiller
|
||||
@ -188,7 +188,7 @@ func TestController(t *testing.T) {
|
||||
syncKey controllerlib.Key
|
||||
jwtAuthenticators []runtime.Object
|
||||
wantClose bool
|
||||
wantErr string
|
||||
wantErr testutil.RequireErrorStringFunc
|
||||
wantLogs []string
|
||||
wantCacheEntries int
|
||||
wantUsernameClaim string
|
||||
@ -350,7 +350,7 @@ func TestController(t *testing.T) {
|
||||
Spec: *missingTLSJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantErr: `failed to build jwt authenticator: could not initialize provider: Get "` + goodIssuer + `/.well-known/openid-configuration": ` + testutil.X509UntrustedCertError("Acme Co"),
|
||||
wantErr: testutil.WantX509UntrustedCertErrorString(`failed to build jwt authenticator: could not initialize provider: Get "`+goodIssuer+`/.well-known/openid-configuration": %s`, "Acme Co"),
|
||||
},
|
||||
{
|
||||
name: "invalid jwt authenticator CA",
|
||||
@ -363,7 +363,7 @@ func TestController(t *testing.T) {
|
||||
Spec: *invalidTLSJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantErr: "failed to build jwt authenticator: invalid TLS configuration: illegal base64 data at input byte 7",
|
||||
wantErr: testutil.WantExactErrorString("failed to build jwt authenticator: invalid TLS configuration: illegal base64 data at input byte 7"),
|
||||
},
|
||||
}
|
||||
|
||||
@ -391,8 +391,8 @@ func TestController(t *testing.T) {
|
||||
|
||||
syncCtx := controllerlib.Context{Context: ctx, Key: tt.syncKey}
|
||||
|
||||
if err := controllerlib.TestSync(t, controller, syncCtx); tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
if err := controllerlib.TestSync(t, controller, syncCtx); tt.wantErr != nil {
|
||||
testutil.RequireErrorStringFromErr(t, err, tt.wantErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@ -490,9 +490,8 @@ func TestController(t *testing.T) {
|
||||
rsp, authenticated, err = cachedAuthenticator.AuthenticateToken(context.Background(), jwt)
|
||||
return !isNotInitialized(err), nil
|
||||
})
|
||||
if test.wantErrorRegexp != "" {
|
||||
require.Error(t, err)
|
||||
require.Regexp(t, test.wantErrorRegexp, err.Error())
|
||||
if test.wantErr != nil {
|
||||
testutil.RequireErrorStringFromErr(t, err, test.wantErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.wantResponse, rsp)
|
||||
@ -528,7 +527,7 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtSignature func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string)
|
||||
wantResponse *authenticator.Response
|
||||
wantAuthenticated bool
|
||||
wantErrorRegexp string
|
||||
wantErr testutil.RequireErrorStringFunc
|
||||
distributedGroupsClaimURL string
|
||||
} {
|
||||
tests := []struct {
|
||||
@ -537,7 +536,7 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtSignature func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string)
|
||||
wantResponse *authenticator.Response
|
||||
wantAuthenticated bool
|
||||
wantErrorRegexp string
|
||||
wantErr testutil.RequireErrorStringFunc
|
||||
distributedGroupsClaimURL string
|
||||
}{
|
||||
{
|
||||
@ -594,14 +593,14 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtClaims: func(claims *jwt.Claims, groups *interface{}, username *string) {
|
||||
},
|
||||
distributedGroupsClaimURL: issuer + "/not_found_claim_source",
|
||||
wantErrorRegexp: `oidc: could not expand distributed claims: while getting distributed claim "` + expectedGroupsClaim + `": error while getting distributed claim JWT: 404 Not Found`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: could not expand distributed claims: while getting distributed claim "` + expectedGroupsClaim + `": error while getting distributed claim JWT: 404 Not Found`),
|
||||
},
|
||||
{
|
||||
name: "distributed groups doesn't return the right claim",
|
||||
jwtClaims: func(claims *jwt.Claims, groups *interface{}, username *string) {
|
||||
},
|
||||
distributedGroupsClaimURL: issuer + "/wrong_claim_source",
|
||||
wantErrorRegexp: `oidc: could not expand distributed claims: jwt returned by distributed claim endpoint "` + issuer + `/wrong_claim_source" did not contain claim: `,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: could not expand distributed claims: jwt returned by distributed claim endpoint "` + issuer + `/wrong_claim_source" did not contain claim: `),
|
||||
},
|
||||
{
|
||||
name: "good token with groups as string",
|
||||
@ -633,7 +632,7 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtClaims: func(_ *jwt.Claims, groups *interface{}, username *string) {
|
||||
*groups = map[string]string{"not an array": "or a string"}
|
||||
},
|
||||
wantErrorRegexp: "oidc: parse groups claim \"" + expectedGroupsClaim + "\": json: cannot unmarshal object into Go value of type string",
|
||||
wantErr: testutil.WantMatchingErrorString("oidc: parse groups claim \"" + expectedGroupsClaim + "\": json: cannot unmarshal object into Go value of type string"),
|
||||
},
|
||||
{
|
||||
name: "bad token with wrong issuer",
|
||||
@ -648,42 +647,42 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||
claims.Audience = nil
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \[\]`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: expected audience "some-audience" got \[\]`),
|
||||
},
|
||||
{
|
||||
name: "bad token with wrong audience",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||
claims.Audience = []string{"wrong-audience"}
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \["wrong-audience"\]`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: expected audience "some-audience" got \["wrong-audience"\]`),
|
||||
},
|
||||
{
|
||||
name: "bad token with nbf in the future",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||
claims.NotBefore = jwt.NewNumericDate(time.Date(3020, 2, 3, 4, 5, 6, 7, time.UTC))
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: current time .* before the nbf \(not before\) time: 3020-.*`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: current time .* before the nbf \(not before\) time: 3020-.*`),
|
||||
},
|
||||
{
|
||||
name: "bad token with exp in past",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||
claims.Expiry = jwt.NewNumericDate(time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC))
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: .+`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: token is expired \(Token Expiry: .+`),
|
||||
},
|
||||
{
|
||||
name: "bad token without exp",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||
claims.Expiry = nil
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: .+`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: token is expired \(Token Expiry: .+`),
|
||||
},
|
||||
{
|
||||
name: "token does not have username claim",
|
||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||
*username = ""
|
||||
},
|
||||
wantErrorRegexp: `oidc: parse username claims "` + expectedUsernameClaim + `": claim not present`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: parse username claims "` + expectedUsernameClaim + `": claim not present`),
|
||||
},
|
||||
{
|
||||
name: "signing key is wrong",
|
||||
@ -693,7 +692,7 @@ func testTableForAuthenticateTokenTests(
|
||||
require.NoError(t, err)
|
||||
*algo = jose.ES256
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: failed to verify signature: failed to verify id token signature`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: failed to verify signature: failed to verify id token signature`),
|
||||
},
|
||||
{
|
||||
name: "signing algo is unsupported",
|
||||
@ -703,7 +702,7 @@ func testTableForAuthenticateTokenTests(
|
||||
require.NoError(t, err)
|
||||
*algo = jose.ES384
|
||||
},
|
||||
wantErrorRegexp: `oidc: verify token: oidc: id token signed with unsupported algorithm, expected \["RS256" "ES256"\] got "ES384"`,
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: id token signed with unsupported algorithm, expected \["RS256" "ES256"\] got "ES384"`),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
@ -125,3 +126,63 @@ func requireSecurityHeaders(t *testing.T, response *httptest.ResponseRecorder) {
|
||||
// This check is more relaxed since Fosite can override the base header we set.
|
||||
require.Contains(t, response.Header().Get("Cache-Control"), "no-store")
|
||||
}
|
||||
|
||||
type RequireErrorStringFunc func(t *testing.T, actualErrorStr string)
|
||||
|
||||
// RequireErrorStringFromErr can be used to make assertions about errors in tests.
|
||||
func RequireErrorStringFromErr(t *testing.T, actualError error, requireFunc RequireErrorStringFunc) {
|
||||
require.Error(t, actualError)
|
||||
requireFunc(t, actualError.Error())
|
||||
}
|
||||
|
||||
// RequireErrorString can be used to make assertions about error strings in tests.
|
||||
func RequireErrorString(t *testing.T, actualErrorStr string, requireFunc RequireErrorStringFunc) {
|
||||
requireFunc(t, actualErrorStr)
|
||||
}
|
||||
|
||||
// WantExactErrorString can be used to set up an expected value for an error string in a test table.
|
||||
// Use when you want to express that the expected string must be an exact match.
|
||||
func WantExactErrorString(wantErrStr string) RequireErrorStringFunc {
|
||||
return func(t *testing.T, actualErrorStr string) {
|
||||
require.Equal(t, wantErrStr, actualErrorStr)
|
||||
}
|
||||
}
|
||||
|
||||
// WantSprintfErrorString can be used to set up an expected value for an error string in a test table.
|
||||
// Use when you want to express that an expected string built using fmt.Sprintf semantics must be an exact match.
|
||||
func WantSprintfErrorString(wantErrSprintfSpecifier string, a ...interface{}) RequireErrorStringFunc {
|
||||
wantErrStr := fmt.Sprintf(wantErrSprintfSpecifier, a...)
|
||||
return func(t *testing.T, actualErrorStr string) {
|
||||
require.Equal(t, wantErrStr, actualErrorStr)
|
||||
}
|
||||
}
|
||||
|
||||
// WantMatchingErrorString can be used to set up an expected value for an error string in a test table.
|
||||
// Use when you want to express that the expected regexp must be a match.
|
||||
func WantMatchingErrorString(wantErrRegexp string) RequireErrorStringFunc {
|
||||
return func(t *testing.T, actualErrorStr string) {
|
||||
require.Regexp(t, wantErrRegexp, actualErrorStr)
|
||||
}
|
||||
}
|
||||
|
||||
// WantX509UntrustedCertErrorString can be used to set up an expected value for an error string in a test table.
|
||||
// expectedErrorFormatString must contain exactly one formatting verb, which should usually be %s, which will
|
||||
// be replaced by the platform-specific X509 untrusted certs error string and then compared against expectedCommonName.
|
||||
func WantX509UntrustedCertErrorString(expectedErrorFormatSpecifier string, expectedCommonName string) RequireErrorStringFunc {
|
||||
// Starting in Go 1.18.1, and until it was fixed in Go 1.19.5, Go on MacOS had an incorrect error string.
|
||||
// We don't care which error string was returned, as long as it is either the normal error string from
|
||||
// the Go x509 library, or the error string that was accidentally returned from the Go x509 library in
|
||||
// those versions of Go on MacOS which had the bug.
|
||||
return func(t *testing.T, actualErrorStr string) {
|
||||
// This is the MacOS error string starting in Go 1.18.1, and until it was fixed in Go 1.19.5.
|
||||
macOSErr := fmt.Sprintf(`x509: “%s” certificate is not trusted`, expectedCommonName)
|
||||
// This is the normal Go x509 library error string.
|
||||
standardErr := `x509: certificate signed by unknown authority`
|
||||
allowedErrorStrings := []string{
|
||||
fmt.Sprintf(expectedErrorFormatSpecifier, macOSErr),
|
||||
fmt.Sprintf(expectedErrorFormatSpecifier, standardErr),
|
||||
}
|
||||
// Allow either.
|
||||
require.Contains(t, allowedErrorStrings, actualErrorStr)
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright 2022 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func X509UntrustedCertError(commonName string) string {
|
||||
if runtime.GOOS == "darwin" {
|
||||
// Golang use's macos' x509 verification APIs on darwin.
|
||||
// This output slightly different error messages than golang's
|
||||
// own x509 verification.
|
||||
return fmt.Sprintf(`x509: “%s” certificate is not trusted`, commonName)
|
||||
}
|
||||
return `x509: certificate signed by unknown authority`
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package upstreamldap
|
||||
@ -179,7 +179,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
searchMocks func(conn *mockldapconn.MockConn)
|
||||
bindEndUserMocks func(conn *mockldapconn.MockConn)
|
||||
dialError error
|
||||
wantError string
|
||||
wantError testutil.RequireErrorStringFunc
|
||||
wantToSkipDial bool
|
||||
wantAuthResponse *authenticators.Response
|
||||
wantUnauthenticated bool
|
||||
@ -711,7 +711,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
Return(exampleGroupSearchResult, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: "found 0 values for attribute \"some-attribute-to-check-during-refresh\" while searching for user \"some-upstream-username\", but expected 1 result",
|
||||
wantError: testutil.WantExactErrorString("found 0 values for attribute \"some-attribute-to-check-during-refresh\" while searching for user \"some-upstream-username\", but expected 1 result"),
|
||||
},
|
||||
{
|
||||
name: "when dial fails",
|
||||
@ -719,7 +719,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
password: testUpstreamPassword,
|
||||
providerConfig: providerConfig(nil),
|
||||
dialError: errors.New("some dial error"),
|
||||
wantError: fmt.Sprintf(`error dialing host "%s": some dial error`, testHost),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "%s": some dial error`, testHost),
|
||||
},
|
||||
{
|
||||
name: "when the UsernameAttribute is dn and there is not a user search filter provided",
|
||||
@ -730,7 +730,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
p.UserSearch.Filter = ""
|
||||
}),
|
||||
wantToSkipDial: true,
|
||||
wantError: `must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`,
|
||||
wantError: testutil.WantExactErrorString(`must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`),
|
||||
},
|
||||
{
|
||||
name: "when binding as the bind user returns an error",
|
||||
@ -741,7 +741,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
conn.EXPECT().Bind(testBindUsername, testBindPassword).Return(errors.New("some bind error")).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`error binding as "%s" before user search: some bind error`, testBindUsername),
|
||||
wantError: testutil.WantSprintfErrorString(`error binding as "%s" before user search: some bind error`, testBindUsername),
|
||||
},
|
||||
{
|
||||
name: "when searching for the user returns an error",
|
||||
@ -753,7 +753,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
conn.EXPECT().Search(expectedUserSearch(nil)).Return(nil, errors.New("some user search error")).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: `error searching for user: some user search error`,
|
||||
wantError: testutil.WantExactErrorString(`error searching for user: some user search error`),
|
||||
},
|
||||
{
|
||||
name: "when searching for the user's groups returns an error",
|
||||
@ -767,7 +767,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
Return(nil, errors.New("some group search error")).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`error searching for group memberships for user with DN "%s": some group search error`, testUserSearchResultDNValue),
|
||||
wantError: testutil.WantSprintfErrorString(`error searching for group memberships for user with DN "%s": some group search error`, testUserSearchResultDNValue),
|
||||
},
|
||||
{
|
||||
name: "when searching for the user returns no results",
|
||||
@ -798,7 +798,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`searching for user "%s" resulted in 2 search results, but expected 1 result`, testUpstreamUsername),
|
||||
wantError: testutil.WantSprintfErrorString(`searching for user "%s" resulted in 2 search results, but expected 1 result`, testUpstreamUsername),
|
||||
},
|
||||
{
|
||||
name: "when searching for the user returns a user without a DN",
|
||||
@ -814,7 +814,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`searching for user "%s" resulted in search result without DN`, testUpstreamUsername),
|
||||
wantError: testutil.WantSprintfErrorString(`searching for user "%s" resulted in search result without DN`, testUpstreamUsername),
|
||||
},
|
||||
{
|
||||
name: "when searching for the user's groups returns a group without a DN",
|
||||
@ -845,7 +845,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(
|
||||
wantError: testutil.WantSprintfErrorString(
|
||||
`searching for group memberships for user with DN "%s" resulted in search result without DN`,
|
||||
testUserSearchResultDNValue),
|
||||
},
|
||||
@ -868,7 +868,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(
|
||||
wantError: testutil.WantSprintfErrorString(
|
||||
`found 0 values for attribute "%s" while searching for user "%s", but expected 1 result`,
|
||||
testUserSearchUsernameAttribute, testUpstreamUsername),
|
||||
},
|
||||
@ -901,7 +901,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(
|
||||
wantError: testutil.WantSprintfErrorString(
|
||||
`error searching for group memberships for user with DN "%s": found 0 values for attribute "%s" while searching for user "%s", but expected 1 result`,
|
||||
testUserSearchResultDNValue, testGroupSearchGroupNameAttribute, testUserSearchResultDNValue),
|
||||
},
|
||||
@ -928,7 +928,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(
|
||||
wantError: testutil.WantSprintfErrorString(
|
||||
`found 2 values for attribute "%s" while searching for user "%s", but expected 1 result`,
|
||||
testUserSearchUsernameAttribute, testUpstreamUsername),
|
||||
},
|
||||
@ -964,7 +964,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(
|
||||
wantError: testutil.WantSprintfErrorString(
|
||||
`error searching for group memberships for user with DN "%s": found 2 values for attribute "%s" while searching for user "%s", but expected 1 result`,
|
||||
testUserSearchResultDNValue, testGroupSearchGroupNameAttribute, testUserSearchResultDNValue),
|
||||
},
|
||||
@ -988,7 +988,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(
|
||||
wantError: testutil.WantSprintfErrorString(
|
||||
`found empty value for attribute "%s" while searching for user "%s", but expected value to be non-empty`,
|
||||
testUserSearchUsernameAttribute, testUpstreamUsername),
|
||||
},
|
||||
@ -1021,7 +1021,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(
|
||||
wantError: testutil.WantSprintfErrorString(
|
||||
`error searching for group memberships for user with DN "%s": found empty value for attribute "%s" while searching for user "%s", but expected value to be non-empty`,
|
||||
testUserSearchResultDNValue, testGroupSearchGroupNameAttribute, testUserSearchResultDNValue),
|
||||
},
|
||||
@ -1044,7 +1044,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`found 0 values for attribute "%s" while searching for user "%s", but expected 1 result`, testUserSearchUIDAttribute, testUpstreamUsername),
|
||||
wantError: testutil.WantSprintfErrorString(`found 0 values for attribute "%s" while searching for user "%s", but expected 1 result`, testUserSearchUIDAttribute, testUpstreamUsername),
|
||||
},
|
||||
{
|
||||
name: "when searching for the user returns a user with too many values for the expected UID attribute",
|
||||
@ -1069,7 +1069,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`found 2 values for attribute "%s" while searching for user "%s", but expected 1 result`, testUserSearchUIDAttribute, testUpstreamUsername),
|
||||
wantError: testutil.WantSprintfErrorString(`found 2 values for attribute "%s" while searching for user "%s", but expected 1 result`, testUserSearchUIDAttribute, testUpstreamUsername),
|
||||
},
|
||||
{
|
||||
name: "when searching for the user returns a user with an empty value for the expected UID attribute",
|
||||
@ -1091,7 +1091,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
}, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`found empty value for attribute "%s" while searching for user "%s", but expected value to be non-empty`, testUserSearchUIDAttribute, testUpstreamUsername),
|
||||
wantError: testutil.WantSprintfErrorString(`found empty value for attribute "%s" while searching for user "%s", but expected value to be non-empty`, testUserSearchUIDAttribute, testUpstreamUsername),
|
||||
},
|
||||
{
|
||||
name: "when the group search has an override func that errors",
|
||||
@ -1109,7 +1109,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
Return(exampleGroupSearchResult, nil).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf("error finding groups for user %s: some error", testUserSearchResultDNValue),
|
||||
wantError: testutil.WantSprintfErrorString("error finding groups for user %s: some error", testUserSearchResultDNValue),
|
||||
},
|
||||
{
|
||||
name: "when binding as the found user returns an error",
|
||||
@ -1127,7 +1127,7 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
conn.EXPECT().Bind(testUserSearchResultDNValue, testUpstreamPassword).Return(errors.New("some bind error")).Times(1)
|
||||
},
|
||||
skipDryRunAuthenticateUser: true,
|
||||
wantError: fmt.Sprintf(`error binding for user "%s" using provided password against DN "%s": some bind error`, testUpstreamUsername, testUserSearchResultDNValue),
|
||||
wantError: testutil.WantSprintfErrorString(`error binding for user "%s" using provided password against DN "%s": some bind error`, testUpstreamUsername, testUserSearchResultDNValue),
|
||||
},
|
||||
{
|
||||
name: "when binding as the found user returns a specific invalid credentials error",
|
||||
@ -1194,8 +1194,8 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
authResponse, authenticated, err := ldapProvider.AuthenticateUser(context.Background(), tt.username, tt.password, tt.grantedScopes)
|
||||
require.Equal(t, !tt.wantToSkipDial, dialWasAttempted)
|
||||
switch {
|
||||
case tt.wantError != "":
|
||||
require.EqualError(t, err, tt.wantError)
|
||||
case tt.wantError != nil:
|
||||
testutil.RequireErrorStringFromErr(t, err, tt.wantError)
|
||||
require.False(t, authenticated)
|
||||
require.Nil(t, authResponse)
|
||||
case tt.wantUnauthenticated:
|
||||
@ -1226,8 +1226,8 @@ func TestEndUserAuthentication(t *testing.T) {
|
||||
authResponse, authenticated, err = ldapProvider.DryRunAuthenticateUser(context.Background(), tt.username, tt.grantedScopes)
|
||||
require.Equal(t, !tt.wantToSkipDial, dialWasAttempted)
|
||||
switch {
|
||||
case tt.wantError != "":
|
||||
require.EqualError(t, err, tt.wantError)
|
||||
case tt.wantError != nil:
|
||||
testutil.RequireErrorStringFromErr(t, err, tt.wantError)
|
||||
require.False(t, authenticated)
|
||||
require.Nil(t, authResponse)
|
||||
case tt.wantUnauthenticated:
|
||||
@ -1852,7 +1852,7 @@ func TestTestConnection(t *testing.T) {
|
||||
providerConfig *ProviderConfig
|
||||
setupMocks func(conn *mockldapconn.MockConn)
|
||||
dialError error
|
||||
wantError string
|
||||
wantError testutil.RequireErrorStringFunc
|
||||
wantToSkipDial bool
|
||||
}{
|
||||
{
|
||||
@ -1867,7 +1867,7 @@ func TestTestConnection(t *testing.T) {
|
||||
name: "when dial fails",
|
||||
providerConfig: providerConfig(nil),
|
||||
dialError: errors.New("some dial error"),
|
||||
wantError: fmt.Sprintf(`error dialing host "%s": some dial error`, testHost),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "%s": some dial error`, testHost),
|
||||
},
|
||||
{
|
||||
name: "when binding as the bind user returns an error",
|
||||
@ -1876,7 +1876,7 @@ func TestTestConnection(t *testing.T) {
|
||||
conn.EXPECT().Bind(testBindUsername, testBindPassword).Return(errors.New("some bind error")).Times(1)
|
||||
conn.EXPECT().Close().Times(1)
|
||||
},
|
||||
wantError: fmt.Sprintf(`error binding as "%s": some bind error`, testBindUsername),
|
||||
wantError: testutil.WantSprintfErrorString(`error binding as "%s": some bind error`, testBindUsername),
|
||||
},
|
||||
{
|
||||
name: "when the config is invalid",
|
||||
@ -1886,7 +1886,7 @@ func TestTestConnection(t *testing.T) {
|
||||
p.UserSearch.Filter = ""
|
||||
}),
|
||||
wantToSkipDial: true,
|
||||
wantError: `must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`,
|
||||
wantError: testutil.WantExactErrorString(`must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`),
|
||||
},
|
||||
}
|
||||
|
||||
@ -1917,8 +1917,8 @@ func TestTestConnection(t *testing.T) {
|
||||
require.Equal(t, !tt.wantToSkipDial, dialWasAttempted)
|
||||
|
||||
switch {
|
||||
case tt.wantError != "":
|
||||
require.EqualError(t, err, tt.wantError)
|
||||
case tt.wantError != nil:
|
||||
testutil.RequireErrorStringFromErr(t, err, tt.wantError)
|
||||
default:
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@ -2010,7 +2010,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
connProto LDAPConnectionProtocol
|
||||
caBundle []byte
|
||||
context context.Context
|
||||
wantError string
|
||||
wantError testutil.RequireErrorStringFunc
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
@ -2025,7 +2025,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: caForTestServerWithBadCertName.Bundle(),
|
||||
connProto: TLS,
|
||||
context: context.Background(),
|
||||
wantError: `LDAP Result Code 200 "Network Error": x509: certificate is valid for 10.2.3.4, not 127.0.0.1`,
|
||||
wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": x509: certificate is valid for 10.2.3.4, not 127.0.0.1`),
|
||||
},
|
||||
{
|
||||
name: "invalid CA bundle with TLS",
|
||||
@ -2033,7 +2033,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: []byte("not a ca bundle"),
|
||||
connProto: TLS,
|
||||
context: context.Background(),
|
||||
wantError: `LDAP Result Code 200 "Network Error": could not parse CA bundle`,
|
||||
wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": could not parse CA bundle`),
|
||||
},
|
||||
{
|
||||
name: "invalid CA bundle with StartTLS",
|
||||
@ -2041,7 +2041,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: []byte("not a ca bundle"),
|
||||
connProto: StartTLS,
|
||||
context: context.Background(),
|
||||
wantError: `LDAP Result Code 200 "Network Error": could not parse CA bundle`,
|
||||
wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": could not parse CA bundle`),
|
||||
},
|
||||
{
|
||||
name: "invalid host with TLS",
|
||||
@ -2049,7 +2049,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: testServerCABundle,
|
||||
connProto: TLS,
|
||||
context: context.Background(),
|
||||
wantError: `LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`,
|
||||
wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`),
|
||||
},
|
||||
{
|
||||
name: "invalid host with StartTLS",
|
||||
@ -2057,7 +2057,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: testServerCABundle,
|
||||
connProto: StartTLS,
|
||||
context: context.Background(),
|
||||
wantError: `LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`,
|
||||
wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`),
|
||||
},
|
||||
{
|
||||
name: "missing CA bundle when it is required because the host is not using a trusted CA",
|
||||
@ -2065,7 +2065,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: nil,
|
||||
connProto: TLS,
|
||||
context: context.Background(),
|
||||
wantError: fmt.Sprintf(`LDAP Result Code 200 "Network Error": %s`, testutil.X509UntrustedCertError("Acme Co")),
|
||||
wantError: testutil.WantX509UntrustedCertErrorString(`LDAP Result Code 200 "Network Error": %s`, "Acme Co"),
|
||||
},
|
||||
{
|
||||
name: "cannot connect to host",
|
||||
@ -2074,7 +2074,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: testServerCABundle,
|
||||
connProto: TLS,
|
||||
context: context.Background(),
|
||||
wantError: fmt.Sprintf(`LDAP Result Code 200 "Network Error": dial tcp %s: connect: connection refused`, recentlyClaimedHostAndPort),
|
||||
wantError: testutil.WantSprintfErrorString(`LDAP Result Code 200 "Network Error": dial tcp %s: connect: connection refused`, recentlyClaimedHostAndPort),
|
||||
},
|
||||
{
|
||||
name: "pays attention to the passed context",
|
||||
@ -2082,7 +2082,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: testServerCABundle,
|
||||
connProto: TLS,
|
||||
context: alreadyCancelledContext,
|
||||
wantError: fmt.Sprintf(`LDAP Result Code 200 "Network Error": dial tcp %s: operation was canceled`, testServerHostAndPort),
|
||||
wantError: testutil.WantSprintfErrorString(`LDAP Result Code 200 "Network Error": dial tcp %s: operation was canceled`, testServerHostAndPort),
|
||||
},
|
||||
{
|
||||
name: "unsupported connection protocol",
|
||||
@ -2090,7 +2090,7 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
caBundle: testServerCABundle,
|
||||
connProto: "bad usage of this type",
|
||||
context: alreadyCancelledContext,
|
||||
wantError: `LDAP Result Code 200 "Network Error": did not specify valid ConnectionProtocol`,
|
||||
wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": did not specify valid ConnectionProtocol`),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
@ -2106,9 +2106,9 @@ func TestRealTLSDialing(t *testing.T) {
|
||||
if conn != nil {
|
||||
defer conn.Close()
|
||||
}
|
||||
if tt.wantError != "" {
|
||||
if tt.wantError != nil {
|
||||
require.Nil(t, conn)
|
||||
require.EqualError(t, err, tt.wantError)
|
||||
testutil.RequireErrorStringFromErr(t, err, tt.wantError)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, conn)
|
||||
|
@ -487,9 +487,8 @@ func TestProviderConfig(t *testing.T) {
|
||||
unreachableServer bool
|
||||
returnStatusCodes []int
|
||||
returnErrBodies []string
|
||||
wantErr string
|
||||
wantErrRegexp string // use either wantErr or wantErrRegexp
|
||||
wantRetryableErrType bool // additionally assert error type when wantErr is non-empty
|
||||
wantErr testutil.RequireErrorStringFunc
|
||||
wantRetryableErrType bool // additionally assert error type when wantErr is non-empty
|
||||
wantNumRequests int
|
||||
wantTokenTypeHint string
|
||||
}{
|
||||
@ -542,7 +541,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusBadRequest, http.StatusBadRequest},
|
||||
returnErrBodies: []string{`{ "error":"invalid_client", "error_description":"unhappy" }`, `{ "error":"anything", "error_description":"unhappy" }`},
|
||||
wantErr: `server responded with status 400 with body: { "error":"anything", "error_description":"unhappy" }`,
|
||||
wantErr: testutil.WantExactErrorString(`server responded with status 400 with body: { "error":"anything", "error_description":"unhappy" }`),
|
||||
wantRetryableErrType: false,
|
||||
wantNumRequests: 2,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -552,7 +551,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusBadRequest},
|
||||
returnErrBodies: []string{`invalid JSON body`},
|
||||
wantErr: `error parsing response body "invalid JSON body" on response with status code 400: invalid character 'i' looking for beginning of value`,
|
||||
wantErr: testutil.WantExactErrorString(`error parsing response body "invalid JSON body" on response with status code 400: invalid character 'i' looking for beginning of value`),
|
||||
wantRetryableErrType: false,
|
||||
wantNumRequests: 1,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -562,7 +561,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusBadRequest},
|
||||
returnErrBodies: []string{``},
|
||||
wantErr: `error parsing response body "" on response with status code 400: unexpected end of JSON input`,
|
||||
wantErr: testutil.WantExactErrorString(`error parsing response body "" on response with status code 400: unexpected end of JSON input`),
|
||||
wantRetryableErrType: false,
|
||||
wantNumRequests: 1,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -572,7 +571,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusBadRequest, http.StatusForbidden},
|
||||
returnErrBodies: []string{`{ "error":"invalid_client", "error_description":"unhappy" }`, ""},
|
||||
wantErr: "server responded with status 403",
|
||||
wantErr: testutil.WantExactErrorString("server responded with status 403"),
|
||||
wantRetryableErrType: false,
|
||||
wantNumRequests: 2,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -582,7 +581,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusBadRequest},
|
||||
returnErrBodies: []string{`{ "error":"anything_else", "error_description":"unhappy" }`},
|
||||
wantErr: `server responded with status 400 with body: { "error":"anything_else", "error_description":"unhappy" }`,
|
||||
wantErr: testutil.WantExactErrorString(`server responded with status 400 with body: { "error":"anything_else", "error_description":"unhappy" }`),
|
||||
wantRetryableErrType: false,
|
||||
wantNumRequests: 1,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -592,7 +591,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusForbidden},
|
||||
returnErrBodies: []string{""},
|
||||
wantErr: "server responded with status 403",
|
||||
wantErr: testutil.WantExactErrorString("server responded with status 403"),
|
||||
wantRetryableErrType: false,
|
||||
wantNumRequests: 1,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -602,7 +601,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusServiceUnavailable}, // 503
|
||||
returnErrBodies: []string{""},
|
||||
wantErr: "retryable revocation error: server responded with status 503",
|
||||
wantErr: testutil.WantExactErrorString("retryable revocation error: server responded with status 503"),
|
||||
wantRetryableErrType: true,
|
||||
wantNumRequests: 1,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -612,7 +611,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.AccessTokenType,
|
||||
returnStatusCodes: []int{http.StatusBadRequest, http.StatusServiceUnavailable}, // 400, 503
|
||||
returnErrBodies: []string{`{ "error":"invalid_client", "error_description":"unhappy" }`, ""},
|
||||
wantErr: "retryable revocation error: server responded with status 503",
|
||||
wantErr: testutil.WantExactErrorString("retryable revocation error: server responded with status 503"),
|
||||
wantRetryableErrType: true,
|
||||
wantNumRequests: 2,
|
||||
wantTokenTypeHint: "access_token",
|
||||
@ -622,7 +621,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{http.StatusInternalServerError}, // 500
|
||||
returnErrBodies: []string{""},
|
||||
wantErr: "retryable revocation error: server responded with status 500",
|
||||
wantErr: testutil.WantExactErrorString("retryable revocation error: server responded with status 500"),
|
||||
wantRetryableErrType: true,
|
||||
wantNumRequests: 1,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -632,7 +631,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
tokenType: provider.RefreshTokenType,
|
||||
returnStatusCodes: []int{599}, // not defined by an RFC, but sometimes considered Network Connect Timeout Error
|
||||
returnErrBodies: []string{""},
|
||||
wantErr: "retryable revocation error: server responded with status 599",
|
||||
wantErr: testutil.WantExactErrorString("retryable revocation error: server responded with status 599"),
|
||||
wantRetryableErrType: true,
|
||||
wantNumRequests: 1,
|
||||
wantTokenTypeHint: "refresh_token",
|
||||
@ -641,7 +640,7 @@ func TestProviderConfig(t *testing.T) {
|
||||
name: "retryable error when the server cannot be reached",
|
||||
tokenType: provider.AccessTokenType,
|
||||
unreachableServer: true,
|
||||
wantErrRegexp: "^retryable revocation error: Post .*: dial tcp .*: connect: connection refused$",
|
||||
wantErr: testutil.WantMatchingErrorString("^retryable revocation error: Post .*: dial tcp .*: connect: connection refused$"),
|
||||
wantRetryableErrType: true,
|
||||
wantNumRequests: 0,
|
||||
},
|
||||
@ -709,13 +708,8 @@ func TestProviderConfig(t *testing.T) {
|
||||
require.Equal(t, tt.wantNumRequests, numRequests,
|
||||
"did not make expected number of requests to revocation endpoint")
|
||||
|
||||
if tt.wantErr != "" || tt.wantErrRegexp != "" { //nolint:nestif
|
||||
if tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
require.Regexp(t, tt.wantErrRegexp, err.Error())
|
||||
}
|
||||
if tt.wantErr != nil {
|
||||
testutil.RequireErrorStringFromErr(t, err, tt.wantErr)
|
||||
|
||||
if tt.wantRetryableErrType {
|
||||
require.ErrorAs(t, err, &provider.RetryableRevocationError{})
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package integration
|
||||
@ -75,7 +75,7 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
password string
|
||||
grantedScopes []string
|
||||
provider *upstreamldap.Provider
|
||||
wantError string
|
||||
wantError testutil.RequireErrorStringFunc
|
||||
wantAuthResponse *authenticators.Response
|
||||
wantUnauthenticated bool
|
||||
}{
|
||||
@ -248,7 +248,7 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.UserSearch.UsernameAttribute = "dn"
|
||||
p.UserSearch.Filter = ""
|
||||
})),
|
||||
wantError: `must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`,
|
||||
wantError: testutil.WantExactErrorString(`must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`),
|
||||
},
|
||||
{
|
||||
name: "group search disabled",
|
||||
@ -352,21 +352,21 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.BindUsername = "invalid-dn" })),
|
||||
wantError: `error binding as "invalid-dn" before user search: LDAP Result Code 34 "Invalid DN Syntax": invalid DN`,
|
||||
wantError: testutil.WantExactErrorString(`error binding as "invalid-dn" before user search: LDAP Result Code 34 "Invalid DN Syntax": invalid DN`),
|
||||
},
|
||||
{
|
||||
name: "when the bind user username is wrong",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.BindUsername = "cn=wrong,dc=pinniped,dc=dev" })),
|
||||
wantError: `error binding as "cn=wrong,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `,
|
||||
wantError: testutil.WantExactErrorString(`error binding as "cn=wrong,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `),
|
||||
},
|
||||
{
|
||||
name: "when the bind user password is wrong",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.BindPassword = "wrong-password" })),
|
||||
wantError: `error binding as "cn=admin,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `,
|
||||
wantError: testutil.WantExactErrorString(`error binding as "cn=admin,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `),
|
||||
},
|
||||
{
|
||||
name: "when the bind user username is wrong with StartTLS: example of an error after successful connection with StartTLS",
|
||||
@ -377,7 +377,7 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.ConnectionProtocol = upstreamldap.StartTLS
|
||||
p.BindUsername = "cn=wrong,dc=pinniped,dc=dev"
|
||||
})),
|
||||
wantError: `error binding as "cn=wrong,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `,
|
||||
wantError: testutil.WantExactErrorString(`error binding as "cn=wrong,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `),
|
||||
},
|
||||
{
|
||||
name: "when the end user password is wrong",
|
||||
@ -405,14 +405,14 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Filter = "*" })),
|
||||
wantError: `error searching for user: LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter`,
|
||||
wantError: testutil.WantExactErrorString(`error searching for user: LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter`),
|
||||
},
|
||||
{
|
||||
name: "when the group search filter does not compile",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.Filter = "*" })),
|
||||
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter`,
|
||||
wantError: testutil.WantExactErrorString(`error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter`),
|
||||
},
|
||||
{
|
||||
name: "when there are too many search results for the user",
|
||||
@ -421,14 +421,14 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
|
||||
p.UserSearch.Filter = "objectClass=*" // overly broad search filter
|
||||
})),
|
||||
wantError: `error searching for user: LDAP Result Code 4 "Size Limit Exceeded": `,
|
||||
wantError: testutil.WantExactErrorString(`error searching for user: LDAP Result Code 4 "Size Limit Exceeded": `),
|
||||
},
|
||||
{
|
||||
name: "when the server is unreachable with TLS",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.Host = "127.0.0.1:" + unusedLocalhostPort })),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": dial tcp 127.0.0.1:%s: connect: connection refused`, unusedLocalhostPort, unusedLocalhostPort),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": dial tcp 127.0.0.1:%s: connect: connection refused`, unusedLocalhostPort, unusedLocalhostPort),
|
||||
},
|
||||
{
|
||||
name: "when the server is unreachable with StartTLS",
|
||||
@ -438,14 +438,14 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.Host = "127.0.0.1:" + unusedLocalhostPort
|
||||
p.ConnectionProtocol = upstreamldap.StartTLS
|
||||
})),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": dial tcp 127.0.0.1:%s: connect: connection refused`, unusedLocalhostPort, unusedLocalhostPort),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": dial tcp 127.0.0.1:%s: connect: connection refused`, unusedLocalhostPort, unusedLocalhostPort),
|
||||
},
|
||||
{
|
||||
name: "when the server is not parsable with TLS",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.Host = "too:many:ports" })),
|
||||
wantError: `error dialing host "too:many:ports": LDAP Result Code 200 "Network Error": host "too:many:ports" is not a valid hostname or IP address`,
|
||||
wantError: testutil.WantExactErrorString(`error dialing host "too:many:ports": LDAP Result Code 200 "Network Error": host "too:many:ports" is not a valid hostname or IP address`),
|
||||
},
|
||||
{
|
||||
name: "when the server is not parsable with StartTLS",
|
||||
@ -456,14 +456,14 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.ConnectionProtocol = upstreamldap.StartTLS
|
||||
p.Host = "too:many:ports"
|
||||
})),
|
||||
wantError: `error dialing host "too:many:ports": LDAP Result Code 200 "Network Error": host "too:many:ports" is not a valid hostname or IP address`,
|
||||
wantError: testutil.WantExactErrorString(`error dialing host "too:many:ports": LDAP Result Code 200 "Network Error": host "too:many:ports" is not a valid hostname or IP address`),
|
||||
},
|
||||
{
|
||||
name: "when the CA bundle is not parsable with TLS",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.CABundle = []byte("invalid-pem") })),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": could not parse CA bundle`, ldapsLocalhostPort),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": could not parse CA bundle`, ldapsLocalhostPort),
|
||||
},
|
||||
{
|
||||
name: "when the CA bundle is not parsable with StartTLS",
|
||||
@ -474,14 +474,14 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.ConnectionProtocol = upstreamldap.StartTLS
|
||||
p.CABundle = []byte("invalid-pem")
|
||||
})),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": could not parse CA bundle`, ldapLocalhostPort),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": could not parse CA bundle`, ldapLocalhostPort),
|
||||
},
|
||||
{
|
||||
name: "when the CA bundle does not cause the host to be trusted with TLS",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.CABundle = nil })),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": %s`, ldapsLocalhostPort, testutil.X509UntrustedCertError("Pinniped Test")),
|
||||
wantError: testutil.WantX509UntrustedCertErrorString(fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": %%s`, ldapsLocalhostPort), "Pinniped Test"),
|
||||
},
|
||||
{
|
||||
name: "when the CA bundle does not cause the host to be trusted with StartTLS",
|
||||
@ -492,35 +492,35 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.ConnectionProtocol = upstreamldap.StartTLS
|
||||
p.CABundle = nil
|
||||
})),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": TLS handshake failed (%s)`, ldapLocalhostPort, testutil.X509UntrustedCertError("Pinniped Test")),
|
||||
wantError: testutil.WantX509UntrustedCertErrorString(fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": TLS handshake failed (%%s)`, ldapLocalhostPort), "Pinniped Test"),
|
||||
},
|
||||
{
|
||||
name: "when trying to use TLS to connect to a port which only supports StartTLS",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.Host = "127.0.0.1:" + ldapLocalhostPort })),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": EOF`, ldapLocalhostPort),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": EOF`, ldapLocalhostPort),
|
||||
},
|
||||
{
|
||||
name: "when trying to use StartTLS to connect to a port which only supports TLS",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.ConnectionProtocol = upstreamldap.StartTLS })),
|
||||
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": unable to read LDAP response packet: unexpected EOF`, ldapsLocalhostPort),
|
||||
wantError: testutil.WantSprintfErrorString(`error dialing host "127.0.0.1:%s": unable to read LDAP response packet: unexpected EOF`, ldapsLocalhostPort),
|
||||
},
|
||||
{
|
||||
name: "when the UsernameAttribute attribute has multiple values in the entry",
|
||||
username: "wally.ldap@example.com",
|
||||
password: "unused-because-error-is-before-bind",
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UsernameAttribute = "mail" })),
|
||||
wantError: `found 2 values for attribute "mail" while searching for user "wally.ldap@example.com", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 2 values for attribute "mail" while searching for user "wally.ldap@example.com", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the UIDAttribute attribute has multiple values in the entry",
|
||||
username: "wally",
|
||||
password: "unused-because-error-is-before-bind",
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UIDAttribute = "mail" })),
|
||||
wantError: `found 2 values for attribute "mail" while searching for user "wally", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 2 values for attribute "mail" while searching for user "wally", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the UsernameAttribute attribute is not found in the entry",
|
||||
@ -530,35 +530,35 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.UserSearch.Filter = "cn={}"
|
||||
p.UserSearch.UsernameAttribute = "attr-does-not-exist"
|
||||
})),
|
||||
wantError: `found 0 values for attribute "attr-does-not-exist" while searching for user "wally", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 0 values for attribute "attr-does-not-exist" while searching for user "wally", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the UIDAttribute attribute is not found in the entry",
|
||||
username: "wally",
|
||||
password: "unused-because-error-is-before-bind",
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UIDAttribute = "attr-does-not-exist" })),
|
||||
wantError: `found 0 values for attribute "attr-does-not-exist" while searching for user "wally", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 0 values for attribute "attr-does-not-exist" while searching for user "wally", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the UsernameAttribute has the wrong case",
|
||||
username: "Seal",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UsernameAttribute = "SN" })), // this is case-sensitive
|
||||
wantError: `found 0 values for attribute "SN" while searching for user "Seal", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 0 values for attribute "SN" while searching for user "Seal", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the UIDAttribute has the wrong case",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UIDAttribute = "SN" })), // this is case-sensitive
|
||||
wantError: `found 0 values for attribute "SN" while searching for user "pinny", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 0 values for attribute "SN" while searching for user "pinny", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the GroupNameAttribute has the wrong case",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.GroupNameAttribute = "CN" })), // this is case-sensitive
|
||||
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": found 0 values for attribute "CN" while searching for user "cn=pinny,ou=users,dc=pinniped,dc=dev", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": found 0 values for attribute "CN" while searching for user "cn=pinny,ou=users,dc=pinniped,dc=dev", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the UsernameAttribute is DN and has the wrong case",
|
||||
@ -568,7 +568,7 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
p.UserSearch.UsernameAttribute = "DN" // dn must be lower-case
|
||||
p.UserSearch.Filter = "cn={}"
|
||||
})),
|
||||
wantError: `found 0 values for attribute "DN" while searching for user "pinny", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 0 values for attribute "DN" while searching for user "pinny", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the UIDAttribute is DN and has the wrong case",
|
||||
@ -577,7 +577,7 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
|
||||
p.UserSearch.UIDAttribute = "DN" // dn must be lower-case
|
||||
})),
|
||||
wantError: `found 0 values for attribute "DN" while searching for user "pinny", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`found 0 values for attribute "DN" while searching for user "pinny", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the GroupNameAttribute is DN and has the wrong case",
|
||||
@ -586,35 +586,35 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
|
||||
p.GroupSearch.GroupNameAttribute = "DN" // dn must be lower-case
|
||||
})),
|
||||
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": found 0 values for attribute "DN" while searching for user "cn=pinny,ou=users,dc=pinniped,dc=dev", but expected 1 result`,
|
||||
wantError: testutil.WantExactErrorString(`error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": found 0 values for attribute "DN" while searching for user "cn=pinny,ou=users,dc=pinniped,dc=dev", but expected 1 result`),
|
||||
},
|
||||
{
|
||||
name: "when the user search base is invalid",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Base = "invalid-base" })),
|
||||
wantError: `error searching for user: LDAP Result Code 34 "Invalid DN Syntax": invalid DN`,
|
||||
wantError: testutil.WantExactErrorString(`error searching for user: LDAP Result Code 34 "Invalid DN Syntax": invalid DN`),
|
||||
},
|
||||
{
|
||||
name: "when the group search base is invalid",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.Base = "invalid-base" })),
|
||||
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 34 "Invalid DN Syntax": invalid DN`,
|
||||
wantError: testutil.WantExactErrorString(`error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 34 "Invalid DN Syntax": invalid DN`),
|
||||
},
|
||||
{
|
||||
name: "when the user search base does not exist",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Base = "ou=does-not-exist,dc=pinniped,dc=dev" })),
|
||||
wantError: `error searching for user: LDAP Result Code 32 "No Such Object": `,
|
||||
wantError: testutil.WantExactErrorString(`error searching for user: LDAP Result Code 32 "No Such Object": `),
|
||||
},
|
||||
{
|
||||
name: "when the group search base does not exist",
|
||||
username: "pinny",
|
||||
password: pinnyPassword,
|
||||
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.Base = "ou=does-not-exist,dc=pinniped,dc=dev" })),
|
||||
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 32 "No Such Object": `,
|
||||
wantError: testutil.WantExactErrorString(`error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 32 "No Such Object": `),
|
||||
},
|
||||
{
|
||||
name: "when the user search base causes no search results",
|
||||
@ -635,7 +635,7 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
username: "pinny",
|
||||
password: "",
|
||||
provider: upstreamldap.New(*providerConfig(nil)),
|
||||
wantError: `error binding for user "pinny" using provided password against DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 206 "Empty password not allowed by the client": ldap: empty password not allowed by the client`,
|
||||
wantError: testutil.WantExactErrorString(`error binding for user "pinny" using provided password against DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 206 "Empty password not allowed by the client": ldap: empty password not allowed by the client`),
|
||||
},
|
||||
{
|
||||
name: "when the user has no password in their entry",
|
||||
@ -655,8 +655,8 @@ func TestLDAPSearch_Parallel(t *testing.T) {
|
||||
authResponse, authenticated, err := tt.provider.AuthenticateUser(ctx, tt.username, tt.password, tt.grantedScopes)
|
||||
|
||||
switch {
|
||||
case tt.wantError != "":
|
||||
require.EqualError(t, err, tt.wantError)
|
||||
case tt.wantError != nil:
|
||||
testutil.RequireErrorStringFromErr(t, err, tt.wantError)
|
||||
require.False(t, authenticated, "expected the user not to be authenticated, but they were")
|
||||
require.Nil(t, authResponse)
|
||||
case tt.wantUnauthenticated:
|
||||
|
Loading…
Reference in New Issue
Block a user