aboutsummaryrefslogtreecommitdiffstats
path: root/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/client.go
diff options
context:
space:
mode:
Diffstat (limited to 'kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/client.go')
-rw-r--r--kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/client.go846
1 files changed, 0 insertions, 846 deletions
diff --git a/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/client.go b/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/client.go
deleted file mode 100644
index 7a3cb40..0000000
--- a/kube2msb/src/vendor/github.com/coreos/go-oidc/oidc/client.go
+++ /dev/null
@@ -1,846 +0,0 @@
-package oidc
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
- "net/mail"
- "net/url"
- "sync"
- "time"
-
- phttp "github.com/coreos/go-oidc/http"
- "github.com/coreos/go-oidc/jose"
- "github.com/coreos/go-oidc/key"
- "github.com/coreos/go-oidc/oauth2"
-)
-
-const (
- // amount of time that must pass after the last key sync
- // completes before another attempt may begin
- keySyncWindow = 5 * time.Second
-)
-
-var (
- DefaultScope = []string{"openid", "email", "profile"}
-
- supportedAuthMethods = map[string]struct{}{
- oauth2.AuthMethodClientSecretBasic: struct{}{},
- oauth2.AuthMethodClientSecretPost: struct{}{},
- }
-)
-
-type ClientCredentials oauth2.ClientCredentials
-
-type ClientIdentity struct {
- Credentials ClientCredentials
- Metadata ClientMetadata
-}
-
-type JWAOptions struct {
- // SigningAlg specifies an JWA alg for signing JWTs.
- //
- // Specifying this field implies different actions depending on the context. It may
- // require objects be serialized and signed as a JWT instead of plain JSON, or
- // require an existing JWT object use the specified alg.
- //
- // See: http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
- SigningAlg string
- // EncryptionAlg, if provided, specifies that the returned or sent object be stored
- // (or nested) within a JWT object and encrypted with the provided JWA alg.
- EncryptionAlg string
- // EncryptionEnc specifies the JWA enc algorithm to use with EncryptionAlg. If
- // EncryptionAlg is provided and EncryptionEnc is omitted, this field defaults
- // to A128CBC-HS256.
- //
- // If EncryptionEnc is provided EncryptionAlg must also be specified.
- EncryptionEnc string
-}
-
-func (opt JWAOptions) valid() error {
- if opt.EncryptionEnc != "" && opt.EncryptionAlg == "" {
- return errors.New("encryption encoding provided with no encryption algorithm")
- }
- return nil
-}
-
-func (opt JWAOptions) defaults() JWAOptions {
- if opt.EncryptionAlg != "" && opt.EncryptionEnc == "" {
- opt.EncryptionEnc = jose.EncA128CBCHS256
- }
- return opt
-}
-
-var (
- // Ensure ClientMetadata satisfies these interfaces.
- _ json.Marshaler = &ClientMetadata{}
- _ json.Unmarshaler = &ClientMetadata{}
-)
-
-// ClientMetadata holds metadata that the authorization server associates
-// with a client identifier. The fields range from human-facing display
-// strings such as client name, to items that impact the security of the
-// protocol, such as the list of valid redirect URIs.
-//
-// See http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
-//
-// TODO: support language specific claim representations
-// http://openid.net/specs/openid-connect-registration-1_0.html#LanguagesAndScripts
-type ClientMetadata struct {
- RedirectURIs []url.URL // Required
-
- // A list of OAuth 2.0 "response_type" values that the client wishes to restrict
- // itself to. Either "code", "token", or another registered extension.
- //
- // If omitted, only "code" will be used.
- ResponseTypes []string
- // A list of OAuth 2.0 grant types the client wishes to restrict itself to.
- // The grant type values used by OIDC are "authorization_code", "implicit",
- // and "refresh_token".
- //
- // If ommitted, only "authorization_code" will be used.
- GrantTypes []string
- // "native" or "web". If omitted, "web".
- ApplicationType string
-
- // List of email addresses.
- Contacts []mail.Address
- // Name of client to be presented to the end-user.
- ClientName string
- // URL that references a logo for the Client application.
- LogoURI *url.URL
- // URL of the home page of the Client.
- ClientURI *url.URL
- // Profile data policies and terms of use to be provided to the end user.
- PolicyURI *url.URL
- TermsOfServiceURI *url.URL
-
- // URL to or the value of the client's JSON Web Key Set document.
- JWKSURI *url.URL
- JWKS *jose.JWKSet
-
- // URL referencing a flie with a single JSON array of redirect URIs.
- SectorIdentifierURI *url.URL
-
- SubjectType string
-
- // Options to restrict the JWS alg and enc values used for server responses and requests.
- IDTokenResponseOptions JWAOptions
- UserInfoResponseOptions JWAOptions
- RequestObjectOptions JWAOptions
-
- // Client requested authorization method and signing options for the token endpoint.
- //
- // Defaults to "client_secret_basic"
- TokenEndpointAuthMethod string
- TokenEndpointAuthSigningAlg string
-
- // DefaultMaxAge specifies the maximum amount of time in seconds before an authorized
- // user must reauthroize.
- //
- // If 0, no limitation is placed on the maximum.
- DefaultMaxAge int64
- // RequireAuthTime specifies if the auth_time claim in the ID token is required.
- RequireAuthTime bool
-
- // Default Authentication Context Class Reference values for authentication requests.
- DefaultACRValues []string
-
- // URI that a third party can use to initiate a login by the relaying party.
- //
- // See: http://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin
- InitiateLoginURI *url.URL
- // Pre-registered request_uri values that may be cached by the server.
- RequestURIs []url.URL
-}
-
-// Defaults returns a shallow copy of ClientMetadata with default
-// values replacing omitted fields.
-func (m ClientMetadata) Defaults() ClientMetadata {
- if len(m.ResponseTypes) == 0 {
- m.ResponseTypes = []string{oauth2.ResponseTypeCode}
- }
- if len(m.GrantTypes) == 0 {
- m.GrantTypes = []string{oauth2.GrantTypeAuthCode}
- }
- if m.ApplicationType == "" {
- m.ApplicationType = "web"
- }
- if m.TokenEndpointAuthMethod == "" {
- m.TokenEndpointAuthMethod = oauth2.AuthMethodClientSecretBasic
- }
- m.IDTokenResponseOptions = m.IDTokenResponseOptions.defaults()
- m.UserInfoResponseOptions = m.UserInfoResponseOptions.defaults()
- m.RequestObjectOptions = m.RequestObjectOptions.defaults()
- return m
-}
-
-func (m *ClientMetadata) MarshalJSON() ([]byte, error) {
- e := m.toEncodableStruct()
- return json.Marshal(&e)
-}
-
-func (m *ClientMetadata) UnmarshalJSON(data []byte) error {
- var e encodableClientMetadata
- if err := json.Unmarshal(data, &e); err != nil {
- return err
- }
- meta, err := e.toStruct()
- if err != nil {
- return err
- }
- if err := meta.Valid(); err != nil {
- return err
- }
- *m = meta
- return nil
-}
-
-type encodableClientMetadata struct {
- RedirectURIs []string `json:"redirect_uris"` // Required
- ResponseTypes []string `json:"response_types,omitempty"`
- GrantTypes []string `json:"grant_types,omitempty"`
- ApplicationType string `json:"application_type,omitempty"`
- Contacts []string `json:"contacts,omitempty"`
- ClientName string `json:"client_name,omitempty"`
- LogoURI string `json:"logo_uri,omitempty"`
- ClientURI string `json:"client_uri,omitempty"`
- PolicyURI string `json:"policy_uri,omitempty"`
- TermsOfServiceURI string `json:"tos_uri,omitempty"`
- JWKSURI string `json:"jwks_uri,omitempty"`
- JWKS *jose.JWKSet `json:"jwks,omitempty"`
- SectorIdentifierURI string `json:"sector_identifier_uri,omitempty"`
- SubjectType string `json:"subject_type,omitempty"`
- IDTokenSignedResponseAlg string `json:"id_token_signed_response_alg,omitempty"`
- IDTokenEncryptedResponseAlg string `json:"id_token_encrypted_response_alg,omitempty"`
- IDTokenEncryptedResponseEnc string `json:"id_token_encrypted_response_enc,omitempty"`
- UserInfoSignedResponseAlg string `json:"userinfo_signed_response_alg,omitempty"`
- UserInfoEncryptedResponseAlg string `json:"userinfo_encrypted_response_alg,omitempty"`
- UserInfoEncryptedResponseEnc string `json:"userinfo_encrypted_response_enc,omitempty"`
- RequestObjectSigningAlg string `json:"request_object_signing_alg,omitempty"`
- RequestObjectEncryptionAlg string `json:"request_object_encryption_alg,omitempty"`
- RequestObjectEncryptionEnc string `json:"request_object_encryption_enc,omitempty"`
- TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
- TokenEndpointAuthSigningAlg string `json:"token_endpoint_auth_signing_alg,omitempty"`
- DefaultMaxAge int64 `json:"default_max_age,omitempty"`
- RequireAuthTime bool `json:"require_auth_time,omitempty"`
- DefaultACRValues []string `json:"default_acr_values,omitempty"`
- InitiateLoginURI string `json:"initiate_login_uri,omitempty"`
- RequestURIs []string `json:"request_uris,omitempty"`
-}
-
-func (c *encodableClientMetadata) toStruct() (ClientMetadata, error) {
- p := stickyErrParser{}
- m := ClientMetadata{
- RedirectURIs: p.parseURIs(c.RedirectURIs, "redirect_uris"),
- ResponseTypes: c.ResponseTypes,
- GrantTypes: c.GrantTypes,
- ApplicationType: c.ApplicationType,
- Contacts: p.parseEmails(c.Contacts, "contacts"),
- ClientName: c.ClientName,
- LogoURI: p.parseURI(c.LogoURI, "logo_uri"),
- ClientURI: p.parseURI(c.ClientURI, "client_uri"),
- PolicyURI: p.parseURI(c.PolicyURI, "policy_uri"),
- TermsOfServiceURI: p.parseURI(c.TermsOfServiceURI, "tos_uri"),
- JWKSURI: p.parseURI(c.JWKSURI, "jwks_uri"),
- JWKS: c.JWKS,
- SectorIdentifierURI: p.parseURI(c.SectorIdentifierURI, "sector_identifier_uri"),
- SubjectType: c.SubjectType,
- TokenEndpointAuthMethod: c.TokenEndpointAuthMethod,
- TokenEndpointAuthSigningAlg: c.TokenEndpointAuthSigningAlg,
- DefaultMaxAge: c.DefaultMaxAge,
- RequireAuthTime: c.RequireAuthTime,
- DefaultACRValues: c.DefaultACRValues,
- InitiateLoginURI: p.parseURI(c.InitiateLoginURI, "initiate_login_uri"),
- RequestURIs: p.parseURIs(c.RequestURIs, "request_uris"),
- IDTokenResponseOptions: JWAOptions{
- c.IDTokenSignedResponseAlg,
- c.IDTokenEncryptedResponseAlg,
- c.IDTokenEncryptedResponseEnc,
- },
- UserInfoResponseOptions: JWAOptions{
- c.UserInfoSignedResponseAlg,
- c.UserInfoEncryptedResponseAlg,
- c.UserInfoEncryptedResponseEnc,
- },
- RequestObjectOptions: JWAOptions{
- c.RequestObjectSigningAlg,
- c.RequestObjectEncryptionAlg,
- c.RequestObjectEncryptionEnc,
- },
- }
- if p.firstErr != nil {
- return ClientMetadata{}, p.firstErr
- }
- return m, nil
-}
-
-// stickyErrParser parses URIs and email addresses. Once it encounters
-// a parse error, subsequent calls become no-op.
-type stickyErrParser struct {
- firstErr error
-}
-
-func (p *stickyErrParser) parseURI(s, field string) *url.URL {
- if p.firstErr != nil || s == "" {
- return nil
- }
- u, err := url.Parse(s)
- if err == nil {
- if u.Host == "" {
- err = errors.New("no host in URI")
- } else if u.Scheme != "http" && u.Scheme != "https" {
- err = errors.New("invalid URI scheme")
- }
- }
- if err != nil {
- p.firstErr = fmt.Errorf("failed to parse %s: %v", field, err)
- return nil
- }
- return u
-}
-
-func (p *stickyErrParser) parseURIs(s []string, field string) []url.URL {
- if p.firstErr != nil || len(s) == 0 {
- return nil
- }
- uris := make([]url.URL, len(s))
- for i, val := range s {
- if val == "" {
- p.firstErr = fmt.Errorf("invalid URI in field %s", field)
- return nil
- }
- if u := p.parseURI(val, field); u != nil {
- uris[i] = *u
- }
- }
- return uris
-}
-
-func (p *stickyErrParser) parseEmails(s []string, field string) []mail.Address {
- if p.firstErr != nil || len(s) == 0 {
- return nil
- }
- addrs := make([]mail.Address, len(s))
- for i, addr := range s {
- if addr == "" {
- p.firstErr = fmt.Errorf("invalid email in field %s", field)
- return nil
- }
- a, err := mail.ParseAddress(addr)
- if err != nil {
- p.firstErr = fmt.Errorf("invalid email in field %s: %v", field, err)
- return nil
- }
- addrs[i] = *a
- }
- return addrs
-}
-
-func (m *ClientMetadata) toEncodableStruct() encodableClientMetadata {
- return encodableClientMetadata{
- RedirectURIs: urisToStrings(m.RedirectURIs),
- ResponseTypes: m.ResponseTypes,
- GrantTypes: m.GrantTypes,
- ApplicationType: m.ApplicationType,
- Contacts: emailsToStrings(m.Contacts),
- ClientName: m.ClientName,
- LogoURI: uriToString(m.LogoURI),
- ClientURI: uriToString(m.ClientURI),
- PolicyURI: uriToString(m.PolicyURI),
- TermsOfServiceURI: uriToString(m.TermsOfServiceURI),
- JWKSURI: uriToString(m.JWKSURI),
- JWKS: m.JWKS,
- SectorIdentifierURI: uriToString(m.SectorIdentifierURI),
- SubjectType: m.SubjectType,
- IDTokenSignedResponseAlg: m.IDTokenResponseOptions.SigningAlg,
- IDTokenEncryptedResponseAlg: m.IDTokenResponseOptions.EncryptionAlg,
- IDTokenEncryptedResponseEnc: m.IDTokenResponseOptions.EncryptionEnc,
- UserInfoSignedResponseAlg: m.UserInfoResponseOptions.SigningAlg,
- UserInfoEncryptedResponseAlg: m.UserInfoResponseOptions.EncryptionAlg,
- UserInfoEncryptedResponseEnc: m.UserInfoResponseOptions.EncryptionEnc,
- RequestObjectSigningAlg: m.RequestObjectOptions.SigningAlg,
- RequestObjectEncryptionAlg: m.RequestObjectOptions.EncryptionAlg,
- RequestObjectEncryptionEnc: m.RequestObjectOptions.EncryptionEnc,
- TokenEndpointAuthMethod: m.TokenEndpointAuthMethod,
- TokenEndpointAuthSigningAlg: m.TokenEndpointAuthSigningAlg,
- DefaultMaxAge: m.DefaultMaxAge,
- RequireAuthTime: m.RequireAuthTime,
- DefaultACRValues: m.DefaultACRValues,
- InitiateLoginURI: uriToString(m.InitiateLoginURI),
- RequestURIs: urisToStrings(m.RequestURIs),
- }
-}
-
-func uriToString(u *url.URL) string {
- if u == nil {
- return ""
- }
- return u.String()
-}
-
-func urisToStrings(urls []url.URL) []string {
- if len(urls) == 0 {
- return nil
- }
- sli := make([]string, len(urls))
- for i, u := range urls {
- sli[i] = u.String()
- }
- return sli
-}
-
-func emailsToStrings(addrs []mail.Address) []string {
- if len(addrs) == 0 {
- return nil
- }
- sli := make([]string, len(addrs))
- for i, addr := range addrs {
- sli[i] = addr.String()
- }
- return sli
-}
-
-// Valid determines if a ClientMetadata conforms with the OIDC specification.
-//
-// 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 (m *ClientMetadata) Valid() error {
- if len(m.RedirectURIs) == 0 {
- return errors.New("zero redirect URLs")
- }
-
- validURI := func(u *url.URL, fieldName string) error {
- if u.Host == "" {
- return fmt.Errorf("no host for uri field %s", fieldName)
- }
- if u.Scheme != "http" && u.Scheme != "https" {
- return fmt.Errorf("uri field %s scheme is not http or https", fieldName)
- }
- return nil
- }
-
- uris := []struct {
- val *url.URL
- name string
- }{
- {m.LogoURI, "logo_uri"},
- {m.ClientURI, "client_uri"},
- {m.PolicyURI, "policy_uri"},
- {m.TermsOfServiceURI, "tos_uri"},
- {m.JWKSURI, "jwks_uri"},
- {m.SectorIdentifierURI, "sector_identifier_uri"},
- {m.InitiateLoginURI, "initiate_login_uri"},
- }
-
- for _, uri := range uris {
- if uri.val == nil {
- continue
- }
- if err := validURI(uri.val, uri.name); err != nil {
- return err
- }
- }
-
- uriLists := []struct {
- vals []url.URL
- name string
- }{
- {m.RedirectURIs, "redirect_uris"},
- {m.RequestURIs, "request_uris"},
- }
- for _, list := range uriLists {
- for _, uri := range list.vals {
- if err := validURI(&uri, list.name); err != nil {
- return err
- }
- }
- }
-
- options := []struct {
- option JWAOptions
- name string
- }{
- {m.IDTokenResponseOptions, "id_token response"},
- {m.UserInfoResponseOptions, "userinfo response"},
- {m.RequestObjectOptions, "request_object"},
- }
- for _, option := range options {
- if err := option.option.valid(); err != nil {
- return fmt.Errorf("invalid JWA values for %s: %v", option.name, err)
- }
- }
- return nil
-}
-
-type ClientRegistrationResponse struct {
- ClientID string // Required
- ClientSecret string
- RegistrationAccessToken string
- RegistrationClientURI string
- // If IsZero is true, unspecified.
- ClientIDIssuedAt time.Time
- // Time at which the client_secret will expire.
- // If IsZero is true, it will not expire.
- ClientSecretExpiresAt time.Time
-
- ClientMetadata
-}
-
-type encodableClientRegistrationResponse struct {
- ClientID string `json:"client_id"` // Required
- ClientSecret string `json:"client_secret,omitempty"`
- RegistrationAccessToken string `json:"registration_access_token,omitempty"`
- RegistrationClientURI string `json:"registration_client_uri,omitempty"`
- ClientIDIssuedAt int64 `json:"client_id_issued_at,omitempty"`
- // Time at which the client_secret will expire, in seconds since the epoch.
- // If 0 it will not expire.
- ClientSecretExpiresAt int64 `json:"client_secret_expires_at"` // Required
-
- encodableClientMetadata
-}
-
-func unixToSec(t time.Time) int64 {
- if t.IsZero() {
- return 0
- }
- return t.Unix()
-}
-
-func (c *ClientRegistrationResponse) MarshalJSON() ([]byte, error) {
- e := encodableClientRegistrationResponse{
- ClientID: c.ClientID,
- ClientSecret: c.ClientSecret,
- RegistrationAccessToken: c.RegistrationAccessToken,
- RegistrationClientURI: c.RegistrationClientURI,
- ClientIDIssuedAt: unixToSec(c.ClientIDIssuedAt),
- ClientSecretExpiresAt: unixToSec(c.ClientSecretExpiresAt),
- encodableClientMetadata: c.ClientMetadata.toEncodableStruct(),
- }
- return json.Marshal(&e)
-}
-
-func secToUnix(sec int64) time.Time {
- if sec == 0 {
- return time.Time{}
- }
- return time.Unix(sec, 0)
-}
-
-func (c *ClientRegistrationResponse) UnmarshalJSON(data []byte) error {
- var e encodableClientRegistrationResponse
- if err := json.Unmarshal(data, &e); err != nil {
- return err
- }
- if e.ClientID == "" {
- return errors.New("no client_id in client registration response")
- }
- metadata, err := e.encodableClientMetadata.toStruct()
- if err != nil {
- return err
- }
- *c = ClientRegistrationResponse{
- ClientID: e.ClientID,
- ClientSecret: e.ClientSecret,
- RegistrationAccessToken: e.RegistrationAccessToken,
- RegistrationClientURI: e.RegistrationClientURI,
- ClientIDIssuedAt: secToUnix(e.ClientIDIssuedAt),
- ClientSecretExpiresAt: secToUnix(e.ClientSecretExpiresAt),
- ClientMetadata: metadata,
- }
- return nil
-}
-
-type ClientConfig struct {
- HTTPClient phttp.Client
- Credentials ClientCredentials
- Scope []string
- RedirectURL string
- ProviderConfig ProviderConfig
- KeySet key.PublicKeySet
-}
-
-func NewClient(cfg ClientConfig) (*Client, error) {
- // Allow empty redirect URL in the case where the client
- // only needs to verify a given token.
- ru, err := url.Parse(cfg.RedirectURL)
- if err != nil {
- return nil, fmt.Errorf("invalid redirect URL: %v", err)
- }
-
- c := Client{
- credentials: cfg.Credentials,
- httpClient: cfg.HTTPClient,
- scope: cfg.Scope,
- redirectURL: ru.String(),
- providerConfig: newProviderConfigRepo(cfg.ProviderConfig),
- keySet: cfg.KeySet,
- }
-
- if c.httpClient == nil {
- c.httpClient = http.DefaultClient
- }
-
- if c.scope == nil {
- c.scope = make([]string, len(DefaultScope))
- copy(c.scope, DefaultScope)
- }
-
- return &c, nil
-}
-
-type Client struct {
- httpClient phttp.Client
- providerConfig *providerConfigRepo
- credentials ClientCredentials
- redirectURL string
- scope []string
- keySet key.PublicKeySet
- providerSyncer *ProviderConfigSyncer
-
- keySetSyncMutex sync.RWMutex
- lastKeySetSync time.Time
-}
-
-func (c *Client) Healthy() error {
- now := time.Now().UTC()
-
- cfg := c.providerConfig.Get()
-
- if cfg.Empty() {
- return errors.New("oidc client provider config empty")
- }
-
- if !cfg.ExpiresAt.IsZero() && cfg.ExpiresAt.Before(now) {
- return errors.New("oidc client provider config expired")
- }
-
- return nil
-}
-
-func (c *Client) OAuthClient() (*oauth2.Client, error) {
- cfg := c.providerConfig.Get()
- authMethod, err := chooseAuthMethod(cfg)
- if err != nil {
- return nil, err
- }
-
- ocfg := oauth2.Config{
- Credentials: oauth2.ClientCredentials(c.credentials),
- RedirectURL: c.redirectURL,
- AuthURL: cfg.AuthEndpoint.String(),
- TokenURL: cfg.TokenEndpoint.String(),
- Scope: c.scope,
- AuthMethod: authMethod,
- }
-
- return oauth2.NewClient(c.httpClient, ocfg)
-}
-
-func chooseAuthMethod(cfg ProviderConfig) (string, error) {
- if len(cfg.TokenEndpointAuthMethodsSupported) == 0 {
- return oauth2.AuthMethodClientSecretBasic, nil
- }
-
- for _, authMethod := range cfg.TokenEndpointAuthMethodsSupported {
- if _, ok := supportedAuthMethods[authMethod]; ok {
- return authMethod, nil
- }
- }
-
- return "", errors.New("no supported auth methods")
-}
-
-// SyncProviderConfig starts the provider config syncer
-func (c *Client) SyncProviderConfig(discoveryURL string) chan struct{} {
- r := NewHTTPProviderConfigGetter(c.httpClient, discoveryURL)
- s := NewProviderConfigSyncer(r, c.providerConfig)
- stop := s.Run()
- s.WaitUntilInitialSync()
- return stop
-}
-
-func (c *Client) maybeSyncKeys() error {
- tooSoon := func() bool {
- return time.Now().UTC().Before(c.lastKeySetSync.Add(keySyncWindow))
- }
-
- // ignore request to sync keys if a sync operation has been
- // attempted too recently
- if tooSoon() {
- return nil
- }
-
- c.keySetSyncMutex.Lock()
- defer c.keySetSyncMutex.Unlock()
-
- // check again, as another goroutine may have been holding
- // the lock while updating the keys
- if tooSoon() {
- return nil
- }
-
- cfg := c.providerConfig.Get()
- r := NewRemotePublicKeyRepo(c.httpClient, cfg.KeysEndpoint.String())
- w := &clientKeyRepo{client: c}
- _, err := key.Sync(r, w)
- c.lastKeySetSync = time.Now().UTC()
-
- return err
-}
-
-type clientKeyRepo struct {
- client *Client
-}
-
-func (r *clientKeyRepo) Set(ks key.KeySet) error {
- pks, ok := ks.(*key.PublicKeySet)
- if !ok {
- return errors.New("unable to cast to PublicKey")
- }
- r.client.keySet = *pks
- return nil
-}
-
-func (c *Client) ClientCredsToken(scope []string) (jose.JWT, error) {
- cfg := c.providerConfig.Get()
-
- if !cfg.SupportsGrantType(oauth2.GrantTypeClientCreds) {
- return jose.JWT{}, fmt.Errorf("%v grant type is not supported", oauth2.GrantTypeClientCreds)
- }
-
- oac, err := c.OAuthClient()
- if err != nil {
- return jose.JWT{}, err
- }
-
- t, err := oac.ClientCredsToken(scope)
- if err != nil {
- return jose.JWT{}, err
- }
-
- jwt, err := jose.ParseJWT(t.IDToken)
- if err != nil {
- return jose.JWT{}, err
- }
-
- return jwt, c.VerifyJWT(jwt)
-}
-
-// ExchangeAuthCode exchanges an OAuth2 auth code for an OIDC JWT ID token.
-func (c *Client) ExchangeAuthCode(code string) (jose.JWT, error) {
- oac, err := c.OAuthClient()
- if err != nil {
- return jose.JWT{}, err
- }
-
- t, err := oac.RequestToken(oauth2.GrantTypeAuthCode, code)
- if err != nil {
- return jose.JWT{}, err
- }
-
- jwt, err := jose.ParseJWT(t.IDToken)
- if err != nil {
- return jose.JWT{}, err
- }
-
- return jwt, c.VerifyJWT(jwt)
-}
-
-// RefreshToken uses a refresh token to exchange for a new OIDC JWT ID Token.
-func (c *Client) RefreshToken(refreshToken string) (jose.JWT, error) {
- oac, err := c.OAuthClient()
- if err != nil {
- return jose.JWT{}, err
- }
-
- t, err := oac.RequestToken(oauth2.GrantTypeRefreshToken, refreshToken)
- if err != nil {
- return jose.JWT{}, err
- }
-
- jwt, err := jose.ParseJWT(t.IDToken)
- if err != nil {
- return jose.JWT{}, err
- }
-
- return jwt, c.VerifyJWT(jwt)
-}
-
-func (c *Client) VerifyJWT(jwt jose.JWT) error {
- var keysFunc func() []key.PublicKey
- if kID, ok := jwt.KeyID(); ok {
- keysFunc = c.keysFuncWithID(kID)
- } else {
- keysFunc = c.keysFuncAll()
- }
-
- v := NewJWTVerifier(
- c.providerConfig.Get().Issuer.String(),
- c.credentials.ID,
- c.maybeSyncKeys, keysFunc)
-
- return v.Verify(jwt)
-}
-
-// keysFuncWithID returns a function that retrieves at most unexpired
-// public key from the Client that matches the provided ID
-func (c *Client) keysFuncWithID(kID string) func() []key.PublicKey {
- return func() []key.PublicKey {
- c.keySetSyncMutex.RLock()
- defer c.keySetSyncMutex.RUnlock()
-
- if c.keySet.ExpiresAt().Before(time.Now()) {
- return []key.PublicKey{}
- }
-
- k := c.keySet.Key(kID)
- if k == nil {
- return []key.PublicKey{}
- }
-
- return []key.PublicKey{*k}
- }
-}
-
-// keysFuncAll returns a function that retrieves all unexpired public
-// keys from the Client
-func (c *Client) keysFuncAll() func() []key.PublicKey {
- return func() []key.PublicKey {
- c.keySetSyncMutex.RLock()
- defer c.keySetSyncMutex.RUnlock()
-
- if c.keySet.ExpiresAt().Before(time.Now()) {
- return []key.PublicKey{}
- }
-
- return c.keySet.Keys()
- }
-}
-
-type providerConfigRepo struct {
- mu sync.RWMutex
- config ProviderConfig // do not access directly, use Get()
-}
-
-func newProviderConfigRepo(pc ProviderConfig) *providerConfigRepo {
- return &providerConfigRepo{sync.RWMutex{}, pc}
-}
-
-// returns an error to implement ProviderConfigSetter
-func (r *providerConfigRepo) Set(cfg ProviderConfig) error {
- r.mu.Lock()
- defer r.mu.Unlock()
- r.config = cfg
- return nil
-}
-
-func (r *providerConfigRepo) Get() ProviderConfig {
- r.mu.RLock()
- defer r.mu.RUnlock()
- return r.config
-}