Tweak timeouts in oidcclient package.

- The overall timeout for logins is increased to 90 minutes.
- The timeout for token refresh is increased from 30 seconds to 60 seconds to be a bit more tolerant of extremely slow networks.
- A new, matching timeout of 60 seconds has been added for the OIDC discovery, auth code exchange, and RFC8693 token exchange operations.

The new code uses the `http.Client.Timeout` field rather than managing contexts on individual requests. This is easier because the OIDC package stores a context at creation time and tries to use it later when performing key refresh operations.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
Matt Moyer 2020-12-15 22:11:49 -06:00
parent 2840e4e152
commit 01b6bf7850
No known key found for this signature in database
GPG Key ID: EAE88AD172C5AE2D

View File

@ -37,9 +37,13 @@ const (
// API operation. // API operation.
minIDTokenValidity = 10 * time.Minute minIDTokenValidity = 10 * time.Minute
// refreshTimeout is the amount of time allotted for OAuth2 refresh operations. Since these don't involve any // httpRequestTimeout is the timeout for operations that involve one (or a few) non-interactive HTTPS requests.
// user interaction, they should always be roughly as fast as network latency. // Since these don't involve any user interaction, they should always be roughly as fast as network latency.
refreshTimeout = 30 * time.Second httpRequestTimeout = 60 * time.Second
// overallTimeout is the overall time that a login is allowed to take. This includes several user interactions, so
// we set this to be relatively long.
overallTimeout = 90 * time.Minute
) )
type handlerState struct { type handlerState struct {
@ -198,8 +202,13 @@ func Login(issuer string, clientID string, opts ...Option) (*oidctypes.Token, er
} }
} }
// Copy the configured HTTP client to set a request timeout (the Go default client has no timeout configured).
httpClientWithTimeout := *h.httpClient
httpClientWithTimeout.Timeout = httpRequestTimeout
h.httpClient = &httpClientWithTimeout
// Always set a long, but non-infinite timeout for this operation. // Always set a long, but non-infinite timeout for this operation.
ctx, cancel := context.WithTimeout(h.ctx, 10*time.Minute) ctx, cancel := context.WithTimeout(h.ctx, overallTimeout)
defer cancel() defer cancel()
ctx = oidc.ClientContext(ctx, h.httpClient) ctx = oidc.ClientContext(ctx, h.httpClient)
h.ctx = ctx h.ctx = ctx
@ -404,8 +413,6 @@ func (h *handlerState) tokenExchangeRFC8693(baseToken *oidctypes.Token) (*oidcty
} }
func (h *handlerState) handleRefresh(ctx context.Context, refreshToken *oidctypes.RefreshToken) (*oidctypes.Token, error) { func (h *handlerState) handleRefresh(ctx context.Context, refreshToken *oidctypes.RefreshToken) (*oidctypes.Token, error) {
ctx, cancel := context.WithTimeout(ctx, refreshTimeout)
defer cancel()
refreshSource := h.oauth2Config.TokenSource(ctx, &oauth2.Token{RefreshToken: refreshToken.Token}) refreshSource := h.oauth2Config.TokenSource(ctx, &oauth2.Token{RefreshToken: refreshToken.Token})
refreshed, err := refreshSource.Token() refreshed, err := refreshSource.Token()
@ -473,7 +480,7 @@ func (h *handlerState) serve(listener net.Listener) func() {
return func() { return func() {
// Gracefully shut down the server, allowing up to 5 seconds for // Gracefully shut down the server, allowing up to 5 seconds for
// clients to receive any in-flight responses. // clients to receive any in-flight responses.
shutdownCtx, cancel := context.WithTimeout(h.ctx, 1*time.Second) shutdownCtx, cancel := context.WithTimeout(h.ctx, 5*time.Second)
_ = srv.Shutdown(shutdownCtx) _ = srv.Shutdown(shutdownCtx)
cancel() cancel()
} }