86c791b8a6
Co-authored-by: Benjamin A. Petersen <ben@benjaminapetersen.me>
80 lines
2.9 KiB
Go
80 lines
2.9 KiB
Go
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package idpdiscovery provides a handler for the upstream IDP discovery endpoint.
|
|
package idpdiscovery
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"sort"
|
|
|
|
"go.pinniped.dev/generated/latest/apis/supervisor/idpdiscovery/v1alpha1"
|
|
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
|
|
)
|
|
|
|
// NewHandler returns an http.Handler that serves the upstream IDP discovery endpoint.
|
|
func NewHandler(upstreamIDPs federationdomainproviders.FederationDomainIdentityProvidersListerI) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, `Method not allowed (try GET)`, http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
encodedMetadata, encodeErr := responseAsJSON(upstreamIDPs)
|
|
if encodeErr != nil {
|
|
http.Error(w, encodeErr.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write(encodedMetadata); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
})
|
|
}
|
|
|
|
func responseAsJSON(upstreamIDPs federationdomainproviders.FederationDomainIdentityProvidersListerI) ([]byte, error) {
|
|
r := v1alpha1.IDPDiscoveryResponse{PinnipedIDPs: []v1alpha1.PinnipedIDP{}}
|
|
|
|
// The cache of IDPs could change at any time, so always recalculate the list.
|
|
for _, federationDomainIdentityProvider := range upstreamIDPs.GetLDAPIdentityProviders() {
|
|
r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.PinnipedIDP{
|
|
Name: federationDomainIdentityProvider.DisplayName,
|
|
Type: v1alpha1.IDPTypeLDAP,
|
|
Flows: []v1alpha1.IDPFlow{v1alpha1.IDPFlowCLIPassword, v1alpha1.IDPFlowBrowserAuthcode},
|
|
})
|
|
}
|
|
for _, federationDomainIdentityProvider := range upstreamIDPs.GetActiveDirectoryIdentityProviders() {
|
|
r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.PinnipedIDP{
|
|
Name: federationDomainIdentityProvider.DisplayName,
|
|
Type: v1alpha1.IDPTypeActiveDirectory,
|
|
Flows: []v1alpha1.IDPFlow{v1alpha1.IDPFlowCLIPassword, v1alpha1.IDPFlowBrowserAuthcode},
|
|
})
|
|
}
|
|
for _, federationDomainIdentityProvider := range upstreamIDPs.GetOIDCIdentityProviders() {
|
|
flows := []v1alpha1.IDPFlow{v1alpha1.IDPFlowBrowserAuthcode}
|
|
if federationDomainIdentityProvider.Provider.AllowsPasswordGrant() {
|
|
flows = append(flows, v1alpha1.IDPFlowCLIPassword)
|
|
}
|
|
r.PinnipedIDPs = append(r.PinnipedIDPs, v1alpha1.PinnipedIDP{
|
|
Name: federationDomainIdentityProvider.DisplayName,
|
|
Type: v1alpha1.IDPTypeOIDC,
|
|
Flows: flows,
|
|
})
|
|
}
|
|
|
|
// Nobody like an API that changes the results unnecessarily. :)
|
|
sort.SliceStable(r.PinnipedIDPs, func(i, j int) bool {
|
|
return r.PinnipedIDPs[i].Name < r.PinnipedIDPs[j].Name
|
|
})
|
|
|
|
var b bytes.Buffer
|
|
encodeErr := json.NewEncoder(&b).Encode(&r)
|
|
encodedMetadata := b.Bytes()
|
|
|
|
return encodedMetadata, encodeErr
|
|
}
|