pomerium/internal/directory/ping/config.go

116 lines
2.8 KiB
Go

package ping
import (
"fmt"
"net/http"
"net/url"
"strings"
"github.com/rs/zerolog"
"github.com/pomerium/pomerium/internal/encoding"
"github.com/pomerium/pomerium/internal/httputil"
)
type config struct {
authURL *url.URL
apiURL *url.URL
serviceAccount *ServiceAccount
httpClient *http.Client
environmentID string
}
// An Option updates the Ping configuration.
type Option func(*config)
// WithAPIURL sets the api url in the config.
func WithAPIURL(apiURL *url.URL) Option {
return func(cfg *config) {
cfg.apiURL = apiURL
}
}
// WithAuthURL sets the auth url in the config.
func WithAuthURL(authURL *url.URL) Option {
return func(cfg *config) {
cfg.authURL = authURL
}
}
// WithEnvironmentID sets the environment ID in the config.
func WithEnvironmentID(environmentID string) Option {
return func(cfg *config) {
cfg.environmentID = environmentID
}
}
// WithHTTPClient sets the http client option.
func WithHTTPClient(httpClient *http.Client) Option {
return func(cfg *config) {
cfg.httpClient = httputil.NewLoggingClient(httpClient, "ping_idp_client",
func(evt *zerolog.Event) *zerolog.Event {
return evt.Str("provider", "ping")
})
}
}
// WithProviderURL sets the environment ID from the provider URL set in the config.
func WithProviderURL(providerURL *url.URL) Option {
// provider URL will be https://auth.pingone.com/{ENVIRONMENT_ID}/as
if providerURL == nil {
return func(cfg *config) {}
}
parts := strings.Split(providerURL.Path, "/")
if len(parts) < 1 {
return func(cfg *config) {}
}
return WithEnvironmentID(parts[1])
}
// WithServiceAccount sets the service account in the config.
func WithServiceAccount(serviceAccount *ServiceAccount) Option {
return func(cfg *config) {
cfg.serviceAccount = serviceAccount
}
}
func getConfig(options ...Option) *config {
cfg := new(config)
WithHTTPClient(http.DefaultClient)(cfg)
WithAuthURL(&url.URL{
Scheme: "https",
Host: "auth.pingone.com",
})(cfg)
WithAPIURL(&url.URL{
Scheme: "https",
Host: "api.pingone.com",
})(cfg)
for _, option := range options {
option(cfg)
}
return cfg
}
// A ServiceAccount is used by the Ping provider to query the API.
type ServiceAccount struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
EnvironmentID string `json:"environment_id"`
}
// ParseServiceAccount parses the service account in the config options.
func ParseServiceAccount(rawServiceAccount string) (*ServiceAccount, error) {
var serviceAccount ServiceAccount
if err := encoding.DecodeBase64OrJSON(rawServiceAccount, &serviceAccount); err != nil {
return nil, err
}
if serviceAccount.ClientID == "" {
return nil, fmt.Errorf("client_id is required")
}
if serviceAccount.ClientSecret == "" {
return nil, fmt.Errorf("client_secret is required")
}
return &serviceAccount, nil
}