76 lines
2.1 KiB
Go
76 lines
2.1 KiB
Go
|
// Copyright 2021 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/internal/oidc"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
idpDiscoveryTypeLDAP = "ldap"
|
||
|
idpDiscoveryTypeOIDC = "oidc"
|
||
|
)
|
||
|
|
||
|
type response struct {
|
||
|
IDPs []identityProviderResponse `json:"pinniped_identity_providers"`
|
||
|
}
|
||
|
|
||
|
type identityProviderResponse struct {
|
||
|
Name string `json:"name"`
|
||
|
Type string `json:"type"`
|
||
|
}
|
||
|
|
||
|
// 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) {
|
||
|
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 oidc.UpstreamIdentityProvidersLister) ([]byte, error) {
|
||
|
r := response{
|
||
|
IDPs: []identityProviderResponse{},
|
||
|
}
|
||
|
|
||
|
// The cache of IDPs could change at any time, so always recalculate the list.
|
||
|
for _, provider := range upstreamIDPs.GetLDAPIdentityProviders() {
|
||
|
r.IDPs = append(r.IDPs, identityProviderResponse{Name: provider.GetName(), Type: idpDiscoveryTypeLDAP})
|
||
|
}
|
||
|
for _, provider := range upstreamIDPs.GetOIDCIdentityProviders() {
|
||
|
r.IDPs = append(r.IDPs, identityProviderResponse{Name: provider.GetName(), Type: idpDiscoveryTypeOIDC})
|
||
|
}
|
||
|
|
||
|
// Nobody like an API that changes the results unnecessarily. :)
|
||
|
sort.SliceStable(r.IDPs, func(i, j int) bool {
|
||
|
return r.IDPs[i].Name < r.IDPs[j].Name
|
||
|
})
|
||
|
|
||
|
var b bytes.Buffer
|
||
|
encodeErr := json.NewEncoder(&b).Encode(&r)
|
||
|
encodedMetadata := b.Bytes()
|
||
|
|
||
|
return encodedMetadata, encodeErr
|
||
|
}
|