|
|
|
|
@ -78,7 +78,7 @@ func NewClient(cfg ClientConfig) (*Client, error) {
|
|
|
|
|
httpClient: cfg.HTTPClient, |
|
|
|
|
scope: cfg.Scope, |
|
|
|
|
redirectURL: ru.String(), |
|
|
|
|
providerConfig: cfg.ProviderConfig, |
|
|
|
|
providerConfig: newProviderConfigRepo(cfg.ProviderConfig), |
|
|
|
|
keySet: cfg.KeySet, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -96,7 +96,7 @@ func NewClient(cfg ClientConfig) (*Client, error) {
|
|
|
|
|
|
|
|
|
|
type Client struct { |
|
|
|
|
httpClient phttp.Client |
|
|
|
|
providerConfig ProviderConfig |
|
|
|
|
providerConfig *providerConfigRepo |
|
|
|
|
credentials ClientCredentials |
|
|
|
|
redirectURL string |
|
|
|
|
scope []string |
|
|
|
|
@ -106,14 +106,39 @@ type Client struct {
|
|
|
|
|
lastKeySetSync time.Time |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Client) Healthy() error { |
|
|
|
|
now := time.Now().UTC() |
|
|
|
|
|
|
|
|
|
if c.providerConfig.Empty() { |
|
|
|
|
cfg := c.providerConfig.Get() |
|
|
|
|
|
|
|
|
|
if cfg.Empty() { |
|
|
|
|
return errors.New("oidc client provider config empty") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !c.providerConfig.ExpiresAt.IsZero() && c.providerConfig.ExpiresAt.Before(now) { |
|
|
|
|
if !cfg.ExpiresAt.IsZero() && cfg.ExpiresAt.Before(now) { |
|
|
|
|
return errors.New("oidc client provider config expired") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -121,7 +146,8 @@ func (c *Client) Healthy() error {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Client) OAuthClient() (*oauth2.Client, error) { |
|
|
|
|
authMethod, err := c.chooseAuthMethod() |
|
|
|
|
cfg := c.providerConfig.Get() |
|
|
|
|
authMethod, err := chooseAuthMethod(cfg) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
@ -129,8 +155,8 @@ func (c *Client) OAuthClient() (*oauth2.Client, error) {
|
|
|
|
|
ocfg := oauth2.Config{ |
|
|
|
|
Credentials: oauth2.ClientCredentials(c.credentials), |
|
|
|
|
RedirectURL: c.redirectURL, |
|
|
|
|
AuthURL: c.providerConfig.AuthEndpoint, |
|
|
|
|
TokenURL: c.providerConfig.TokenEndpoint, |
|
|
|
|
AuthURL: cfg.AuthEndpoint, |
|
|
|
|
TokenURL: cfg.TokenEndpoint, |
|
|
|
|
Scope: c.scope, |
|
|
|
|
AuthMethod: authMethod, |
|
|
|
|
} |
|
|
|
|
@ -138,12 +164,12 @@ func (c *Client) OAuthClient() (*oauth2.Client, error) {
|
|
|
|
|
return oauth2.NewClient(c.httpClient, ocfg) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Client) chooseAuthMethod() (string, error) { |
|
|
|
|
if len(c.providerConfig.TokenEndpointAuthMethodsSupported) == 0 { |
|
|
|
|
func chooseAuthMethod(cfg ProviderConfig) (string, error) { |
|
|
|
|
if len(cfg.TokenEndpointAuthMethodsSupported) == 0 { |
|
|
|
|
return oauth2.AuthMethodClientSecretBasic, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, authMethod := range c.providerConfig.TokenEndpointAuthMethodsSupported { |
|
|
|
|
for _, authMethod := range cfg.TokenEndpointAuthMethodsSupported { |
|
|
|
|
if _, ok := supportedAuthMethods[authMethod]; ok { |
|
|
|
|
return authMethod, nil |
|
|
|
|
} |
|
|
|
|
@ -153,9 +179,8 @@ func (c *Client) chooseAuthMethod() (string, error) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Client) SyncProviderConfig(discoveryURL string) chan struct{} { |
|
|
|
|
rp := &providerConfigRepo{c} |
|
|
|
|
r := NewHTTPProviderConfigGetter(c.httpClient, discoveryURL) |
|
|
|
|
return NewProviderConfigSyncer(r, rp).Run() |
|
|
|
|
return NewProviderConfigSyncer(r, c.providerConfig).Run() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Client) maybeSyncKeys() error { |
|
|
|
|
@ -178,7 +203,8 @@ func (c *Client) maybeSyncKeys() error {
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
r := NewRemotePublicKeyRepo(c.httpClient, c.providerConfig.KeysEndpoint) |
|
|
|
|
cfg := c.providerConfig.Get() |
|
|
|
|
r := NewRemotePublicKeyRepo(c.httpClient, cfg.KeysEndpoint) |
|
|
|
|
w := &clientKeyRepo{client: c} |
|
|
|
|
_, err := key.Sync(r, w) |
|
|
|
|
c.lastKeySetSync = time.Now().UTC() |
|
|
|
|
@ -186,15 +212,6 @@ func (c *Client) maybeSyncKeys() error {
|
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type providerConfigRepo struct { |
|
|
|
|
client *Client |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (r *providerConfigRepo) Set(cfg ProviderConfig) error { |
|
|
|
|
r.client.providerConfig = cfg |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type clientKeyRepo struct { |
|
|
|
|
client *Client |
|
|
|
|
} |
|
|
|
|
@ -209,7 +226,9 @@ func (r *clientKeyRepo) Set(ks key.KeySet) error {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Client) ClientCredsToken(scope []string) (jose.JWT, error) { |
|
|
|
|
if !c.providerConfig.SupportsGrantType(oauth2.GrantTypeClientCreds) { |
|
|
|
|
cfg := c.providerConfig.Get() |
|
|
|
|
|
|
|
|
|
if !cfg.SupportsGrantType(oauth2.GrantTypeClientCreds) { |
|
|
|
|
return jose.JWT{}, fmt.Errorf("%v grant type is not supported", oauth2.GrantTypeClientCreds) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -280,7 +299,7 @@ func (c *Client) VerifyJWT(jwt jose.JWT) error {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
v := NewJWTVerifier( |
|
|
|
|
c.providerConfig.Issuer, |
|
|
|
|
c.providerConfig.Get().Issuer, |
|
|
|
|
c.credentials.ID, |
|
|
|
|
c.maybeSyncKeys, keysFunc) |
|
|
|
|
|
|
|
|
|
|