Extract Supervisor IDP discovery endpoint string constants into apis pkg

This commit is contained in:
Ryan Richard 2021-08-17 17:50:02 -07:00
parent 62c6d53a21
commit 0089540b07
9 changed files with 274 additions and 65 deletions

View File

@ -3,6 +3,42 @@
package v1alpha1 package v1alpha1
// IDPType are the strings that can be returned by the Supervisor identity provider discovery endpoint
// as the "type" of each returned identity provider.
type IDPType string
// IDPFlow are the strings that can be returned by the Supervisor identity provider discovery endpoint
// in the array of allowed client "flows" for each returned identity provider.
type IDPFlow string
const (
IDPTypeOIDC IDPType = "oidc"
IDPTypeLDAP IDPType = "ldap"
IDPFlowCLIPassword IDPFlow = "cli_password"
IDPFlowBrowserAuthcode IDPFlow = "browser_authcode"
)
// Equals is a convenience function for comparing an IDPType to a string.
func (r IDPType) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPType to a string.
func (r IDPType) String() string {
return string(r)
}
// Equals is a convenience function for comparing an IDPFlow to a string.
func (r IDPFlow) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPFlow to a string.
func (r IDPFlow) String() string {
return string(r)
}
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // 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 // 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.
@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct {
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // SupervisorPinnipedIDP 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 SupervisorPinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type IDPType `json:"type"`
Flows []string `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`
} }

View File

@ -138,8 +138,8 @@ func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
f.BoolVar(&flags.oidc.debugSessionCache, "oidc-debug-session-cache", false, "Print debug logs related to the OpenID Connect session cache") f.BoolVar(&flags.oidc.debugSessionCache, "oidc-debug-session-cache", false, "Print debug logs related to the OpenID Connect session cache")
f.StringVar(&flags.oidc.requestAudience, "oidc-request-audience", "", "Request a token with an alternate audience using RFC8693 token exchange") f.StringVar(&flags.oidc.requestAudience, "oidc-request-audience", "", "Request a token with an alternate audience using RFC8693 token exchange")
f.StringVar(&flags.oidc.upstreamIDPName, "upstream-identity-provider-name", "", "The name of the upstream identity provider used during login with a Supervisor") f.StringVar(&flags.oidc.upstreamIDPName, "upstream-identity-provider-name", "", "The name of the upstream identity provider used during login with a Supervisor")
f.StringVar(&flags.oidc.upstreamIDPType, "upstream-identity-provider-type", "", "The type of the upstream identity provider used during login with a Supervisor (e.g. 'oidc', 'ldap')") f.StringVar(&flags.oidc.upstreamIDPType, "upstream-identity-provider-type", "", fmt.Sprintf("The type of the upstream identity provider used during login with a Supervisor (e.g. '%s', '%s')", idpdiscoveryv1alpha1.IDPTypeOIDC, idpdiscoveryv1alpha1.IDPTypeLDAP))
f.StringVar(&flags.oidc.upstreamIDPFlow, "upstream-identity-provider-flow", "", "The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. 'cli_password', 'browser_authcode')") f.StringVar(&flags.oidc.upstreamIDPFlow, "upstream-identity-provider-flow", "", fmt.Sprintf("The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. '%s', '%s')", idpdiscoveryv1alpha1.IDPFlowCLIPassword, idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode))
f.StringVar(&flags.kubeconfigPath, "kubeconfig", os.Getenv("KUBECONFIG"), "Path to kubeconfig file") f.StringVar(&flags.kubeconfigPath, "kubeconfig", os.Getenv("KUBECONFIG"), "Path to kubeconfig file")
f.StringVar(&flags.kubeconfigContextOverride, "kubeconfig-context", "", "Kubeconfig context name (default: current active context)") f.StringVar(&flags.kubeconfigContextOverride, "kubeconfig-context", "", "Kubeconfig context name (default: current active context)")
f.BoolVar(&flags.skipValidate, "skip-validation", false, "Skip final validation of the kubeconfig (default: false)") f.BoolVar(&flags.skipValidate, "skip-validation", false, "Skip final validation of the kubeconfig (default: false)")
@ -772,8 +772,8 @@ func discoverSupervisorUpstreamIDP(ctx context.Context, flags *getKubeconfigPara
} }
flags.oidc.upstreamIDPName = selectedIDPName flags.oidc.upstreamIDPName = selectedIDPName
flags.oidc.upstreamIDPType = selectedIDPType flags.oidc.upstreamIDPType = selectedIDPType.String()
flags.oidc.upstreamIDPFlow = selectedIDPFlow flags.oidc.upstreamIDPFlow = selectedIDPFlow.String()
return nil return nil
} }
@ -841,15 +841,15 @@ func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDP
return body.PinnipedIDPs, nil return body.PinnipedIDPs, nil
} }
func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.SupervisorPinnipedIDP, specifiedIDPName, specifiedIDPType string) (string, string, []string, error) { func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.SupervisorPinnipedIDP, specifiedIDPName, specifiedIDPType string) (string, idpdiscoveryv1alpha1.IDPType, []idpdiscoveryv1alpha1.IDPFlow, error) {
pinnipedIDPsString, _ := json.Marshal(pinnipedIDPs) pinnipedIDPsString, _ := json.Marshal(pinnipedIDPs)
var discoveredFlows []string var discoveredFlows []idpdiscoveryv1alpha1.IDPFlow
switch { switch {
case specifiedIDPName != "" && specifiedIDPType != "": case specifiedIDPName != "" && specifiedIDPType != "":
// The user specified both name and type, so check to see if there exists an exact match. // The user specified both name and type, so check to see if there exists an exact match.
for _, idp := range pinnipedIDPs { for _, idp := range pinnipedIDPs {
if idp.Name == specifiedIDPName && idp.Type == specifiedIDPType { if idp.Name == specifiedIDPName && idp.Type.Equals(specifiedIDPType) {
return specifiedIDPName, specifiedIDPType, idp.Flows, nil return specifiedIDPName, idp.Type, idp.Flows, nil
} }
} }
return "", "", nil, fmt.Errorf( return "", "", nil, fmt.Errorf(
@ -858,8 +858,9 @@ func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.Supervisor
case specifiedIDPType != "": case specifiedIDPType != "":
// The user specified only a type, so check if there is only one of that type found. // The user specified only a type, so check if there is only one of that type found.
discoveredName := "" discoveredName := ""
var discoveredType idpdiscoveryv1alpha1.IDPType
for _, idp := range pinnipedIDPs { for _, idp := range pinnipedIDPs {
if idp.Type == specifiedIDPType { if idp.Type.Equals(specifiedIDPType) {
if discoveredName != "" { if discoveredName != "" {
return "", "", nil, fmt.Errorf( return "", "", nil, fmt.Errorf(
"multiple Supervisor upstream identity providers of type %q were found, "+ "multiple Supervisor upstream identity providers of type %q were found, "+
@ -868,6 +869,7 @@ func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.Supervisor
specifiedIDPType, pinnipedIDPsString) specifiedIDPType, pinnipedIDPsString)
} }
discoveredName = idp.Name discoveredName = idp.Name
discoveredType = idp.Type
discoveredFlows = idp.Flows discoveredFlows = idp.Flows
} }
} }
@ -876,10 +878,10 @@ func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.Supervisor
"no Supervisor upstream identity providers of type %q were found. "+ "no Supervisor upstream identity providers of type %q were found. "+
"Found these upstreams: %s", specifiedIDPType, pinnipedIDPsString) "Found these upstreams: %s", specifiedIDPType, pinnipedIDPsString)
} }
return discoveredName, specifiedIDPType, discoveredFlows, nil return discoveredName, discoveredType, discoveredFlows, nil
case specifiedIDPName != "": case specifiedIDPName != "":
// The user specified only a name, so check if there is only one of that name found. // The user specified only a name, so check if there is only one of that name found.
discoveredType := "" var discoveredType idpdiscoveryv1alpha1.IDPType
for _, idp := range pinnipedIDPs { for _, idp := range pinnipedIDPs {
if idp.Name == specifiedIDPName { if idp.Name == specifiedIDPName {
if discoveredType != "" { if discoveredType != "" {
@ -911,19 +913,19 @@ func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.Supervisor
} }
} }
func selectUpstreamIDPFlow(discoveredIDPFlows []string, selectedIDPName string, selectedIDPType string, specifiedFlow string) (string, error) { func selectUpstreamIDPFlow(discoveredIDPFlows []idpdiscoveryv1alpha1.IDPFlow, selectedIDPName string, selectedIDPType idpdiscoveryv1alpha1.IDPType, specifiedFlow string) (idpdiscoveryv1alpha1.IDPFlow, error) {
switch { switch {
case len(discoveredIDPFlows) == 0: case len(discoveredIDPFlows) == 0:
// No flows listed by discovery means that we are talking to an old Supervisor from before this feature existed. // No flows listed by discovery means that we are talking to an old Supervisor from before this feature existed.
// If the user specified a flow on the CLI flag then use it without validation, otherwise skip flow selection // If the user specified a flow on the CLI flag then use it without validation, otherwise skip flow selection
// and return empty string. // and return empty string.
return specifiedFlow, nil return idpdiscoveryv1alpha1.IDPFlow(specifiedFlow), nil
case specifiedFlow != "": case specifiedFlow != "":
// The user specified a flow, so validate that it is available for the selected IDP. // The user specified a flow, so validate that it is available for the selected IDP.
for _, flow := range discoveredIDPFlows { for _, flow := range discoveredIDPFlows {
if flow == specifiedFlow { if flow.Equals(specifiedFlow) {
// Found it, so use it as specified by the user. // Found it, so use it as specified by the user.
return specifiedFlow, nil return flow, nil
} }
} }
return "", fmt.Errorf( return "", fmt.Errorf(

View File

@ -24,6 +24,7 @@ import (
"k8s.io/client-go/transport" "k8s.io/client-go/transport"
"k8s.io/klog/v2/klogr" "k8s.io/klog/v2/klogr"
idpdiscoveryv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
"go.pinniped.dev/internal/execcredcache" "go.pinniped.dev/internal/execcredcache"
"go.pinniped.dev/internal/groupsuffix" "go.pinniped.dev/internal/groupsuffix"
"go.pinniped.dev/internal/plog" "go.pinniped.dev/internal/plog"
@ -38,13 +39,6 @@ func init() {
loginCmd.AddCommand(oidcLoginCommand(oidcLoginCommandRealDeps())) loginCmd.AddCommand(oidcLoginCommand(oidcLoginCommandRealDeps()))
} }
const (
idpTypeOIDC = "oidc"
idpTypeLDAP = "ldap"
idpFlowCLIPassword = "cli_password"
idpFlowBrowserAuthcode = "browser_authcode"
)
type oidcLoginCommandDeps struct { type oidcLoginCommandDeps struct {
lookupEnv func(string) (string, bool) lookupEnv func(string) (string, bool)
login func(string, string, ...oidcclient.Option) (*oidctypes.Token, error) login func(string, string, ...oidcclient.Option) (*oidctypes.Token, error)
@ -116,8 +110,8 @@ func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command {
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix") cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
cmd.Flags().StringVar(&flags.credentialCachePath, "credential-cache", filepath.Join(mustGetConfigDir(), "credentials.yaml"), "Path to cluster-specific credentials cache (\"\" disables the cache)") cmd.Flags().StringVar(&flags.credentialCachePath, "credential-cache", filepath.Join(mustGetConfigDir(), "credentials.yaml"), "Path to cluster-specific credentials cache (\"\" disables the cache)")
cmd.Flags().StringVar(&flags.upstreamIdentityProviderName, "upstream-identity-provider-name", "", "The name of the upstream identity provider used during login with a Supervisor") cmd.Flags().StringVar(&flags.upstreamIdentityProviderName, "upstream-identity-provider-name", "", "The name of the upstream identity provider used during login with a Supervisor")
cmd.Flags().StringVar(&flags.upstreamIdentityProviderType, "upstream-identity-provider-type", idpTypeOIDC, fmt.Sprintf("The type of the upstream identity provider used during login with a Supervisor (e.g. '%s', '%s')", idpTypeOIDC, idpTypeLDAP)) cmd.Flags().StringVar(&flags.upstreamIdentityProviderType, "upstream-identity-provider-type", idpdiscoveryv1alpha1.IDPTypeOIDC.String(), fmt.Sprintf("The type of the upstream identity provider used during login with a Supervisor (e.g. '%s', '%s')", idpdiscoveryv1alpha1.IDPTypeOIDC, idpdiscoveryv1alpha1.IDPTypeLDAP))
cmd.Flags().StringVar(&flags.upstreamIdentityProviderFlow, "upstream-identity-provider-flow", "", fmt.Sprintf("The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. '%s', '%s')", idpFlowBrowserAuthcode, idpFlowCLIPassword)) cmd.Flags().StringVar(&flags.upstreamIdentityProviderFlow, "upstream-identity-provider-flow", "", fmt.Sprintf("The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. '%s', '%s')", idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode, idpdiscoveryv1alpha1.IDPFlowCLIPassword))
// --skip-listen is mainly needed for testing. We'll leave it hidden until we have a non-testing use case. // --skip-listen is mainly needed for testing. We'll leave it hidden until we have a non-testing use case.
mustMarkHidden(cmd, "skip-listen") mustMarkHidden(cmd, "skip-listen")
@ -170,7 +164,10 @@ func runOIDCLogin(cmd *cobra.Command, deps oidcLoginCommandDeps, flags oidcLogin
flags.upstreamIdentityProviderName, flags.upstreamIdentityProviderType)) flags.upstreamIdentityProviderName, flags.upstreamIdentityProviderType))
} }
flowOpts, err := flowOptions(flags.upstreamIdentityProviderType, flags.upstreamIdentityProviderFlow) flowOpts, err := flowOptions(
idpdiscoveryv1alpha1.IDPType(flags.upstreamIdentityProviderType),
idpdiscoveryv1alpha1.IDPFlow(flags.upstreamIdentityProviderFlow),
)
if err != nil { if err != nil {
return err return err
} }
@ -255,35 +252,37 @@ func runOIDCLogin(cmd *cobra.Command, deps oidcLoginCommandDeps, flags oidcLogin
return json.NewEncoder(cmd.OutOrStdout()).Encode(cred) return json.NewEncoder(cmd.OutOrStdout()).Encode(cred)
} }
func flowOptions(requestedIDPType string, requestedFlow string) ([]oidcclient.Option, error) { func flowOptions(requestedIDPType idpdiscoveryv1alpha1.IDPType, requestedFlow idpdiscoveryv1alpha1.IDPFlow) ([]oidcclient.Option, error) {
useCLIFlow := []oidcclient.Option{oidcclient.WithCLISendingCredentials()} useCLIFlow := []oidcclient.Option{oidcclient.WithCLISendingCredentials()}
switch requestedIDPType { switch requestedIDPType {
case idpTypeOIDC: case idpdiscoveryv1alpha1.IDPTypeOIDC:
switch requestedFlow { switch requestedFlow {
case idpFlowCLIPassword: case idpdiscoveryv1alpha1.IDPFlowCLIPassword:
return useCLIFlow, nil return useCLIFlow, nil
case idpFlowBrowserAuthcode, "": case idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode, "":
return nil, nil // browser authcode flow is the default Option, so don't need to return an Option here return nil, nil // browser authcode flow is the default Option, so don't need to return an Option here
default: default:
return nil, fmt.Errorf( return nil, fmt.Errorf(
"--upstream-identity-provider-flow value not recognized for identity provider type %q: %s (supported values: %s)", "--upstream-identity-provider-flow value not recognized for identity provider type %q: %s (supported values: %s)",
requestedIDPType, requestedFlow, strings.Join([]string{idpFlowBrowserAuthcode, idpFlowCLIPassword}, ", ")) requestedIDPType, requestedFlow, strings.Join([]string{idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode.String(), idpdiscoveryv1alpha1.IDPFlowCLIPassword.String()}, ", "))
} }
case idpTypeLDAP: case idpdiscoveryv1alpha1.IDPTypeLDAP:
switch requestedFlow { switch requestedFlow {
case idpFlowCLIPassword, "": case idpdiscoveryv1alpha1.IDPFlowCLIPassword, "":
return useCLIFlow, nil return useCLIFlow, nil
case idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode:
fallthrough // not supported for LDAP providers, so fallthrough to error case
default: default:
return nil, fmt.Errorf( return nil, fmt.Errorf(
"--upstream-identity-provider-flow value not recognized for identity provider type %q: %s (supported values: %s)", "--upstream-identity-provider-flow value not recognized for identity provider type %q: %s (supported values: %s)",
requestedIDPType, requestedFlow, []string{idpFlowCLIPassword}) requestedIDPType, requestedFlow, []string{idpdiscoveryv1alpha1.IDPFlowCLIPassword.String()})
} }
default: default:
// Surprisingly cobra does not support this kind of flag validation. See https://github.com/spf13/pflag/issues/236 // Surprisingly cobra does not support this kind of flag validation. See https://github.com/spf13/pflag/issues/236
return nil, fmt.Errorf( return nil, fmt.Errorf(
"--upstream-identity-provider-type value not recognized: %s (supported values: %s)", "--upstream-identity-provider-type value not recognized: %s (supported values: %s)",
requestedIDPType, strings.Join([]string{idpTypeOIDC, idpTypeLDAP}, ", ")) requestedIDPType, strings.Join([]string{idpdiscoveryv1alpha1.IDPTypeOIDC.String(), idpdiscoveryv1alpha1.IDPTypeLDAP.String()}, ", "))
} }
} }

View File

@ -3,6 +3,42 @@
package v1alpha1 package v1alpha1
// IDPType are the strings that can be returned by the Supervisor identity provider discovery endpoint
// as the "type" of each returned identity provider.
type IDPType string
// IDPFlow are the strings that can be returned by the Supervisor identity provider discovery endpoint
// in the array of allowed client "flows" for each returned identity provider.
type IDPFlow string
const (
IDPTypeOIDC IDPType = "oidc"
IDPTypeLDAP IDPType = "ldap"
IDPFlowCLIPassword IDPFlow = "cli_password"
IDPFlowBrowserAuthcode IDPFlow = "browser_authcode"
)
// Equals is a convenience function for comparing an IDPType to a string.
func (r IDPType) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPType to a string.
func (r IDPType) String() string {
return string(r)
}
// Equals is a convenience function for comparing an IDPFlow to a string.
func (r IDPFlow) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPFlow to a string.
func (r IDPFlow) String() string {
return string(r)
}
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // 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 // 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.
@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct {
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // SupervisorPinnipedIDP 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 SupervisorPinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type IDPType `json:"type"`
Flows []string `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`
} }

View File

@ -3,6 +3,42 @@
package v1alpha1 package v1alpha1
// IDPType are the strings that can be returned by the Supervisor identity provider discovery endpoint
// as the "type" of each returned identity provider.
type IDPType string
// IDPFlow are the strings that can be returned by the Supervisor identity provider discovery endpoint
// in the array of allowed client "flows" for each returned identity provider.
type IDPFlow string
const (
IDPTypeOIDC IDPType = "oidc"
IDPTypeLDAP IDPType = "ldap"
IDPFlowCLIPassword IDPFlow = "cli_password"
IDPFlowBrowserAuthcode IDPFlow = "browser_authcode"
)
// Equals is a convenience function for comparing an IDPType to a string.
func (r IDPType) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPType to a string.
func (r IDPType) String() string {
return string(r)
}
// Equals is a convenience function for comparing an IDPFlow to a string.
func (r IDPFlow) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPFlow to a string.
func (r IDPFlow) String() string {
return string(r)
}
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // 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 // 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.
@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct {
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // SupervisorPinnipedIDP 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 SupervisorPinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type IDPType `json:"type"`
Flows []string `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`
} }

View File

@ -3,6 +3,42 @@
package v1alpha1 package v1alpha1
// IDPType are the strings that can be returned by the Supervisor identity provider discovery endpoint
// as the "type" of each returned identity provider.
type IDPType string
// IDPFlow are the strings that can be returned by the Supervisor identity provider discovery endpoint
// in the array of allowed client "flows" for each returned identity provider.
type IDPFlow string
const (
IDPTypeOIDC IDPType = "oidc"
IDPTypeLDAP IDPType = "ldap"
IDPFlowCLIPassword IDPFlow = "cli_password"
IDPFlowBrowserAuthcode IDPFlow = "browser_authcode"
)
// Equals is a convenience function for comparing an IDPType to a string.
func (r IDPType) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPType to a string.
func (r IDPType) String() string {
return string(r)
}
// Equals is a convenience function for comparing an IDPFlow to a string.
func (r IDPFlow) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPFlow to a string.
func (r IDPFlow) String() string {
return string(r)
}
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // 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 // 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.
@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct {
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // SupervisorPinnipedIDP 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 SupervisorPinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type IDPType `json:"type"`
Flows []string `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`
} }

View File

@ -3,6 +3,42 @@
package v1alpha1 package v1alpha1
// IDPType are the strings that can be returned by the Supervisor identity provider discovery endpoint
// as the "type" of each returned identity provider.
type IDPType string
// IDPFlow are the strings that can be returned by the Supervisor identity provider discovery endpoint
// in the array of allowed client "flows" for each returned identity provider.
type IDPFlow string
const (
IDPTypeOIDC IDPType = "oidc"
IDPTypeLDAP IDPType = "ldap"
IDPFlowCLIPassword IDPFlow = "cli_password"
IDPFlowBrowserAuthcode IDPFlow = "browser_authcode"
)
// Equals is a convenience function for comparing an IDPType to a string.
func (r IDPType) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPType to a string.
func (r IDPType) String() string {
return string(r)
}
// Equals is a convenience function for comparing an IDPFlow to a string.
func (r IDPFlow) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPFlow to a string.
func (r IDPFlow) String() string {
return string(r)
}
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // 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 // 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.
@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct {
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // SupervisorPinnipedIDP 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 SupervisorPinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type IDPType `json:"type"`
Flows []string `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`
} }

View File

@ -3,6 +3,42 @@
package v1alpha1 package v1alpha1
// IDPType are the strings that can be returned by the Supervisor identity provider discovery endpoint
// as the "type" of each returned identity provider.
type IDPType string
// IDPFlow are the strings that can be returned by the Supervisor identity provider discovery endpoint
// in the array of allowed client "flows" for each returned identity provider.
type IDPFlow string
const (
IDPTypeOIDC IDPType = "oidc"
IDPTypeLDAP IDPType = "ldap"
IDPFlowCLIPassword IDPFlow = "cli_password"
IDPFlowBrowserAuthcode IDPFlow = "browser_authcode"
)
// Equals is a convenience function for comparing an IDPType to a string.
func (r IDPType) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPType to a string.
func (r IDPType) String() string {
return string(r)
}
// Equals is a convenience function for comparing an IDPFlow to a string.
func (r IDPFlow) Equals(s string) bool {
return string(r) == s
}
// String is a convenience function to convert an IDPFlow to a string.
func (r IDPFlow) String() string {
return string(r)
}
// SupervisorOIDCDiscoveryResponse is part of the response from a FederationDomain's OpenID Provider Configuration // 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 // 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.
@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct {
// SupervisorPinnipedIDP describes a single identity provider as included in the response of a FederationDomain's // SupervisorPinnipedIDP 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 SupervisorPinnipedIDP struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type IDPType `json:"type"`
Flows []string `json:"flows,omitempty"` Flows []IDPFlow `json:"flows,omitempty"`
} }

View File

@ -14,14 +14,6 @@ import (
"go.pinniped.dev/internal/oidc" "go.pinniped.dev/internal/oidc"
) )
const (
idpDiscoveryTypeLDAP = "ldap"
idpDiscoveryTypeOIDC = "oidc"
flowOIDCBrowser = "browser_authcode"
flowCLIPassword = "cli_password"
)
// 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) {
@ -53,18 +45,18 @@ func responseAsJSON(upstreamIDPs oidc.UpstreamIdentityProvidersLister) ([]byte,
for _, provider := range upstreamIDPs.GetLDAPIdentityProviders() { for _, provider := range upstreamIDPs.GetLDAPIdentityProviders() {
r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{ r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{
Name: provider.GetName(), Name: provider.GetName(),
Type: idpDiscoveryTypeLDAP, Type: v1alpha1.IDPTypeLDAP,
Flows: []string{flowCLIPassword}, Flows: []v1alpha1.IDPFlow{v1alpha1.IDPFlowCLIPassword},
}) })
} }
for _, provider := range upstreamIDPs.GetOIDCIdentityProviders() { for _, provider := range upstreamIDPs.GetOIDCIdentityProviders() {
flows := []string{flowOIDCBrowser} flows := []v1alpha1.IDPFlow{v1alpha1.IDPFlowBrowserAuthcode}
if provider.AllowsPasswordGrant() { if provider.AllowsPasswordGrant() {
flows = append(flows, flowCLIPassword) flows = append(flows, v1alpha1.IDPFlowCLIPassword)
} }
r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{ r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{
Name: provider.GetName(), Name: provider.GetName(),
Type: idpDiscoveryTypeOIDC, Type: v1alpha1.IDPTypeOIDC,
Flows: flows, Flows: flows,
}) })
} }