Extract Supervisor authorize endpoint string constants into apis pkg

This commit is contained in:
Ryan Richard 2021-08-18 10:20:33 -07:00
parent 0089540b07
commit 04b8f0b455
17 changed files with 240 additions and 92 deletions

View File

@ -39,26 +39,26 @@ func (r IDPFlow) String() string {
return string(r) return string(r)
} }
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // OIDCDiscoveryResponse 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 // 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. // configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct { type OIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"` SupervisorDiscovery OIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
} }
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint. // OIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct { type OIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"` PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
} }
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint. // IDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct { type IDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"` PinnipedIDPs []PinnipedIDP `json:"pinniped_identity_providers"`
} }
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // PinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint. // identity provider discovery endpoint.
type SupervisorPinnipedIDP struct { type PinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type IDPType `json:"type"` Type IDPType `json:"type"`
Flows []IDPFlow `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`

View File

@ -0,0 +1,25 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
// Constants related to the Supervisor FederationDomain's authorization and token endpoints.
const (
// AuthorizeUsernameHeaderName is the name of the HTTP header which can be used to transmit a username
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizeUsernameHeaderName = "Pinniped-Username"
// AuthorizePasswordHeaderName is the name of the HTTP header which can be used to transmit a password
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizePasswordHeaderName = "Pinniped-Password" //nolint:gosec // this is not a credential
// AuthorizeUpstreamIDPNameParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the name of the desired identity provider.
AuthorizeUpstreamIDPNameParamName = "pinniped_idp_name"
// AuthorizeUpstreamIDPTypeParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the type of the desired identity provider.
AuthorizeUpstreamIDPTypeParamName = "pinniped_idp_type"
)

View File

@ -801,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 idpdiscoveryv1alpha1.SupervisorOIDCDiscoveryResponse var body idpdiscoveryv1alpha1.OIDCDiscoveryResponse
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)
@ -810,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) ([]idpdiscoveryv1alpha1.SupervisorPinnipedIDP, error) { func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDPsEndpoint string, httpClient *http.Client) ([]idpdiscoveryv1alpha1.PinnipedIDP, 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)
@ -832,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 idpdiscoveryv1alpha1.SupervisorIDPDiscoveryResponse var body idpdiscoveryv1alpha1.IDPDiscoveryResponse
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)
@ -841,7 +841,7 @@ func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDP
return body.PinnipedIDPs, nil return body.PinnipedIDPs, nil
} }
func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.SupervisorPinnipedIDP, specifiedIDPName, specifiedIDPType string) (string, idpdiscoveryv1alpha1.IDPType, []idpdiscoveryv1alpha1.IDPFlow, error) { func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.PinnipedIDP, specifiedIDPName, specifiedIDPType string) (string, idpdiscoveryv1alpha1.IDPType, []idpdiscoveryv1alpha1.IDPFlow, error) {
pinnipedIDPsString, _ := json.Marshal(pinnipedIDPs) pinnipedIDPsString, _ := json.Marshal(pinnipedIDPs)
var discoveredFlows []idpdiscoveryv1alpha1.IDPFlow var discoveredFlows []idpdiscoveryv1alpha1.IDPFlow
switch { switch {

View File

@ -39,26 +39,26 @@ func (r IDPFlow) String() string {
return string(r) return string(r)
} }
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // OIDCDiscoveryResponse 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 // 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. // configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct { type OIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"` SupervisorDiscovery OIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
} }
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint. // OIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct { type OIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"` PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
} }
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint. // IDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct { type IDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"` PinnipedIDPs []PinnipedIDP `json:"pinniped_identity_providers"`
} }
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // PinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint. // identity provider discovery endpoint.
type SupervisorPinnipedIDP struct { type PinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type IDPType `json:"type"` Type IDPType `json:"type"`
Flows []IDPFlow `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`

View File

@ -0,0 +1,25 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
// Constants related to the Supervisor FederationDomain's authorization and token endpoints.
const (
// AuthorizeUsernameHeaderName is the name of the HTTP header which can be used to transmit a username
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizeUsernameHeaderName = "Pinniped-Username"
// AuthorizePasswordHeaderName is the name of the HTTP header which can be used to transmit a password
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizePasswordHeaderName = "Pinniped-Password" //nolint:gosec // this is not a credential
// AuthorizeUpstreamIDPNameParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the name of the desired identity provider.
AuthorizeUpstreamIDPNameParamName = "pinniped_idp_name"
// AuthorizeUpstreamIDPTypeParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the type of the desired identity provider.
AuthorizeUpstreamIDPTypeParamName = "pinniped_idp_type"
)

View File

@ -39,26 +39,26 @@ func (r IDPFlow) String() string {
return string(r) return string(r)
} }
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // OIDCDiscoveryResponse 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 // 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. // configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct { type OIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"` SupervisorDiscovery OIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
} }
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint. // OIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct { type OIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"` PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
} }
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint. // IDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct { type IDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"` PinnipedIDPs []PinnipedIDP `json:"pinniped_identity_providers"`
} }
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // PinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint. // identity provider discovery endpoint.
type SupervisorPinnipedIDP struct { type PinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type IDPType `json:"type"` Type IDPType `json:"type"`
Flows []IDPFlow `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`

View File

@ -0,0 +1,25 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
// Constants related to the Supervisor FederationDomain's authorization and token endpoints.
const (
// AuthorizeUsernameHeaderName is the name of the HTTP header which can be used to transmit a username
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizeUsernameHeaderName = "Pinniped-Username"
// AuthorizePasswordHeaderName is the name of the HTTP header which can be used to transmit a password
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizePasswordHeaderName = "Pinniped-Password" //nolint:gosec // this is not a credential
// AuthorizeUpstreamIDPNameParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the name of the desired identity provider.
AuthorizeUpstreamIDPNameParamName = "pinniped_idp_name"
// AuthorizeUpstreamIDPTypeParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the type of the desired identity provider.
AuthorizeUpstreamIDPTypeParamName = "pinniped_idp_type"
)

View File

@ -39,26 +39,26 @@ func (r IDPFlow) String() string {
return string(r) return string(r)
} }
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // OIDCDiscoveryResponse 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 // 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. // configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct { type OIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"` SupervisorDiscovery OIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
} }
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint. // OIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct { type OIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"` PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
} }
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint. // IDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct { type IDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"` PinnipedIDPs []PinnipedIDP `json:"pinniped_identity_providers"`
} }
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // PinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint. // identity provider discovery endpoint.
type SupervisorPinnipedIDP struct { type PinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type IDPType `json:"type"` Type IDPType `json:"type"`
Flows []IDPFlow `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`

View File

@ -0,0 +1,25 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
// Constants related to the Supervisor FederationDomain's authorization and token endpoints.
const (
// AuthorizeUsernameHeaderName is the name of the HTTP header which can be used to transmit a username
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizeUsernameHeaderName = "Pinniped-Username"
// AuthorizePasswordHeaderName is the name of the HTTP header which can be used to transmit a password
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizePasswordHeaderName = "Pinniped-Password" //nolint:gosec // this is not a credential
// AuthorizeUpstreamIDPNameParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the name of the desired identity provider.
AuthorizeUpstreamIDPNameParamName = "pinniped_idp_name"
// AuthorizeUpstreamIDPTypeParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the type of the desired identity provider.
AuthorizeUpstreamIDPTypeParamName = "pinniped_idp_type"
)

View File

@ -39,26 +39,26 @@ func (r IDPFlow) String() string {
return string(r) return string(r)
} }
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // OIDCDiscoveryResponse 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 // 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. // configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct { type OIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"` SupervisorDiscovery OIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
} }
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint. // OIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct { type OIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"` PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
} }
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint. // IDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct { type IDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"` PinnipedIDPs []PinnipedIDP `json:"pinniped_identity_providers"`
} }
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // PinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint. // identity provider discovery endpoint.
type SupervisorPinnipedIDP struct { type PinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type IDPType `json:"type"` Type IDPType `json:"type"`
Flows []IDPFlow `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`

View File

@ -0,0 +1,25 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
// Constants related to the Supervisor FederationDomain's authorization and token endpoints.
const (
// AuthorizeUsernameHeaderName is the name of the HTTP header which can be used to transmit a username
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizeUsernameHeaderName = "Pinniped-Username"
// AuthorizePasswordHeaderName is the name of the HTTP header which can be used to transmit a password
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizePasswordHeaderName = "Pinniped-Password" //nolint:gosec // this is not a credential
// AuthorizeUpstreamIDPNameParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the name of the desired identity provider.
AuthorizeUpstreamIDPNameParamName = "pinniped_idp_name"
// AuthorizeUpstreamIDPTypeParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the type of the desired identity provider.
AuthorizeUpstreamIDPTypeParamName = "pinniped_idp_type"
)

View File

@ -39,26 +39,26 @@ func (r IDPFlow) String() string {
return string(r) return string(r)
} }
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // OIDCDiscoveryResponse 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 // 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. // configuration metadata and only picks out the portion related to Supervisor identity provider discovery.
type SupervisorOIDCDiscoveryResponse struct { type OIDCDiscoveryResponse struct {
SupervisorDiscovery SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"` SupervisorDiscovery OIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"`
} }
// SupervisorOIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint. // OIDCDiscoveryResponseIDPEndpoint contains the URL for the identity provider discovery endpoint.
type SupervisorOIDCDiscoveryResponseIDPEndpoint struct { type OIDCDiscoveryResponseIDPEndpoint struct {
PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"` PinnipedIDPsEndpoint string `json:"pinniped_identity_providers_endpoint"`
} }
// SupervisorIDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint. // IDPDiscoveryResponse is the response of a FederationDomain's identity provider discovery endpoint.
type SupervisorIDPDiscoveryResponse struct { type IDPDiscoveryResponse struct {
PinnipedIDPs []SupervisorPinnipedIDP `json:"pinniped_identity_providers"` PinnipedIDPs []PinnipedIDP `json:"pinniped_identity_providers"`
} }
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // PinnipedIDP describes a single identity provider as included in the response of a FederationDomain's
// identity provider discovery endpoint. // identity provider discovery endpoint.
type SupervisorPinnipedIDP struct { type PinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type IDPType `json:"type"` Type IDPType `json:"type"`
Flows []IDPFlow `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`

View File

@ -0,0 +1,25 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package oidc
// Constants related to the Supervisor FederationDomain's authorization and token endpoints.
const (
// AuthorizeUsernameHeaderName is the name of the HTTP header which can be used to transmit a username
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizeUsernameHeaderName = "Pinniped-Username"
// AuthorizePasswordHeaderName is the name of the HTTP header which can be used to transmit a password
// to the authorize endpoint when using a password flow, for example an OIDCIdentityProvider with a password grant
// or an LDAPIdentityProvider.
AuthorizePasswordHeaderName = "Pinniped-Password" //nolint:gosec // this is not a credential
// AuthorizeUpstreamIDPNameParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the name of the desired identity provider.
AuthorizeUpstreamIDPNameParamName = "pinniped_idp_name"
// AuthorizeUpstreamIDPTypeParamName is the name of the HTTP request parameter which can be used to help select which
// identity provider should be used for authentication by sending the type of the desired identity provider.
AuthorizeUpstreamIDPTypeParamName = "pinniped_idp_type"
)

View File

@ -17,6 +17,7 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
"k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/authenticator"
supervisoroidc "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/httputil/httperr" "go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/httputil/securityheader" "go.pinniped.dev/internal/httputil/securityheader"
"go.pinniped.dev/internal/oidc" "go.pinniped.dev/internal/oidc"
@ -28,11 +29,6 @@ import (
"go.pinniped.dev/pkg/oidcclient/pkce" "go.pinniped.dev/pkg/oidcclient/pkce"
) )
const (
CustomUsernameHeaderName = "Pinniped-Username"
CustomPasswordHeaderName = "Pinniped-Password" //nolint:gosec // this is not a credential
)
func NewHandler( func NewHandler(
downstreamIssuer string, downstreamIssuer string,
idpLister oidc.UpstreamIdentityProvidersLister, idpLister oidc.UpstreamIdentityProvidersLister,
@ -59,7 +55,7 @@ func NewHandler(
} }
if oidcUpstream != nil { if oidcUpstream != nil {
if len(r.Header.Values(CustomUsernameHeaderName)) > 0 { if len(r.Header.Values(supervisoroidc.AuthorizeUsernameHeaderName)) > 0 {
// The client set a username header, so they are trying to log in with a username/password. // The client set a username header, so they are trying to log in with a username/password.
return handleAuthRequestForOIDCUpstreamPasswordGrant(r, w, oauthHelperWithStorage, oidcUpstream) return handleAuthRequestForOIDCUpstreamPasswordGrant(r, w, oauthHelperWithStorage, oidcUpstream)
} }
@ -286,8 +282,8 @@ func makeDownstreamSessionAndReturnAuthcodeRedirect(
} }
func requireNonEmptyUsernameAndPasswordHeaders(r *http.Request, w http.ResponseWriter, oauthHelper fosite.OAuth2Provider, authorizeRequester fosite.AuthorizeRequester) (string, string, bool) { func requireNonEmptyUsernameAndPasswordHeaders(r *http.Request, w http.ResponseWriter, oauthHelper fosite.OAuth2Provider, authorizeRequester fosite.AuthorizeRequester) (string, string, bool) {
username := r.Header.Get(CustomUsernameHeaderName) username := r.Header.Get(supervisoroidc.AuthorizeUsernameHeaderName)
password := r.Header.Get(CustomPasswordHeaderName) password := r.Header.Get(supervisoroidc.AuthorizePasswordHeaderName)
if username == "" || password == "" { if username == "" || password == "" {
// Return an error according to OIDC spec 3.1.2.6 (second paragraph). // Return an error according to OIDC spec 3.1.2.6 (second paragraph).
err := errors.WithStack(fosite.ErrAccessDenied.WithHintf("Missing or blank username or password.")) err := errors.WithStack(fosite.ErrAccessDenied.WithHintf("Missing or blank username or password."))

View File

@ -42,7 +42,7 @@ type Metadata struct {
// vvv Custom vvv // vvv Custom vvv
SupervisorDiscovery v1alpha1.SupervisorOIDCDiscoveryResponseIDPEndpoint `json:"discovery.supervisor.pinniped.dev/v1alpha1"` v1alpha1.OIDCDiscoveryResponse
// ^^^ Custom ^^^ // ^^^ Custom ^^^
} }
@ -54,7 +54,11 @@ 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: v1alpha1.SupervisorOIDCDiscoveryResponseIDPEndpoint{PinnipedIDPsEndpoint: issuerURL + oidc.PinnipedIDPsPathV1Alpha1}, OIDCDiscoveryResponse: v1alpha1.OIDCDiscoveryResponse{
SupervisorDiscovery: v1alpha1.OIDCDiscoveryResponseIDPEndpoint{
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

@ -37,13 +37,11 @@ func NewHandler(upstreamIDPs oidc.UpstreamIdentityProvidersLister) http.Handler
} }
func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte, error) { func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte, error) {
r := v1alpha1.SupervisorIDPDiscoveryResponse{ r := v1alpha1.IDPDiscoveryResponse{PinnipedIDPs: []v1alpha1.PinnipedIDP{}}
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.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{ r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.PinnipedIDP{
Name: provider.GetName(), Name: provider.GetName(),
Type: v1alpha1.IDPTypeLDAP, Type: v1alpha1.IDPTypeLDAP,
Flows: []v1alpha1.IDPFlow{v1alpha1.IDPFlowCLIPassword}, Flows: []v1alpha1.IDPFlow{v1alpha1.IDPFlowCLIPassword},
@ -54,7 +52,7 @@ func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte,
if provider.AllowsPasswordGrant() { if provider.AllowsPasswordGrant() {
flows = append(flows, v1alpha1.IDPFlowCLIPassword) flows = append(flows, v1alpha1.IDPFlowCLIPassword)
} }
r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{ r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.PinnipedIDP{
Name: provider.GetName(), Name: provider.GetName(),
Type: v1alpha1.IDPTypeOIDC, Type: v1alpha1.IDPTypeOIDC,
Flows: flows, Flows: flows,

View File

@ -28,6 +28,7 @@ import (
"golang.org/x/term" "golang.org/x/term"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
supervisoroidc "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
"go.pinniped.dev/internal/httputil/httperr" "go.pinniped.dev/internal/httputil/httperr"
"go.pinniped.dev/internal/httputil/securityheader" "go.pinniped.dev/internal/httputil/securityheader"
"go.pinniped.dev/internal/oidc/provider" "go.pinniped.dev/internal/oidc/provider"
@ -52,11 +53,6 @@ const (
// we set this to be relatively long. // we set this to be relatively long.
overallTimeout = 90 * time.Minute overallTimeout = 90 * time.Minute
supervisorAuthorizeUpstreamNameParam = "pinniped_idp_name"
supervisorAuthorizeUpstreamTypeParam = "pinniped_idp_type"
supervisorAuthorizeUpstreamUsernameHeader = "Pinniped-Username"
supervisorAuthorizeUpstreamPasswordHeader = "Pinniped-Password" // nolint:gosec // this is not a credential
defaultLDAPUsernamePrompt = "Username: " defaultLDAPUsernamePrompt = "Username: "
defaultLDAPPasswordPrompt = "Password: " defaultLDAPPasswordPrompt = "Password: "
@ -389,8 +385,12 @@ func (h *handlerState) baseLogin() (*oidctypes.Token, error) {
h.pkce.Method(), h.pkce.Method(),
} }
if h.upstreamIdentityProviderName != "" { if h.upstreamIdentityProviderName != "" {
authorizeOptions = append(authorizeOptions, oauth2.SetAuthURLParam(supervisorAuthorizeUpstreamNameParam, h.upstreamIdentityProviderName)) authorizeOptions = append(authorizeOptions,
authorizeOptions = append(authorizeOptions, oauth2.SetAuthURLParam(supervisorAuthorizeUpstreamTypeParam, h.upstreamIdentityProviderType)) oauth2.SetAuthURLParam(supervisoroidc.AuthorizeUpstreamIDPNameParamName, h.upstreamIdentityProviderName),
)
authorizeOptions = append(authorizeOptions,
oauth2.SetAuthURLParam(supervisoroidc.AuthorizeUpstreamIDPTypeParamName, h.upstreamIdentityProviderType),
)
} }
// Choose the appropriate authorization and authcode exchange strategy. // Choose the appropriate authorization and authcode exchange strategy.
@ -445,8 +445,8 @@ func (h *handlerState) cliBasedAuth(authorizeOptions *[]oauth2.AuthCodeOption) (
if err != nil { if err != nil {
return nil, fmt.Errorf("could not build authorize request: %w", err) return nil, fmt.Errorf("could not build authorize request: %w", err)
} }
authReq.Header.Set(supervisorAuthorizeUpstreamUsernameHeader, username) authReq.Header.Set(supervisoroidc.AuthorizeUsernameHeaderName, username)
authReq.Header.Set(supervisorAuthorizeUpstreamPasswordHeader, password) authReq.Header.Set(supervisoroidc.AuthorizePasswordHeaderName, password)
authRes, err := h.httpClient.Do(authReq) authRes, err := h.httpClient.Do(authReq)
if err != nil { if err != nil {
return nil, fmt.Errorf("authorization response error: %w", err) return nil, fmt.Errorf("authorization response error: %w", err)