2017-05-09 00:43:48 +00:00
|
|
|
package sso
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/xml"
|
2021-11-22 14:13:26 +00:00
|
|
|
"fmt"
|
2023-10-27 18:28:54 +00:00
|
|
|
"io"
|
2017-05-09 00:43:48 +00:00
|
|
|
"net/http"
|
2021-06-01 00:07:51 +00:00
|
|
|
"time"
|
2017-05-09 00:43:48 +00:00
|
|
|
|
2025-07-07 18:13:46 +00:00
|
|
|
"github.com/crewjam/saml"
|
2021-11-24 20:56:54 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
|
2023-04-27 12:43:20 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
2017-05-09 00:43:48 +00:00
|
|
|
)
|
|
|
|
|
|
2025-07-07 18:13:46 +00:00
|
|
|
// GetMetadata returns the parsed IdP metadata from the config.MetadataURL or config.Metadata.
|
|
|
|
|
// If config.MetadataURL is set, then it's used to request the metadata.
|
|
|
|
|
// If config.MetadataURL is not set, then config.Metadata is used.
|
|
|
|
|
func GetMetadata(config *fleet.SSOProviderSettings) (*saml.EntityDescriptor, error) {
|
|
|
|
|
if config.MetadataURL == "" && config.Metadata == "" {
|
|
|
|
|
return nil, fmt.Errorf("missing metadata for idp %q", config.IDPName)
|
2023-04-27 12:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
2025-07-07 18:13:46 +00:00
|
|
|
var xmlMetadata []byte
|
|
|
|
|
if config.MetadataURL != "" {
|
|
|
|
|
var err error
|
|
|
|
|
xmlMetadata, err = getMetadata(config.MetadataURL)
|
2023-04-27 12:43:20 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2025-07-07 18:13:46 +00:00
|
|
|
} else {
|
|
|
|
|
xmlMetadata = []byte(config.Metadata)
|
2023-04-27 12:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
2025-07-07 18:13:46 +00:00
|
|
|
return ParseMetadata(xmlMetadata)
|
2017-05-09 00:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
2025-07-07 18:13:46 +00:00
|
|
|
func getMetadata(metadataURL string) ([]byte, error) {
|
2021-11-24 20:56:54 +00:00
|
|
|
client := fleethttp.NewClient(fleethttp.WithTimeout(5 * time.Second))
|
2017-05-09 00:43:48 +00:00
|
|
|
request, err := http.NewRequest(http.MethodGet, metadataURL, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
resp, err := client.Do(request)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
2021-11-22 14:13:26 +00:00
|
|
|
return nil, fmt.Errorf("SAML metadata server at %s returned %s", metadataURL, resp.Status)
|
2017-05-09 00:43:48 +00:00
|
|
|
}
|
2023-10-27 18:28:54 +00:00
|
|
|
xmlData, err := io.ReadAll(resp.Body)
|
2017-05-09 00:43:48 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2025-07-07 18:13:46 +00:00
|
|
|
return xmlData, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ParseMetadata parses SSO IdP metadata from the given raw XML bytes.
|
|
|
|
|
func ParseMetadata(xmlMetadata []byte) (*saml.EntityDescriptor, error) {
|
|
|
|
|
var entityDescriptor saml.EntityDescriptor
|
|
|
|
|
if err := xml.Unmarshal(xmlMetadata, &entityDescriptor); err != nil {
|
2017-05-09 00:43:48 +00:00
|
|
|
return nil, err
|
|
|
|
|
}
|
2025-07-07 18:13:46 +00:00
|
|
|
return &entityDescriptor, nil
|
2017-05-09 00:43:48 +00:00
|
|
|
}
|