Save an http.Client with each upstreamoidc.ProviderConfig object.

This allows the token exchange request to be performed with the correct TLS configuration.

We go to a bit of extra work to make sure the `http.Client` object is cached between reconcile operations so that connection pooling works as expected.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
Matt Moyer
2020-12-02 15:55:33 -06:00
parent c23c54f500
commit 4fe691de92
4 changed files with 33 additions and 24 deletions
@@ -70,15 +70,21 @@ type IDPCache interface {
// lruValidatorCache caches the *oidc.Provider associated with a particular issuer/TLS configuration.
type lruValidatorCache struct{ cache *cache.Expiring }
func (c *lruValidatorCache) getProvider(spec *v1alpha1.UpstreamOIDCProviderSpec) *oidc.Provider {
if result, ok := c.cache.Get(c.cacheKey(spec)); ok {
return result.(*oidc.Provider)
}
return nil
type lruValidatorCacheEntry struct {
provider *oidc.Provider
client *http.Client
}
func (c *lruValidatorCache) putProvider(spec *v1alpha1.UpstreamOIDCProviderSpec, provider *oidc.Provider) {
c.cache.Set(c.cacheKey(spec), provider, validatorCacheTTL)
func (c *lruValidatorCache) getProvider(spec *v1alpha1.UpstreamOIDCProviderSpec) (*oidc.Provider, *http.Client) {
if result, ok := c.cache.Get(c.cacheKey(spec)); ok {
entry := result.(*lruValidatorCacheEntry)
return entry.provider, entry.client
}
return nil, nil
}
func (c *lruValidatorCache) putProvider(spec *v1alpha1.UpstreamOIDCProviderSpec, provider *oidc.Provider, client *http.Client) {
c.cache.Set(c.cacheKey(spec), &lruValidatorCacheEntry{provider: provider, client: client}, validatorCacheTTL)
}
func (c *lruValidatorCache) cacheKey(spec *v1alpha1.UpstreamOIDCProviderSpec) interface{} {
@@ -97,8 +103,8 @@ type controller struct {
providers idpinformers.UpstreamOIDCProviderInformer
secrets corev1informers.SecretInformer
validatorCache interface {
getProvider(spec *v1alpha1.UpstreamOIDCProviderSpec) *oidc.Provider
putProvider(spec *v1alpha1.UpstreamOIDCProviderSpec, provider *oidc.Provider)
getProvider(*v1alpha1.UpstreamOIDCProviderSpec) (*oidc.Provider, *http.Client)
putProvider(*v1alpha1.UpstreamOIDCProviderSpec, *oidc.Provider, *http.Client)
}
}
@@ -224,6 +230,7 @@ func (c *controller) validateSecret(upstream *v1alpha1.UpstreamOIDCProvider, res
// If everything is valid, update the result and set the condition to true.
result.Config.ClientID = string(clientID)
result.Config.ClientSecret = string(clientSecret)
return &v1alpha1.Condition{
Type: typeClientCredsValid,
Status: v1alpha1.ConditionTrue,
@@ -234,8 +241,8 @@ func (c *controller) validateSecret(upstream *v1alpha1.UpstreamOIDCProvider, res
// validateIssuer validates the .spec.issuer field, performs OIDC discovery, and returns the appropriate OIDCDiscoverySucceeded condition.
func (c *controller) validateIssuer(ctx context.Context, upstream *v1alpha1.UpstreamOIDCProvider, result *upstreamoidc.ProviderConfig) *v1alpha1.Condition {
// Get the provider (from cache if possible).
discoveredProvider := c.validatorCache.getProvider(&upstream.Spec)
// Get the provider and HTTP Client from cache if possible.
discoveredProvider, httpClient := c.validatorCache.getProvider(&upstream.Spec)
// If the provider does not exist in the cache, do a fresh discovery lookup and save to the cache.
if discoveredProvider == nil {
@@ -248,7 +255,7 @@ func (c *controller) validateIssuer(ctx context.Context, upstream *v1alpha1.Upst
Message: err.Error(),
}
}
httpClient := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
httpClient = &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
discoveredProvider, err = oidc.NewProvider(oidc.ClientContext(ctx, httpClient), upstream.Spec.Issuer)
if err != nil {
@@ -261,7 +268,7 @@ func (c *controller) validateIssuer(ctx context.Context, upstream *v1alpha1.Upst
}
// Update the cache with the newly discovered value.
c.validatorCache.putProvider(&upstream.Spec, discoveredProvider)
c.validatorCache.putProvider(&upstream.Spec, discoveredProvider, httpClient)
}
// Parse out and validate the discovered authorize endpoint.
@@ -286,6 +293,7 @@ func (c *controller) validateIssuer(ctx context.Context, upstream *v1alpha1.Upst
// If everything is valid, update the result and set the condition to true.
result.Config.Endpoint = discoveredProvider.Endpoint()
result.Provider = discoveredProvider
result.Client = httpClient
return &v1alpha1.Condition{
Type: typeOIDCDiscoverySucceeded,
Status: v1alpha1.ConditionTrue,