diff --git a/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go.tmpl b/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go.tmpl index 1d37195f..f6702273 100644 --- a/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go.tmpl +++ b/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go.tmpl @@ -3,6 +3,42 @@ 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 // 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. @@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct { // 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"` + Name string `json:"name"` + Type IDPType `json:"type"` + Flows []IDPFlow `json:"flows,omitempty"` } diff --git a/cmd/pinniped/cmd/kubeconfig.go b/cmd/pinniped/cmd/kubeconfig.go index 272f210d..53429b8c 100644 --- a/cmd/pinniped/cmd/kubeconfig.go +++ b/cmd/pinniped/cmd/kubeconfig.go @@ -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.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.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.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.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", "", 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.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)") @@ -772,8 +772,8 @@ func discoverSupervisorUpstreamIDP(ctx context.Context, flags *getKubeconfigPara } flags.oidc.upstreamIDPName = selectedIDPName - flags.oidc.upstreamIDPType = selectedIDPType - flags.oidc.upstreamIDPFlow = selectedIDPFlow + flags.oidc.upstreamIDPType = selectedIDPType.String() + flags.oidc.upstreamIDPFlow = selectedIDPFlow.String() return nil } @@ -841,15 +841,15 @@ func discoverAllAvailableSupervisorUpstreamIDPs(ctx context.Context, pinnipedIDP 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) - var discoveredFlows []string + var discoveredFlows []idpdiscoveryv1alpha1.IDPFlow switch { case specifiedIDPName != "" && specifiedIDPType != "": // The user specified both name and type, so check to see if there exists an exact match. for _, idp := range pinnipedIDPs { - if idp.Name == specifiedIDPName && idp.Type == specifiedIDPType { - return specifiedIDPName, specifiedIDPType, idp.Flows, nil + if idp.Name == specifiedIDPName && idp.Type.Equals(specifiedIDPType) { + return specifiedIDPName, idp.Type, idp.Flows, nil } } return "", "", nil, fmt.Errorf( @@ -858,8 +858,9 @@ func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.Supervisor case specifiedIDPType != "": // The user specified only a type, so check if there is only one of that type found. discoveredName := "" + var discoveredType idpdiscoveryv1alpha1.IDPType for _, idp := range pinnipedIDPs { - if idp.Type == specifiedIDPType { + if idp.Type.Equals(specifiedIDPType) { if discoveredName != "" { return "", "", nil, fmt.Errorf( "multiple Supervisor upstream identity providers of type %q were found, "+ @@ -868,6 +869,7 @@ func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.Supervisor specifiedIDPType, pinnipedIDPsString) } discoveredName = idp.Name + discoveredType = idp.Type discoveredFlows = idp.Flows } } @@ -876,10 +878,10 @@ func selectUpstreamIDPNameAndType(pinnipedIDPs []idpdiscoveryv1alpha1.Supervisor "no Supervisor upstream identity providers of type %q were found. "+ "Found these upstreams: %s", specifiedIDPType, pinnipedIDPsString) } - return discoveredName, specifiedIDPType, discoveredFlows, nil + return discoveredName, discoveredType, discoveredFlows, nil case specifiedIDPName != "": // 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 { if idp.Name == specifiedIDPName { 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 { case len(discoveredIDPFlows) == 0: // 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 // and return empty string. - return specifiedFlow, nil + return idpdiscoveryv1alpha1.IDPFlow(specifiedFlow), nil case specifiedFlow != "": // The user specified a flow, so validate that it is available for the selected IDP. for _, flow := range discoveredIDPFlows { - if flow == specifiedFlow { + if flow.Equals(specifiedFlow) { // Found it, so use it as specified by the user. - return specifiedFlow, nil + return flow, nil } } return "", fmt.Errorf( diff --git a/cmd/pinniped/cmd/login_oidc.go b/cmd/pinniped/cmd/login_oidc.go index 25ebcc6d..eaef1fda 100644 --- a/cmd/pinniped/cmd/login_oidc.go +++ b/cmd/pinniped/cmd/login_oidc.go @@ -24,6 +24,7 @@ import ( "k8s.io/client-go/transport" "k8s.io/klog/v2/klogr" + idpdiscoveryv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1" "go.pinniped.dev/internal/execcredcache" "go.pinniped.dev/internal/groupsuffix" "go.pinniped.dev/internal/plog" @@ -38,13 +39,6 @@ func init() { loginCmd.AddCommand(oidcLoginCommand(oidcLoginCommandRealDeps())) } -const ( - idpTypeOIDC = "oidc" - idpTypeLDAP = "ldap" - idpFlowCLIPassword = "cli_password" - idpFlowBrowserAuthcode = "browser_authcode" -) - type oidcLoginCommandDeps struct { lookupEnv func(string) (string, bool) 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.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.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.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.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')", idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode, idpdiscoveryv1alpha1.IDPFlowCLIPassword)) // --skip-listen is mainly needed for testing. We'll leave it hidden until we have a non-testing use case. mustMarkHidden(cmd, "skip-listen") @@ -170,7 +164,10 @@ func runOIDCLogin(cmd *cobra.Command, deps oidcLoginCommandDeps, flags oidcLogin 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 { return err } @@ -255,35 +252,37 @@ func runOIDCLogin(cmd *cobra.Command, deps oidcLoginCommandDeps, flags oidcLogin 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()} switch requestedIDPType { - case idpTypeOIDC: + case idpdiscoveryv1alpha1.IDPTypeOIDC: switch requestedFlow { - case idpFlowCLIPassword: + case idpdiscoveryv1alpha1.IDPFlowCLIPassword: 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 default: return nil, fmt.Errorf( "--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 { - case idpFlowCLIPassword, "": + case idpdiscoveryv1alpha1.IDPFlowCLIPassword, "": return useCLIFlow, nil + case idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode: + fallthrough // not supported for LDAP providers, so fallthrough to error case default: return nil, fmt.Errorf( "--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: // Surprisingly cobra does not support this kind of flag validation. See https://github.com/spf13/pflag/issues/236 return nil, fmt.Errorf( "--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()}, ", ")) } } diff --git a/generated/1.17/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go b/generated/1.17/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go index 1d37195f..f6702273 100644 --- a/generated/1.17/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go +++ b/generated/1.17/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go @@ -3,6 +3,42 @@ 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 // 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. @@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct { // 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"` + Name string `json:"name"` + Type IDPType `json:"type"` + Flows []IDPFlow `json:"flows,omitempty"` } diff --git a/generated/1.18/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go b/generated/1.18/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go index 1d37195f..f6702273 100644 --- a/generated/1.18/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go +++ b/generated/1.18/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go @@ -3,6 +3,42 @@ 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 // 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. @@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct { // 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"` + Name string `json:"name"` + Type IDPType `json:"type"` + Flows []IDPFlow `json:"flows,omitempty"` } diff --git a/generated/1.19/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go b/generated/1.19/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go index 1d37195f..f6702273 100644 --- a/generated/1.19/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go +++ b/generated/1.19/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go @@ -3,6 +3,42 @@ 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 // 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. @@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct { // 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"` + Name string `json:"name"` + Type IDPType `json:"type"` + Flows []IDPFlow `json:"flows,omitempty"` } diff --git a/generated/1.20/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go b/generated/1.20/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go index 1d37195f..f6702273 100644 --- a/generated/1.20/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go +++ b/generated/1.20/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go @@ -3,6 +3,42 @@ 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 // 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. @@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct { // 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"` + Name string `json:"name"` + Type IDPType `json:"type"` + Flows []IDPFlow `json:"flows,omitempty"` } diff --git a/generated/latest/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go b/generated/latest/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go index 1d37195f..f6702273 100644 --- a/generated/latest/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go +++ b/generated/latest/apis/supervisor/idpdiscovery/v1alpha1/types_supervisor_idp_discovery.go @@ -3,6 +3,42 @@ 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 // 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. @@ -23,7 +59,7 @@ type SupervisorIDPDiscoveryResponse struct { // 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"` + Name string `json:"name"` + Type IDPType `json:"type"` + Flows []IDPFlow `json:"flows,omitempty"` } diff --git a/internal/oidc/idpdiscovery/idp_discovery_handler.go b/internal/oidc/idpdiscovery/idp_discovery_handler.go index 32ce187d..1ffeca2f 100644 --- a/internal/oidc/idpdiscovery/idp_discovery_handler.go +++ b/internal/oidc/idpdiscovery/idp_discovery_handler.go @@ -14,14 +14,6 @@ import ( "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. func NewHandler(upstreamIDPs oidc.UpstreamIdentityProvidersLister) http.Handler { 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() { r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{ Name: provider.GetName(), - Type: idpDiscoveryTypeLDAP, - Flows: []string{flowCLIPassword}, + Type: v1alpha1.IDPTypeLDAP, + Flows: []v1alpha1.IDPFlow{v1alpha1.IDPFlowCLIPassword}, }) } for _, provider := range upstreamIDPs.GetOIDCIdentityProviders() { - flows := []string{flowOIDCBrowser} + flows := []v1alpha1.IDPFlow{v1alpha1.IDPFlowBrowserAuthcode} if provider.AllowsPasswordGrant() { - flows = append(flows, flowCLIPassword) + flows = append(flows, v1alpha1.IDPFlowCLIPassword) } r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.SupervisorPinnipedIDP{ Name: provider.GetName(), - Type: idpDiscoveryTypeOIDC, + Type: v1alpha1.IDPTypeOIDC, Flows: flows, }) }