Extract Supervisor IDP discovery endpoint types into apis package

This commit is contained in:
Ryan Richard 2021-08-17 15:23:03 -07:00
parent 964d16110e
commit 96474b3d99
11 changed files with 236 additions and 100 deletions

View File

@ -0,0 +1,29 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration
// Document returned by the .well-known/openid-configuration endpoint. It ignores all the standard OpenID Provider
// configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
}
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"`
}
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint.
type SupervisorPinnipedIDP struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows,omitempty"`
}

View File

@ -32,6 +32,7 @@ import (
conciergev1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1" conciergev1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1" configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
idpdiscoveryv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
conciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned" conciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
"go.pinniped.dev/internal/groupsuffix" "go.pinniped.dev/internal/groupsuffix"
) )
@ -98,24 +99,6 @@ type getKubeconfigParams struct {
credentialCachePathSet bool credentialCachePathSet bool
} }
type supervisorOIDCDiscoveryResponseWithV1Alpha1 struct {
SupervisorDiscovery SupervisorDiscoveryResponseV1Alpha1 `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
}
type SupervisorDiscoveryResponseV1Alpha1 struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
type supervisorIDPsDiscoveryResponseV1Alpha1 struct {
PinnipedIDPs []pinnipedIDPResponse `json:"pinniped_identity_providers"`
}
type pinnipedIDPResponse struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows,omitempty"`
}
func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command { func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
var ( var (
cmd = &cobra.Command{ cmd = &cobra.Command{
@ -818,7 +801,7 @@ func discoverIDPsDiscoveryEndpointURL(ctx context.Context, issuer string, httpCl
return "", fmt.Errorf("while fetching OIDC discovery data from issuer: %w", err) return "", fmt.Errorf("while fetching OIDC discovery data from issuer: %w", err)
} }
var body supervisorOIDCDiscoveryResponseWithV1Alpha1 var body idpdiscoveryv1alpha1.SupervisorOIDCDiscoveryResponse
err = discoveredProvider.Claims(&body) err = discoveredProvider.Claims(&body)
if err != nil { if err != nil {
return "", fmt.Errorf("while fetching OIDC discovery data from issuer: %w", err) return "", fmt.Errorf("while fetching OIDC discovery data from issuer: %w", err)
@ -827,7 +810,7 @@ func discoverIDPsDiscoveryEndpointURL(ctx context.Context, issuer string, httpCl
return body.SupervisorDiscovery.PinnipedIDPsEndpoint, nil return body.SupervisorDiscovery.PinnipedIDPsEndpoint, nil
} }
func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDPsEndpoint string, httpClient *http.Client) ([]pinnipedIDPResponse, error) { func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDPsEndpoint string, httpClient *http.Client) ([]idpdiscoveryv1alpha1.SupervisorPinnipedIDP, error) {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, pinnipedIDPsEndpoint, nil) request, err := http.NewRequestWithContext(ctx, http.MethodGet, pinnipedIDPsEndpoint, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("while forming request to IDP discovery URL: %w", err) return nil, fmt.Errorf("while forming request to IDP discovery URL: %w", err)
@ -849,7 +832,7 @@ func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDP
return nil, fmt.Errorf("unable to fetch IDP discovery data from issuer: could not read response body: %w", err) return nil, fmt.Errorf("unable to fetch IDP discovery data from issuer: could not read response body: %w", err)
} }
var body supervisorIDPsDiscoveryResponseV1Alpha1 var body idpdiscoveryv1alpha1.SupervisorIDPDiscoveryResponse
err = json.Unmarshal(rawBody, &body) err = json.Unmarshal(rawBody, &body)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to fetch IDP discovery data from issuer: could not parse response JSON: %w", err) return nil, fmt.Errorf("unable to fetch IDP discovery data from issuer: could not parse response JSON: %w", err)
@ -858,7 +841,7 @@ func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDP
return body.PinnipedIDPs, nil return body.PinnipedIDPs, nil
} }
func selectUpstreamIDPNameAndType(pinnipedIDPs []pinnipedIDPResponse, specifiedIDPName, specifiedIDPType string) (string, string, []string, error) { func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.SupervisorPinnipedIDP, specifiedIDPName, specifiedIDPType string) (string, string, []string, error) {
pinnipedIDPsString, _ := json.Marshal(pinnipedIDPs) pinnipedIDPsString, _ := json.Marshal(pinnipedIDPs)
var discoveredFlows []string var discoveredFlows []string
switch { switch {

View File

@ -0,0 +1,29 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration
// Document returned by the .well-known/openid-configuration endpoint. It ignores all the standard OpenID Provider
// configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
}
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"`
}
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint.
type SupervisorPinnipedIDP struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows,omitempty"`
}

View File

@ -0,0 +1,29 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration
// Document returned by the .well-known/openid-configuration endpoint. It ignores all the standard OpenID Provider
// configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
}
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"`
}
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint.
type SupervisorPinnipedIDP struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows,omitempty"`
}

View File

@ -0,0 +1,29 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration
// Document returned by the .well-known/openid-configuration endpoint. It ignores all the standard OpenID Provider
// configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
}
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"`
}
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint.
type SupervisorPinnipedIDP struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows,omitempty"`
}

View File

@ -0,0 +1,29 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration
// Document returned by the .well-known/openid-configuration endpoint. It ignores all the standard OpenID Provider
// configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
}
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"`
}
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint.
type SupervisorPinnipedIDP struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows,omitempty"`
}

View File

@ -0,0 +1,29 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration
// Document returned by the .well-known/openid-configuration endpoint. It ignores all the standard OpenID Provider
// configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
}
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"`
}
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint.
type SupervisorPinnipedIDP struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows,omitempty"`
}

View File

@ -9,6 +9,7 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
"go.pinniped.dev/internal/oidc" "go.pinniped.dev/internal/oidc"
) )
@ -41,20 +42,11 @@ type Metadata struct {
// vvv Custom vvv // vvv Custom vvv
SupervisorDiscovery SupervisorDiscoveryMetadataV1Alpha1 `json:"discovery.supervisor.pinniped.dev/v1alpha1"` SupervisorDiscovery v1alpha1.SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
// ^^^ Custom ^^^ // ^^^ Custom ^^^
} }
type SupervisorDiscoveryMetadataV1Alpha1 struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
}
type IdentityProviderMetadata struct {
Name string `json:"name"`
Type string `json:"type"`
}
// NewHandler returns an http.Handler that serves an OIDC discovery endpoint. // NewHandler returns an http.Handler that serves an OIDC discovery endpoint.
func NewHandler(issuerURL string) http.Handler { func NewHandler(issuerURL string) http.Handler {
oidcConfig := Metadata{ oidcConfig := Metadata{
@ -62,7 +54,7 @@ func NewHandler(issuerURL string) http.Handler {
AuthorizationEndpoint: issuerURL + oidc.AuthorizationEndpointPath, AuthorizationEndpoint: issuerURL + oidc.AuthorizationEndpointPath,
TokenEndpoint: issuerURL + oidc.TokenEndpointPath, TokenEndpoint: issuerURL + oidc.TokenEndpointPath,
JWKSURI: issuerURL + oidc.JWKSEndpointPath, JWKSURI: issuerURL + oidc.JWKSEndpointPath,
SupervisorDiscovery: SupervisorDiscoveryMetadataV1Alpha1{PinnipedIDPsEndpoint: issuerURL + oidc.PinnipedIDPsPathV1Alpha1}, SupervisorDiscovery: v1alpha1.SupervisorOIDCDiscoveryResponseIDPEndpoint{PinnipedIDPsEndpoint: issuerURL + oidc.PinnipedIDPsPathV1Alpha1},
ResponseTypesSupported: []string{"code"}, ResponseTypesSupported: []string{"code"},
ResponseModesSupported: []string{"query", "form_post"}, ResponseModesSupported: []string{"query", "form_post"},
SubjectTypesSupported: []string{"public"}, SubjectTypesSupported: []string{"public"},

View File

@ -4,13 +4,13 @@
package discovery package discovery
import ( import (
"encoding/json"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc" "go.pinniped.dev/internal/oidc"
) )
@ -24,7 +24,7 @@ func TestDiscovery(t *testing.T) {
wantStatus int wantStatus int
wantContentType string wantContentType string
wantBodyJSON interface{} wantBodyJSON string
wantBodyString string wantBodyString string
}{ }{
{ {
@ -34,22 +34,24 @@ func TestDiscovery(t *testing.T) {
path: "/some/path" + oidc.WellKnownEndpointPath, path: "/some/path" + oidc.WellKnownEndpointPath,
wantStatus: http.StatusOK, wantStatus: http.StatusOK,
wantContentType: "application/json", wantContentType: "application/json",
wantBodyJSON: &Metadata{ wantBodyJSON: here.Doc(`
Issuer: "https://some-issuer.com/some/path", {
AuthorizationEndpoint: "https://some-issuer.com/some/path/oauth2/authorize", "issuer": "https://some-issuer.com/some/path",
TokenEndpoint: "https://some-issuer.com/some/path/oauth2/token", "authorization_endpoint": "https://some-issuer.com/some/path/oauth2/authorize",
JWKSURI: "https://some-issuer.com/some/path/jwks.json", "token_endpoint": "https://some-issuer.com/some/path/oauth2/token",
SupervisorDiscovery: SupervisorDiscoveryMetadataV1Alpha1{ "jwks_uri": "https://some-issuer.com/some/path/jwks.json",
PinnipedIDPsEndpoint: "https://some-issuer.com/some/path/v1alpha1/pinniped_identity_providers", "response_types_supported": ["code"],
}, "response_modes_supported": ["query", "form_post"],
ResponseTypesSupported: []string{"code"}, "subject_types_supported": ["public"],
ResponseModesSupported: []string{"query", "form_post"}, "id_token_signing_alg_values_supported": ["ES256"],
SubjectTypesSupported: []string{"public"}, "token_endpoint_auth_methods_supported": ["client_secret_basic"],
IDTokenSigningAlgValuesSupported: []string{"ES256"}, "scopes_supported": ["openid", "offline"],
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic"}, "claims_supported": ["groups"],
ScopesSupported: []string{"openid", "offline"}, "discovery.supervisor.pinniped.dev/v1alpha1": {
ClaimsSupported: []string{"groups"}, "pinniped_identity_providers_endpoint": "https://some-issuer.com/some/path/v1alpha1/pinniped_identity_providers"
}, }
}
`),
}, },
{ {
name: "bad method", name: "bad method",
@ -73,10 +75,8 @@ func TestDiscovery(t *testing.T) {
require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type")) require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type"))
if test.wantBodyJSON != nil { if test.wantBodyJSON != "" {
wantJSON, err := json.Marshal(test.wantBodyJSON) require.JSONEq(t, test.wantBodyJSON, rsp.Body.String())
require.NoError(t, err)
require.JSONEq(t, string(wantJSON), rsp.Body.String())
} }
if test.wantBodyString != "" { if test.wantBodyString != "" {

View File

@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"sort" "sort"
"go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
"go.pinniped.dev/internal/oidc" "go.pinniped.dev/internal/oidc"
) )
@ -21,16 +22,6 @@ const (
flowCLIPassword = "cli_password" flowCLIPassword = "cli_password"
) )
type response struct {
IDPs []identityProviderResponse `json:"pinniped_identity_providers"`
}
type identityProviderResponse struct {
Name string `json:"name"`
Type string `json:"type"`
Flows []string `json:"flows"`
}
// NewHandler returns an http.Handler that serves the upstream IDP discovery endpoint. // NewHandler returns an http.Handler that serves the upstream IDP discovery endpoint.
func NewHandler(upstreamIDPs oidc.UpstreamIdentityProvidersLister) http.Handler { func NewHandler(upstreamIDPs oidc.UpstreamIdentityProvidersLister) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -54,13 +45,13 @@ func NewHandler(upstreamIDPs oidc.UpstreamIdentityProvidersLister) http.Handler
} }
func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte, error) { func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte, error) {
r := response{ r := v1alpha1.SupervisorIDPDiscoveryResponse{
IDPs: []identityProviderResponse{}, PinnipedIDPs: []v1alpha1.SupervisorPinnipedIDP{},
} }
// The cache of IDPs could change at any time, so always recalculate the list. // The cache of IDPs could change at any time, so always recalculate the list.
for _, provider := range upstreamIDPs.GetLDAPIdentityProviders() { for _, provider := range upstreamIDPs.GetLDAPIdentityProviders() {
r.IDPs = append(r.IDPs, identityProviderResponse{ r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{
Name: provider.GetName(), Name: provider.GetName(),
Type: idpDiscoveryTypeLDAP, Type: idpDiscoveryTypeLDAP,
Flows: []string{flowCLIPassword}, Flows: []string{flowCLIPassword},
@ -71,7 +62,7 @@ func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte,
if provider.AllowsPasswordGrant() { if provider.AllowsPasswordGrant() {
flows = append(flows, flowCLIPassword) flows = append(flows, flowCLIPassword)
} }
r.IDPs = append(r.IDPs, identityProviderResponse{ r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{
Name: provider.GetName(), Name: provider.GetName(),
Type: idpDiscoveryTypeOIDC, Type: idpDiscoveryTypeOIDC,
Flows: flows, Flows: flows,
@ -79,8 +70,8 @@ func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte,
} }
// Nobody like an API that changes the results unnecessarily. :) // Nobody like an API that changes the results unnecessarily. :)
sort.SliceStable(r.IDPs, func(i, j int) bool { sort.SliceStable(r.PinnipedIDPs, func(i, j int) bool {
return r.IDPs[i].Name < r.IDPs[j].Name return r.PinnipedIDPs[i].Name < r.PinnipedIDPs[j].Name
}) })
var b bytes.Buffer var b bytes.Buffer

View File

@ -4,13 +4,13 @@
package idpdiscovery package idpdiscovery
import ( import (
"encoding/json"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc" "go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/provider" "go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/testutil/oidctestutil" "go.pinniped.dev/internal/testutil/oidctestutil"
@ -25,8 +25,8 @@ func TestIDPDiscovery(t *testing.T) {
wantStatus int wantStatus int
wantContentType string wantContentType string
wantFirstResponseBodyJSON interface{} wantFirstResponseBodyJSON string
wantSecondResponseBodyJSON interface{} wantSecondResponseBodyJSON string
wantBodyString string wantBodyString string
}{ }{
{ {
@ -35,24 +35,24 @@ func TestIDPDiscovery(t *testing.T) {
path: "/some/path" + oidc.WellKnownEndpointPath, path: "/some/path" + oidc.WellKnownEndpointPath,
wantStatus: http.StatusOK, wantStatus: http.StatusOK,
wantContentType: "application/json", wantContentType: "application/json",
wantFirstResponseBodyJSON: &response{ wantFirstResponseBodyJSON: here.Doc(`{
IDPs: []identityProviderResponse{ "pinniped_identity_providers": [
{Name: "a-some-ldap-idp", Type: "ldap", Flows: []string{"cli_password"}}, {"name": "a-some-ldap-idp", "type": "ldap", "flows": ["cli_password"]},
{Name: "a-some-oidc-idp", Type: "oidc", Flows: []string{"browser_authcode"}}, {"name": "a-some-oidc-idp", "type": "oidc", "flows": ["browser_authcode"]},
{Name: "x-some-idp", Type: "ldap", Flows: []string{"cli_password"}}, {"name": "x-some-idp", "type": "ldap", "flows": ["cli_password"]},
{Name: "x-some-idp", Type: "oidc", Flows: []string{"browser_authcode"}}, {"name": "x-some-idp", "type": "oidc", "flows": ["browser_authcode"]},
{Name: "z-some-ldap-idp", Type: "ldap", Flows: []string{"cli_password"}}, {"name": "z-some-ldap-idp", "type": "ldap", "flows": ["cli_password"]},
{Name: "z-some-oidc-idp", Type: "oidc", Flows: []string{"browser_authcode", "cli_password"}}, {"name": "z-some-oidc-idp", "type": "oidc", "flows": ["browser_authcode", "cli_password"]}
}, ]
}, }`),
wantSecondResponseBodyJSON: &response{ wantSecondResponseBodyJSON: here.Doc(`{
IDPs: []identityProviderResponse{ "pinniped_identity_providers": [
{Name: "some-other-ldap-idp-1", Type: "ldap", Flows: []string{"cli_password"}}, {"name": "some-other-ldap-idp-1", "type": "ldap", "flows": ["cli_password"]},
{Name: "some-other-ldap-idp-2", Type: "ldap", Flows: []string{"cli_password"}}, {"name": "some-other-ldap-idp-2", "type": "ldap", "flows": ["cli_password"]},
{Name: "some-other-oidc-idp-1", Type: "oidc", Flows: []string{"browser_authcode", "cli_password"}}, {"name": "some-other-oidc-idp-1", "type": "oidc", "flows": ["browser_authcode", "cli_password"]},
{Name: "some-other-oidc-idp-2", Type: "oidc", Flows: []string{"browser_authcode"}}, {"name": "some-other-oidc-idp-2", "type": "oidc", "flows": ["browser_authcode"]}
}, ]
}, }`),
}, },
{ {
name: "bad method", name: "bad method",
@ -84,10 +84,8 @@ func TestIDPDiscovery(t *testing.T) {
require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type")) require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type"))
if test.wantFirstResponseBodyJSON != nil { if test.wantFirstResponseBodyJSON != "" {
wantJSON, err := json.Marshal(test.wantFirstResponseBodyJSON) require.JSONEq(t, test.wantFirstResponseBodyJSON, rsp.Body.String())
require.NoError(t, err)
require.JSONEq(t, string(wantJSON), rsp.Body.String())
} }
if test.wantBodyString != "" { if test.wantBodyString != "" {
@ -112,10 +110,8 @@ func TestIDPDiscovery(t *testing.T) {
require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type")) require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type"))
if test.wantFirstResponseBodyJSON != nil { if test.wantFirstResponseBodyJSON != "" {
wantJSON, err := json.Marshal(test.wantSecondResponseBodyJSON) require.JSONEq(t, test.wantSecondResponseBodyJSON, rsp.Body.String())
require.NoError(t, err)
require.JSONEq(t, string(wantJSON), rsp.Body.String())
} }
if test.wantBodyString != "" { if test.wantBodyString != "" {