diff --git a/google/appengine.go b/google/appengine.go index 433bcf8..506db23 100644 --- a/google/appengine.go +++ b/google/appengine.go @@ -12,31 +12,32 @@ import ( // AppEngineConfig represents a configuration for an // App Engine application's Google service account. type AppEngineConfig struct { - // Default transport to be used while constructing + // Transport represents the default transport to be used while constructing // oauth2.Transport instances from this configuration. Transport *urlfetch.Transport - context appengine.Context - scopes []string + + context appengine.Context + scopes []string } // NewAppEngineConfig creates a new AppEngineConfig for the // provided auth scopes. func NewAppEngineConfig(context appengine.Context, scopes []string) *AppEngineConfig { - return &AppEngineConfig{context: context, scopes: scopes} + return &AppEngineConfig{ + Transport: &urlfetch.Transport{ + Context: context, + Deadline: 0, + AllowInvalidServerCertificate: false, + }, + context: context, + scopes: scopes, + } } // NewTransport returns a transport that authorizes // the requests with the application's service account. func (c *AppEngineConfig) NewTransport() *oauth2.Transport { - if c.Transport != nil { - return oauth2.NewTransport(c.Transport, c, nil) - } - transport := &urlfetch.Transport{ - Context: c.context, - Deadline: 0, - AllowInvalidServerCertificate: false, - } - return oauth2.NewTransport(transport, c, nil) + return oauth2.NewTransport(c.Transport, c, nil) } // FetchToken fetches a new access token for the provided scopes. diff --git a/google/appenginevm.go b/google/appenginevm.go index 848185f..ae466e4 100644 --- a/google/appenginevm.go +++ b/google/appenginevm.go @@ -3,29 +3,40 @@ package google import ( - "net/http" - "github.com/golang/oauth2" "google.golang.org/appengine" + "google.golang.org/appengine/urlfetch" ) // AppEngineConfig represents a configuration for an // App Engine application's Google service account. type AppEngineConfig struct { - context appengine.Context - scopes []string + // Transport represents the default transport to be used while constructing + // oauth2.Transport instances from this configuration. + Transport *urlfetch.Transport + context appengine.Context + + scopes []string } // NewAppEngineConfig creates a new AppEngineConfig for the // provided auth scopes. func NewAppEngineConfig(context appengine.Context, scopes []string) *AppEngineConfig { - return &AppEngineConfig{context: context, scopes: scopes} + return &AppEngineConfig{ + Transport: &urlfetch.Transport{ + Context: context, + Deadline: 0, + AllowInvalidServerCertificate: false, + }, + context: context, + scopes: scopes, + } } // NewTransport returns a transport that authorizes // the requests with the application's service account. func (c *AppEngineConfig) NewTransport() *oauth2.Transport { - return oauth2.NewTransport(http.DefaultTransport, c, nil) + return oauth2.NewTransport(c.Transport, c, nil) } // FetchToken fetches a new access token for the provided scopes. diff --git a/google/google.go b/google/google.go index db95b92..a9d2d95 100644 --- a/google/google.go +++ b/google/google.go @@ -37,6 +37,15 @@ type metaTokenRespBody struct { // ComputeEngineConfig represents a OAuth 2.0 consumer client // running on Google Compute Engine. type ComputeEngineConfig struct { + // Client is the default HTTP client to be used while retrieving + // tokens from the OAuth 2.0 provider. + Client *http.Client + + // Transport represents the default round tripper to be used + // while constructing new oauth2.Transport instances from + // this configuration. + Transport http.RoundTripper + account string } @@ -56,12 +65,16 @@ func NewServiceAccountConfig(opts *oauth2.JWTOptions) (*oauth2.JWTConfig, error) // from Google Compute Engine instance's metaserver. If no account is // provided, default is used. func NewComputeEngineConfig(account string) *ComputeEngineConfig { - return &ComputeEngineConfig{account: account} + return &ComputeEngineConfig{ + Client: http.DefaultClient, + Transport: http.DefaultTransport, + account: account, + } } // NewTransport creates an authorized transport. func (c *ComputeEngineConfig) NewTransport() *oauth2.Transport { - return oauth2.NewTransport(http.DefaultTransport, c, nil) + return oauth2.NewTransport(c.Transport, c, nil) } // FetchToken retrieves a new access token via metadata server. @@ -76,7 +89,7 @@ func (c *ComputeEngineConfig) FetchToken(existing *oauth2.Token) (token *oauth2. return } req.Header.Add("X-Google-Metadata-Request", "True") - resp, err := http.DefaultClient.Do(req) + resp, err := c.Client.Do(req) if err != nil { return } diff --git a/jwt.go b/jwt.go index 6328586..ba83c1b 100644 --- a/jwt.go +++ b/jwt.go @@ -55,12 +55,27 @@ func NewJWTConfig(opts *JWTOptions, aud string) (*JWTConfig, error) { if err != nil { return nil, err } - return &JWTConfig{opts: opts, aud: audURL, key: parsedKey}, nil + return &JWTConfig{ + Client: http.DefaultClient, + Transport: http.DefaultTransport, + opts: opts, + aud: audURL, + key: parsedKey, + }, nil } // JWTConfig represents an OAuth 2.0 provider and client options to // provide authorized transports with a Bearer JWT token. type JWTConfig struct { + // Client is the default HTTP client to be used while retrieving + // tokens from the OAuth 2.0 provider. + Client *http.Client + + // Transport represents the default round tripper to be used + // while constructing new oauth2.Transport instances from + // this configuration. + Transport http.RoundTripper + opts *JWTOptions aud *url.URL key *rsa.PrivateKey @@ -69,13 +84,13 @@ type JWTConfig struct { // NewTransport creates a transport that is authorize with the // parent JWT configuration. func (c *JWTConfig) NewTransport() *Transport { - return NewTransport(http.DefaultTransport, c, &Token{}) + return NewTransport(c.Transport, c, &Token{}) } // NewTransportWithUser creates a transport that is authorized by // the client and impersonates the specified user. func (c *JWTConfig) NewTransportWithUser(user string) *Transport { - return NewTransport(http.DefaultTransport, c, &Token{Subject: user}) + return NewTransport(c.Transport, c, &Token{Subject: user}) } // fetchToken retrieves a new access token and updates the existing token @@ -107,7 +122,7 @@ func (c *JWTConfig) FetchToken(existing *Token) (token *Token, err error) { v.Set("assertion", payload) // Make a request with assertion to get a new token. - resp, err := http.DefaultClient.PostForm(c.aud.String(), v) + resp, err := c.Client.PostForm(c.aud.String(), v) if err != nil { return nil, err } diff --git a/oauth2.go b/oauth2.go index 8b3cb5e..936b2d4 100644 --- a/oauth2.go +++ b/oauth2.go @@ -96,7 +96,13 @@ func NewConfig(opts *Options, authURL, tokenURL string) (*Config, error) { if err != nil { return nil, err } - conf := &Config{opts: opts, authURL: aURL, tokenURL: tURL} + conf := &Config{ + Client: http.DefaultClient, + Transport: http.DefaultTransport, + opts: opts, + authURL: aURL, + tokenURL: tURL, + } if err = conf.validate(); err != nil { return nil, err } @@ -105,6 +111,15 @@ func NewConfig(opts *Options, authURL, tokenURL string) (*Config, error) { // Config represents the configuration of an OAuth 2.0 consumer client. type Config struct { + // Client is the default HTTP client to be used while retrieving + // tokens from the OAuth 2.0 provider. + Client *http.Client + + // Transport represents the default round tripper to be used + // while constructing new oauth2.Transport instances from + // this configuration. + Transport http.RoundTripper + opts *Options // AuthURL is the URL the user will be directed to // in order to grant access. @@ -151,7 +166,7 @@ func (c *Config) AuthCodeURL(state string) (authURL string) { // t.SetToken(validToken) // func (c *Config) NewTransport() *Transport { - return NewTransport(http.DefaultTransport, c, nil) + return NewTransport(c.Transport, c, nil) } // NewTransportWithCode exchanges the OAuth 2.0 authorization code with @@ -163,7 +178,7 @@ func (c *Config) NewTransportWithCode(code string) (*Transport, error) { if err != nil { return nil, err } - return NewTransport(http.DefaultTransport, c, token), nil + return NewTransport(c.Transport, c, token), nil } // FetchToken retrieves a new access token and updates the existing token @@ -183,10 +198,10 @@ func (c *Config) FetchToken(existing *Token) (*Token, error) { // Checks if all required configuration fields have non-zero values. func (c *Config) validate() error { if c.opts.ClientID == "" { - return errors.New("A client ID should be provided.") + return errors.New("oauth2: missing client ID") } if c.opts.ClientSecret == "" { - return errors.New("A client secret should be provided.") + return errors.New("oauth2: missing client secret") } return nil } @@ -216,7 +231,7 @@ func (c *Config) retrieveToken(v url.Values) (*Token, error) { // Dropbox accepts either, but not both. // The spec requires servers to always support the Authorization header, // so that's all we use. - r, err := http.DefaultClient.PostForm(c.tokenURL.String(), v) + r, err := c.Client.PostForm(c.tokenURL.String(), v) if err != nil { return nil, err }