aboutsummaryrefslogtreecommitdiffstats
path: root/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/provider.go
diff options
context:
space:
mode:
Diffstat (limited to 'kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/provider.go')
-rw-r--r--kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/provider.go688
1 files changed, 0 insertions, 688 deletions
diff --git a/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/provider.go b/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/provider.go
deleted file mode 100644
index 1235890..0000000
--- a/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/provider.go
+++ /dev/null
@@ -1,688 +0,0 @@
-package oidc
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "strings"
- "sync"
- "time"
-
- "github.com/coreos/pkg/capnslog"
- "github.com/coreos/pkg/timeutil"
- "github.com/jonboulle/clockwork"
-
- phttp "github.com/coreos/go-oidc/http"
- "github.com/coreos/go-oidc/oauth2"
-)
-
-var (
- log = capnslog.NewPackageLogger("github.com/coreos/go-oidc", "http")
-)
-
-const (
- // Subject Identifier types defined by the OIDC spec. Specifies if the provider
- // should provide the same sub claim value to all clients (public) or a unique
- // value for each client (pairwise).
- //
- // See: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
- SubjectTypePublic = "public"
- SubjectTypePairwise = "pairwise"
-)
-
-var (
- // Default values for omitted provider config fields.
- //
- // Use ProviderConfig's Defaults method to fill a provider config with these values.
- DefaultGrantTypesSupported = []string{oauth2.GrantTypeAuthCode, oauth2.GrantTypeImplicit}
- DefaultResponseModesSupported = []string{"query", "fragment"}
- DefaultTokenEndpointAuthMethodsSupported = []string{oauth2.AuthMethodClientSecretBasic}
- DefaultClaimTypesSupported = []string{"normal"}
-)
-
-const (
- MaximumProviderConfigSyncInterval = 24 * time.Hour
- MinimumProviderConfigSyncInterval = time.Minute
-
- discoveryConfigPath = "/.well-known/openid-configuration"
-)
-
-// internally configurable for tests
-var minimumProviderConfigSyncInterval = MinimumProviderConfigSyncInterval
-
-var (
- // Ensure ProviderConfig satisfies these interfaces.
- _ json.Marshaler = &ProviderConfig{}
- _ json.Unmarshaler = &ProviderConfig{}
-)
-
-// ProviderConfig represents the OpenID Provider Metadata specifying what
-// configurations a provider supports.
-//
-// See: http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
-type ProviderConfig struct {
- Issuer *url.URL // Required
- AuthEndpoint *url.URL // Required
- TokenEndpoint *url.URL // Required if grant types other than "implicit" are supported
- UserInfoEndpoint *url.URL
- KeysEndpoint *url.URL // Required
- RegistrationEndpoint *url.URL
-
- // Servers MAY choose not to advertise some supported scope values even when this
- // parameter is used, although those defined in OpenID Core SHOULD be listed, if supported.
- ScopesSupported []string
- // OAuth2.0 response types supported.
- ResponseTypesSupported []string // Required
- // OAuth2.0 response modes supported.
- //
- // If omitted, defaults to DefaultResponseModesSupported.
- ResponseModesSupported []string
- // OAuth2.0 grant types supported.
- //
- // If omitted, defaults to DefaultGrantTypesSupported.
- GrantTypesSupported []string
- ACRValuesSupported []string
- // SubjectTypesSupported specifies strategies for providing values for the sub claim.
- SubjectTypesSupported []string // Required
-
- // JWA signing and encryption algorith values supported for ID tokens.
- IDTokenSigningAlgValues []string // Required
- IDTokenEncryptionAlgValues []string
- IDTokenEncryptionEncValues []string
-
- // JWA signing and encryption algorith values supported for user info responses.
- UserInfoSigningAlgValues []string
- UserInfoEncryptionAlgValues []string
- UserInfoEncryptionEncValues []string
-
- // JWA signing and encryption algorith values supported for request objects.
- ReqObjSigningAlgValues []string
- ReqObjEncryptionAlgValues []string
- ReqObjEncryptionEncValues []string
-
- TokenEndpointAuthMethodsSupported []string
- TokenEndpointAuthSigningAlgValuesSupported []string
- DisplayValuesSupported []string
- ClaimTypesSupported []string
- ClaimsSupported []string
- ServiceDocs *url.URL
- ClaimsLocalsSupported []string
- UILocalsSupported []string
- ClaimsParameterSupported bool
- RequestParameterSupported bool
- RequestURIParamaterSupported bool
- RequireRequestURIRegistration bool
-
- Policy *url.URL
- TermsOfService *url.URL
-
- // Not part of the OpenID Provider Metadata
- ExpiresAt time.Time
-}
-
-// Defaults returns a shallow copy of ProviderConfig with default
-// values replacing omitted fields.
-//
-// var cfg oidc.ProviderConfig
-// // Fill provider config with default values for omitted fields.
-// cfg = cfg.Defaults()
-//
-func (p ProviderConfig) Defaults() ProviderConfig {
- setDefault := func(val *[]string, defaultVal []string) {
- if len(*val) == 0 {
- *val = defaultVal
- }
- }
- setDefault(&p.GrantTypesSupported, DefaultGrantTypesSupported)
- setDefault(&p.ResponseModesSupported, DefaultResponseModesSupported)
- setDefault(&p.TokenEndpointAuthMethodsSupported, DefaultTokenEndpointAuthMethodsSupported)
- setDefault(&p.ClaimTypesSupported, DefaultClaimTypesSupported)
- return p
-}
-
-func (p *ProviderConfig) MarshalJSON() ([]byte, error) {
- e := p.toEncodableStruct()
- return json.Marshal(&e)
-}
-
-func (p *ProviderConfig) UnmarshalJSON(data []byte) error {
- var e encodableProviderConfig
- if err := json.Unmarshal(data, &e); err != nil {
- return err
- }
- conf, err := e.toStruct()
- if err != nil {
- return err
- }
- if err := conf.Valid(); err != nil {
- return err
- }
- *p = conf
- return nil
-}
-
-type encodableProviderConfig struct {
- Issuer string `json:"issuer"`
- AuthEndpoint string `json:"authorization_endpoint"`
- TokenEndpoint string `json:"token_endpoint"`
- UserInfoEndpoint string `json:"userinfo_endpoint,omitempty"`
- KeysEndpoint string `json:"jwks_uri"`
- RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
-
- // Use 'omitempty' for all slices as per OIDC spec:
- // "Claims that return multiple values are represented as JSON arrays.
- // Claims with zero elements MUST be omitted from the response."
- // http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
-
- ScopesSupported []string `json:"scopes_supported,omitempty"`
- ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
- ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
- GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
- ACRValuesSupported []string `json:"acr_values_supported,omitempty"`
- SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
-
- IDTokenSigningAlgValues []string `json:"id_token_signing_alg_values_supported,omitempty"`
- IDTokenEncryptionAlgValues []string `json:"id_token_encryption_alg_values_supported,omitempty"`
- IDTokenEncryptionEncValues []string `json:"id_token_encryption_enc_values_supported,omitempty"`
- UserInfoSigningAlgValues []string `json:"userinfo_signing_alg_values_supported,omitempty"`
- UserInfoEncryptionAlgValues []string `json:"userinfo_encryption_alg_values_supported,omitempty"`
- UserInfoEncryptionEncValues []string `json:"userinfo_encryption_enc_values_supported,omitempty"`
- ReqObjSigningAlgValues []string `json:"request_object_signing_alg_values_supported,omitempty"`
- ReqObjEncryptionAlgValues []string `json:"request_object_encryption_alg_values_supported,omitempty"`
- ReqObjEncryptionEncValues []string `json:"request_object_encryption_enc_values_supported,omitempty"`
-
- TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
- TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
-
- DisplayValuesSupported []string `json:"display_values_supported,omitempty"`
- ClaimTypesSupported []string `json:"claim_types_supported,omitempty"`
- ClaimsSupported []string `json:"claims_supported,omitempty"`
- ServiceDocs string `json:"service_documentation,omitempty"`
- ClaimsLocalsSupported []string `json:"claims_locales_supported,omitempty"`
- UILocalsSupported []string `json:"ui_locales_supported,omitempty"`
- ClaimsParameterSupported bool `json:"claims_parameter_supported,omitempty"`
- RequestParameterSupported bool `json:"request_parameter_supported,omitempty"`
- RequestURIParamaterSupported bool `json:"request_uri_parameter_supported,omitempty"`
- RequireRequestURIRegistration bool `json:"require_request_uri_registration,omitempty"`
-
- Policy string `json:"op_policy_uri,omitempty"`
- TermsOfService string `json:"op_tos_uri,omitempty"`
-}
-
-func (cfg ProviderConfig) toEncodableStruct() encodableProviderConfig {
- return encodableProviderConfig{
- Issuer: uriToString(cfg.Issuer),
- AuthEndpoint: uriToString(cfg.AuthEndpoint),
- TokenEndpoint: uriToString(cfg.TokenEndpoint),
- UserInfoEndpoint: uriToString(cfg.UserInfoEndpoint),
- KeysEndpoint: uriToString(cfg.KeysEndpoint),
- RegistrationEndpoint: uriToString(cfg.RegistrationEndpoint),
- ScopesSupported: cfg.ScopesSupported,
- ResponseTypesSupported: cfg.ResponseTypesSupported,
- ResponseModesSupported: cfg.ResponseModesSupported,
- GrantTypesSupported: cfg.GrantTypesSupported,
- ACRValuesSupported: cfg.ACRValuesSupported,
- SubjectTypesSupported: cfg.SubjectTypesSupported,
- IDTokenSigningAlgValues: cfg.IDTokenSigningAlgValues,
- IDTokenEncryptionAlgValues: cfg.IDTokenEncryptionAlgValues,
- IDTokenEncryptionEncValues: cfg.IDTokenEncryptionEncValues,
- UserInfoSigningAlgValues: cfg.UserInfoSigningAlgValues,
- UserInfoEncryptionAlgValues: cfg.UserInfoEncryptionAlgValues,
- UserInfoEncryptionEncValues: cfg.UserInfoEncryptionEncValues,
- ReqObjSigningAlgValues: cfg.ReqObjSigningAlgValues,
- ReqObjEncryptionAlgValues: cfg.ReqObjEncryptionAlgValues,
- ReqObjEncryptionEncValues: cfg.ReqObjEncryptionEncValues,
- TokenEndpointAuthMethodsSupported: cfg.TokenEndpointAuthMethodsSupported,
- TokenEndpointAuthSigningAlgValuesSupported: cfg.TokenEndpointAuthSigningAlgValuesSupported,
- DisplayValuesSupported: cfg.DisplayValuesSupported,
- ClaimTypesSupported: cfg.ClaimTypesSupported,
- ClaimsSupported: cfg.ClaimsSupported,
- ServiceDocs: uriToString(cfg.ServiceDocs),
- ClaimsLocalsSupported: cfg.ClaimsLocalsSupported,
- UILocalsSupported: cfg.UILocalsSupported,
- ClaimsParameterSupported: cfg.ClaimsParameterSupported,
- RequestParameterSupported: cfg.RequestParameterSupported,
- RequestURIParamaterSupported: cfg.RequestURIParamaterSupported,
- RequireRequestURIRegistration: cfg.RequireRequestURIRegistration,
- Policy: uriToString(cfg.Policy),
- TermsOfService: uriToString(cfg.TermsOfService),
- }
-}
-
-func (e encodableProviderConfig) toStruct() (ProviderConfig, error) {
- p := stickyErrParser{}
- conf := ProviderConfig{
- Issuer: p.parseURI(e.Issuer, "issuer"),
- AuthEndpoint: p.parseURI(e.AuthEndpoint, "authorization_endpoint"),
- TokenEndpoint: p.parseURI(e.TokenEndpoint, "token_endpoint"),
- UserInfoEndpoint: p.parseURI(e.UserInfoEndpoint, "userinfo_endpoint"),
- KeysEndpoint: p.parseURI(e.KeysEndpoint, "jwks_uri"),
- RegistrationEndpoint: p.parseURI(e.RegistrationEndpoint, "registration_endpoint"),
- ScopesSupported: e.ScopesSupported,
- ResponseTypesSupported: e.ResponseTypesSupported,
- ResponseModesSupported: e.ResponseModesSupported,
- GrantTypesSupported: e.GrantTypesSupported,
- ACRValuesSupported: e.ACRValuesSupported,
- SubjectTypesSupported: e.SubjectTypesSupported,
- IDTokenSigningAlgValues: e.IDTokenSigningAlgValues,
- IDTokenEncryptionAlgValues: e.IDTokenEncryptionAlgValues,
- IDTokenEncryptionEncValues: e.IDTokenEncryptionEncValues,
- UserInfoSigningAlgValues: e.UserInfoSigningAlgValues,
- UserInfoEncryptionAlgValues: e.UserInfoEncryptionAlgValues,
- UserInfoEncryptionEncValues: e.UserInfoEncryptionEncValues,
- ReqObjSigningAlgValues: e.ReqObjSigningAlgValues,
- ReqObjEncryptionAlgValues: e.ReqObjEncryptionAlgValues,
- ReqObjEncryptionEncValues: e.ReqObjEncryptionEncValues,
- TokenEndpointAuthMethodsSupported: e.TokenEndpointAuthMethodsSupported,
- TokenEndpointAuthSigningAlgValuesSupported: e.TokenEndpointAuthSigningAlgValuesSupported,
- DisplayValuesSupported: e.DisplayValuesSupported,
- ClaimTypesSupported: e.ClaimTypesSupported,
- ClaimsSupported: e.ClaimsSupported,
- ServiceDocs: p.parseURI(e.ServiceDocs, "service_documentation"),
- ClaimsLocalsSupported: e.ClaimsLocalsSupported,
- UILocalsSupported: e.UILocalsSupported,
- ClaimsParameterSupported: e.ClaimsParameterSupported,
- RequestParameterSupported: e.RequestParameterSupported,
- RequestURIParamaterSupported: e.RequestURIParamaterSupported,
- RequireRequestURIRegistration: e.RequireRequestURIRegistration,
- Policy: p.parseURI(e.Policy, "op_policy-uri"),
- TermsOfService: p.parseURI(e.TermsOfService, "op_tos_uri"),
- }
- if p.firstErr != nil {
- return ProviderConfig{}, p.firstErr
- }
- return conf, nil
-}
-
-// Empty returns if a ProviderConfig holds no information.
-//
-// This case generally indicates a ProviderConfigGetter has experienced an error
-// and has nothing to report.
-func (p ProviderConfig) Empty() bool {
- return p.Issuer == nil
-}
-
-func contains(sli []string, ele string) bool {
- for _, s := range sli {
- if s == ele {
- return true
- }
- }
- return false
-}
-
-// Valid determines if a ProviderConfig conforms with the OIDC specification.
-// If Valid returns successfully it guarantees required field are non-nil and
-// URLs are well formed.
-//
-// Valid is called by UnmarshalJSON.
-//
-// NOTE(ericchiang): For development purposes Valid does not mandate 'https' for
-// URLs fields where the OIDC spec requires it. This may change in future releases
-// of this package. See: https://github.com/coreos/go-oidc/issues/34
-func (p ProviderConfig) Valid() error {
- grantTypes := p.GrantTypesSupported
- if len(grantTypes) == 0 {
- grantTypes = DefaultGrantTypesSupported
- }
- implicitOnly := true
- for _, grantType := range grantTypes {
- if grantType != oauth2.GrantTypeImplicit {
- implicitOnly = false
- break
- }
- }
-
- if len(p.SubjectTypesSupported) == 0 {
- return errors.New("missing required field subject_types_supported")
- }
- if len(p.IDTokenSigningAlgValues) == 0 {
- return errors.New("missing required field id_token_signing_alg_values_supported")
- }
-
- if len(p.ScopesSupported) != 0 && !contains(p.ScopesSupported, "openid") {
- return errors.New("scoped_supported must be unspecified or include 'openid'")
- }
-
- if !contains(p.IDTokenSigningAlgValues, "RS256") {
- return errors.New("id_token_signing_alg_values_supported must include 'RS256'")
- }
- if contains(p.TokenEndpointAuthMethodsSupported, "none") {
- return errors.New("token_endpoint_auth_signing_alg_values_supported cannot include 'none'")
- }
-
- uris := []struct {
- val *url.URL
- name string
- required bool
- }{
- {p.Issuer, "issuer", true},
- {p.AuthEndpoint, "authorization_endpoint", true},
- {p.TokenEndpoint, "token_endpoint", !implicitOnly},
- {p.UserInfoEndpoint, "userinfo_endpoint", false},
- {p.KeysEndpoint, "jwks_uri", true},
- {p.RegistrationEndpoint, "registration_endpoint", false},
- {p.ServiceDocs, "service_documentation", false},
- {p.Policy, "op_policy_uri", false},
- {p.TermsOfService, "op_tos_uri", false},
- }
-
- for _, uri := range uris {
- if uri.val == nil {
- if !uri.required {
- continue
- }
- return fmt.Errorf("empty value for required uri field %s", uri.name)
- }
- if uri.val.Host == "" {
- return fmt.Errorf("no host for uri field %s", uri.name)
- }
- if uri.val.Scheme != "http" && uri.val.Scheme != "https" {
- return fmt.Errorf("uri field %s schemeis not http or https", uri.name)
- }
- }
- return nil
-}
-
-// Supports determines if provider supports a client given their respective metadata.
-func (p ProviderConfig) Supports(c ClientMetadata) error {
- if err := p.Valid(); err != nil {
- return fmt.Errorf("invalid provider config: %v", err)
- }
- if err := c.Valid(); err != nil {
- return fmt.Errorf("invalid client config: %v", err)
- }
-
- // Fill default values for omitted fields
- c = c.Defaults()
- p = p.Defaults()
-
- // Do the supported values list the requested one?
- supports := []struct {
- supported []string
- requested string
- name string
- }{
- {p.IDTokenSigningAlgValues, c.IDTokenResponseOptions.SigningAlg, "id_token_signed_response_alg"},
- {p.IDTokenEncryptionAlgValues, c.IDTokenResponseOptions.EncryptionAlg, "id_token_encryption_response_alg"},
- {p.IDTokenEncryptionEncValues, c.IDTokenResponseOptions.EncryptionEnc, "id_token_encryption_response_enc"},
- {p.UserInfoSigningAlgValues, c.UserInfoResponseOptions.SigningAlg, "userinfo_signed_response_alg"},
- {p.UserInfoEncryptionAlgValues, c.UserInfoResponseOptions.EncryptionAlg, "userinfo_encryption_response_alg"},
- {p.UserInfoEncryptionEncValues, c.UserInfoResponseOptions.EncryptionEnc, "userinfo_encryption_response_enc"},
- {p.ReqObjSigningAlgValues, c.RequestObjectOptions.SigningAlg, "request_object_signing_alg"},
- {p.ReqObjEncryptionAlgValues, c.RequestObjectOptions.EncryptionAlg, "request_object_encryption_alg"},
- {p.ReqObjEncryptionEncValues, c.RequestObjectOptions.EncryptionEnc, "request_object_encryption_enc"},
- }
- for _, field := range supports {
- if field.requested == "" {
- continue
- }
- if !contains(field.supported, field.requested) {
- return fmt.Errorf("provider does not support requested value for field %s", field.name)
- }
- }
-
- stringsEqual := func(s1, s2 string) bool { return s1 == s2 }
-
- // For lists, are the list of requested values a subset of the supported ones?
- supportsAll := []struct {
- supported []string
- requested []string
- name string
- // OAuth2.0 response_type can be space separated lists where order doesn't matter.
- // For example "id_token token" is the same as "token id_token"
- // Support a custom compare method.
- comp func(s1, s2 string) bool
- }{
- {p.GrantTypesSupported, c.GrantTypes, "grant_types", stringsEqual},
- {p.ResponseTypesSupported, c.ResponseTypes, "response_type", oauth2.ResponseTypesEqual},
- }
- for _, field := range supportsAll {
- requestLoop:
- for _, req := range field.requested {
- for _, sup := range field.supported {
- if field.comp(req, sup) {
- continue requestLoop
- }
- }
- return fmt.Errorf("provider does not support requested value for field %s", field.name)
- }
- }
-
- // TODO(ericchiang): Are there more checks we feel comfortable with begin strict about?
-
- return nil
-}
-
-func (p ProviderConfig) SupportsGrantType(grantType string) bool {
- var supported []string
- if len(p.GrantTypesSupported) == 0 {
- supported = DefaultGrantTypesSupported
- } else {
- supported = p.GrantTypesSupported
- }
-
- for _, t := range supported {
- if t == grantType {
- return true
- }
- }
- return false
-}
-
-type ProviderConfigGetter interface {
- Get() (ProviderConfig, error)
-}
-
-type ProviderConfigSetter interface {
- Set(ProviderConfig) error
-}
-
-type ProviderConfigSyncer struct {
- from ProviderConfigGetter
- to ProviderConfigSetter
- clock clockwork.Clock
-
- initialSyncDone bool
- initialSyncWait sync.WaitGroup
-}
-
-func NewProviderConfigSyncer(from ProviderConfigGetter, to ProviderConfigSetter) *ProviderConfigSyncer {
- return &ProviderConfigSyncer{
- from: from,
- to: to,
- clock: clockwork.NewRealClock(),
- }
-}
-
-func (s *ProviderConfigSyncer) Run() chan struct{} {
- stop := make(chan struct{})
-
- var next pcsStepper
- next = &pcsStepNext{aft: time.Duration(0)}
-
- s.initialSyncWait.Add(1)
- go func() {
- for {
- select {
- case <-s.clock.After(next.after()):
- next = next.step(s.sync)
- case <-stop:
- return
- }
- }
- }()
-
- return stop
-}
-
-func (s *ProviderConfigSyncer) WaitUntilInitialSync() {
- s.initialSyncWait.Wait()
-}
-
-func (s *ProviderConfigSyncer) sync() (time.Duration, error) {
- cfg, err := s.from.Get()
- if err != nil {
- return 0, err
- }
-
- if err = s.to.Set(cfg); err != nil {
- return 0, fmt.Errorf("error setting provider config: %v", err)
- }
-
- if !s.initialSyncDone {
- s.initialSyncWait.Done()
- s.initialSyncDone = true
- }
-
- log.Infof("Updating provider config: config=%#v", cfg)
-
- return nextSyncAfter(cfg.ExpiresAt, s.clock), nil
-}
-
-type pcsStepFunc func() (time.Duration, error)
-
-type pcsStepper interface {
- after() time.Duration
- step(pcsStepFunc) pcsStepper
-}
-
-type pcsStepNext struct {
- aft time.Duration
-}
-
-func (n *pcsStepNext) after() time.Duration {
- return n.aft
-}
-
-func (n *pcsStepNext) step(fn pcsStepFunc) (next pcsStepper) {
- ttl, err := fn()
- if err == nil {
- next = &pcsStepNext{aft: ttl}
- log.Debugf("Synced provider config, next attempt in %v", next.after())
- } else {
- next = &pcsStepRetry{aft: time.Second}
- log.Errorf("Provider config sync failed, retrying in %v: %v", next.after(), err)
- }
- return
-}
-
-type pcsStepRetry struct {
- aft time.Duration
-}
-
-func (r *pcsStepRetry) after() time.Duration {
- return r.aft
-}
-
-func (r *pcsStepRetry) step(fn pcsStepFunc) (next pcsStepper) {
- ttl, err := fn()
- if err == nil {
- next = &pcsStepNext{aft: ttl}
- log.Infof("Provider config sync no longer failing")
- } else {
- next = &pcsStepRetry{aft: timeutil.ExpBackoff(r.aft, time.Minute)}
- log.Errorf("Provider config sync still failing, retrying in %v: %v", next.after(), err)
- }
- return
-}
-
-func nextSyncAfter(exp time.Time, clock clockwork.Clock) time.Duration {
- if exp.IsZero() {
- return MaximumProviderConfigSyncInterval
- }
-
- t := exp.Sub(clock.Now()) / 2
- if t > MaximumProviderConfigSyncInterval {
- t = MaximumProviderConfigSyncInterval
- } else if t < minimumProviderConfigSyncInterval {
- t = minimumProviderConfigSyncInterval
- }
-
- return t
-}
-
-type httpProviderConfigGetter struct {
- hc phttp.Client
- issuerURL string
- clock clockwork.Clock
-}
-
-func NewHTTPProviderConfigGetter(hc phttp.Client, issuerURL string) *httpProviderConfigGetter {
- return &httpProviderConfigGetter{
- hc: hc,
- issuerURL: issuerURL,
- clock: clockwork.NewRealClock(),
- }
-}
-
-func (r *httpProviderConfigGetter) Get() (cfg ProviderConfig, err error) {
- // If the Issuer value contains a path component, any terminating / MUST be removed before
- // appending /.well-known/openid-configuration.
- // https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
- discoveryURL := strings.TrimSuffix(r.issuerURL, "/") + discoveryConfigPath
- req, err := http.NewRequest("GET", discoveryURL, nil)
- if err != nil {
- return
- }
-
- resp, err := r.hc.Do(req)
- if err != nil {
- return
- }
- defer resp.Body.Close()
-
- if err = json.NewDecoder(resp.Body).Decode(&cfg); err != nil {
- return
- }
-
- var ttl time.Duration
- var ok bool
- ttl, ok, err = phttp.Cacheable(resp.Header)
- if err != nil {
- return
- } else if ok {
- cfg.ExpiresAt = r.clock.Now().UTC().Add(ttl)
- }
-
- // The issuer value returned MUST be identical to the Issuer URL that was directly used to retrieve the configuration information.
- // http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationValidation
- if !urlEqual(cfg.Issuer.String(), r.issuerURL) {
- err = fmt.Errorf(`"issuer" in config (%v) does not match provided issuer URL (%v)`, cfg.Issuer, r.issuerURL)
- return
- }
-
- return
-}
-
-func FetchProviderConfig(hc phttp.Client, issuerURL string) (ProviderConfig, error) {
- if hc == nil {
- hc = http.DefaultClient
- }
-
- g := NewHTTPProviderConfigGetter(hc, issuerURL)
- return g.Get()
-}
-
-func WaitForProviderConfig(hc phttp.Client, issuerURL string) (pcfg ProviderConfig) {
- return waitForProviderConfig(hc, issuerURL, clockwork.NewRealClock())
-}
-
-func waitForProviderConfig(hc phttp.Client, issuerURL string, clock clockwork.Clock) (pcfg ProviderConfig) {
- var sleep time.Duration
- var err error
- for {
- pcfg, err = FetchProviderConfig(hc, issuerURL)
- if err == nil {
- break
- }
-
- sleep = timeutil.ExpBackoff(sleep, time.Minute)
- fmt.Printf("Failed fetching provider config, trying again in %v: %v\n", sleep, err)
- time.Sleep(sleep)
- }
-
- return
-}