oauth2: don't use http.DefaultTransport.

http.DefaultTransport is not available on App Engine.
This commit is contained in:
Burcu Dogan 2014-07-11 10:57:28 -07:00
parent 958c47866e
commit 0f597d5ad4
8 changed files with 37 additions and 27 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/golang/oauth2" "github.com/golang/oauth2"
"appengine" "appengine"
"appengine/urlfetch"
) )
// AppEngineConfig represents a configuration for an // AppEngineConfig represents a configuration for an
@ -26,7 +27,12 @@ func NewAppEngineConfig(context appengine.Context, scopes []string) *AppEngineCo
// NewTransport returns a transport that authorizes // NewTransport returns a transport that authorizes
// the requests with the application's service account. // the requests with the application's service account.
func (c *AppEngineConfig) NewTransport() oauth2.Transport { func (c *AppEngineConfig) NewTransport() oauth2.Transport {
return oauth2.NewAuthorizedTransport(c, nil) transport := &urlfetch.Transport{
Context: c.context,
Deadline: 0,
AllowInvalidServerCertificate: false,
}
return oauth2.NewAuthorizedTransport(transport, c, nil)
} }
// FetchToken fetches a new access token for the provided scopes. // FetchToken fetches a new access token for the provided scopes.

View File

@ -3,6 +3,7 @@
package google package google
import ( import (
"net/http"
"strings" "strings"
"github.com/golang/oauth2" "github.com/golang/oauth2"
@ -25,7 +26,7 @@ func NewAppEngineConfig(context appengine.Context, scopes []string) *AppEngineCo
// NewTransport returns a transport that authorizes // NewTransport returns a transport that authorizes
// the requests with the application's service account. // the requests with the application's service account.
func (c *AppEngineConfig) NewTransport() oauth2.Transport { func (c *AppEngineConfig) NewTransport() oauth2.Transport {
return oauth2.NewAuthorizedTransport(c, nil) return oauth2.NewAuthorizedTransport(http.DefaultTransport, c, nil)
} }
// FetchToken fetches a new access token for the provided scopes. // FetchToken fetches a new access token for the provided scopes.

View File

@ -61,7 +61,7 @@ func NewComputeEngineConfig(account string) *ComputeEngineConfig {
// NewTransport creates an authorized transport. // NewTransport creates an authorized transport.
func (c *ComputeEngineConfig) NewTransport() oauth2.Transport { func (c *ComputeEngineConfig) NewTransport() oauth2.Transport {
return oauth2.NewAuthorizedTransport(c, nil) return oauth2.NewAuthorizedTransport(http.DefaultTransport, c, nil)
} }
// FetchToken retrieves a new access token via metadata server. // FetchToken retrieves a new access token via metadata server.
@ -76,7 +76,7 @@ func (c *ComputeEngineConfig) FetchToken(existing *oauth2.Token) (token *oauth2.
return return
} }
req.Header.Add("X-Google-Metadata-Request", "True") req.Header.Add("X-Google-Metadata-Request", "True")
resp, err := (&http.Client{Transport: oauth2.DefaultTransport}).Do(req) resp, err := (&http.Client{}).Do(req)
if err != nil { if err != nil {
return return
} }

6
jwt.go
View File

@ -61,13 +61,13 @@ type JWTConfig struct {
// NewTransport creates a transport that is authorize with the // NewTransport creates a transport that is authorize with the
// parent JWT configuration. // parent JWT configuration.
func (c *JWTConfig) NewTransport() Transport { func (c *JWTConfig) NewTransport() Transport {
return NewAuthorizedTransport(c, &Token{}) return NewAuthorizedTransport(http.DefaultTransport, c, &Token{})
} }
// NewTransportWithUser creates a transport that is authorized by // NewTransportWithUser creates a transport that is authorized by
// the client and impersonates the specified user. // the client and impersonates the specified user.
func (c *JWTConfig) NewTransportWithUser(user string) Transport { func (c *JWTConfig) NewTransportWithUser(user string) Transport {
return NewAuthorizedTransport(c, &Token{Subject: user}) return NewAuthorizedTransport(http.DefaultTransport, c, &Token{Subject: user})
} }
// fetchToken retrieves a new access token and updates the existing token // fetchToken retrieves a new access token and updates the existing token
@ -100,7 +100,7 @@ func (c *JWTConfig) FetchToken(existing *Token) (token *Token, err error) {
v.Set("assertion", payload) v.Set("assertion", payload)
// Make a request with assertion to get a new token. // Make a request with assertion to get a new token.
client := http.Client{Transport: DefaultTransport} client := http.Client{}
resp, err := client.PostForm(c.aud, v) resp, err := client.PostForm(c.aud, v)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -18,10 +18,6 @@ import (
"time" "time"
) )
// The default transport implementation to be used while
// making the authorized requests.
var DefaultTransport = http.DefaultTransport
type tokenRespBody struct { type tokenRespBody struct {
AccessToken string `json:"access_token"` AccessToken string `json:"access_token"`
TokenType string `json:"token_type"` TokenType string `json:"token_type"`
@ -138,7 +134,7 @@ func (c *Config) AuthCodeURL(state string) (authURL string, err error) {
// t.SetToken(validToken) // t.SetToken(validToken)
// //
func (c *Config) NewTransport() Transport { func (c *Config) NewTransport() Transport {
return NewAuthorizedTransport(c, nil) return NewAuthorizedTransport(http.DefaultTransport, c, nil)
} }
// NewTransportWithCode exchanges the OAuth 2.0 exchange code with // NewTransportWithCode exchanges the OAuth 2.0 exchange code with
@ -150,7 +146,7 @@ func (c *Config) NewTransportWithCode(exchangeCode string) (Transport, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewAuthorizedTransport(c, token), nil return NewAuthorizedTransport(http.DefaultTransport, c, token), nil
} }
// FetchToken retrieves a new access token and updates the existing token // FetchToken retrieves a new access token and updates the existing token
@ -210,7 +206,7 @@ func (c *Config) exchange(exchangeCode string) (*Token, error) {
func (c *Config) updateToken(tok *Token, v url.Values) error { func (c *Config) updateToken(tok *Token, v url.Values) error {
v.Set("client_id", c.opts.ClientID) v.Set("client_id", c.opts.ClientID)
v.Set("client_secret", c.opts.ClientSecret) v.Set("client_secret", c.opts.ClientSecret)
r, err := (&http.Client{Transport: DefaultTransport}).PostForm(c.tokenURL, v) r, err := (&http.Client{}).PostForm(c.tokenURL, v)
if err != nil { if err != nil {
return err return err
} }

View File

@ -35,8 +35,6 @@ func newTestConf() *Config {
} }
func TestAuthCodeURL(t *testing.T) { func TestAuthCodeURL(t *testing.T) {
DefaultTransport = http.DefaultTransport
conf := newTestConf() conf := newTestConf()
url, err := conf.AuthCodeURL("foo") url, err := conf.AuthCodeURL("foo")
if err != nil { if err != nil {
@ -48,8 +46,13 @@ func TestAuthCodeURL(t *testing.T) {
} }
func TestExchangePayload(t *testing.T) { func TestExchangePayload(t *testing.T) {
oldDefaultTransport := http.DefaultTransport
defer func() {
http.DefaultTransport = oldDefaultTransport
}()
conf := newTestConf() conf := newTestConf()
DefaultTransport = &mockTransport{ http.DefaultTransport = &mockTransport{
rt: func(req *http.Request) (resp *http.Response, err error) { rt: func(req *http.Request) (resp *http.Response, err error) {
headerContentType := req.Header.Get("Content-Type") headerContentType := req.Header.Get("Content-Type")
if headerContentType != "application/x-www-form-urlencoded" { if headerContentType != "application/x-www-form-urlencoded" {
@ -66,8 +69,13 @@ func TestExchangePayload(t *testing.T) {
} }
func TestExchangingTransport(t *testing.T) { func TestExchangingTransport(t *testing.T) {
oldDefaultTransport := http.DefaultTransport
defer func() {
http.DefaultTransport = oldDefaultTransport
}()
conf := newTestConf() conf := newTestConf()
DefaultTransport = &mockTransport{ http.DefaultTransport = &mockTransport{
rt: func(req *http.Request) (resp *http.Response, err error) { rt: func(req *http.Request) (resp *http.Response, err error) {
if req.URL.RequestURI() != "token-url" { if req.URL.RequestURI() != "token-url" {
t.Fatalf("NewTransportWithCode should have exchanged the code, but it didn't.") t.Fatalf("NewTransportWithCode should have exchanged the code, but it didn't.")
@ -79,8 +87,6 @@ func TestExchangingTransport(t *testing.T) {
} }
func TestFetchWithNoRedirect(t *testing.T) { func TestFetchWithNoRedirect(t *testing.T) {
DefaultTransport = http.DefaultTransport
fetcher := newTestConf() fetcher := newTestConf()
_, err := fetcher.FetchToken(&Token{}) _, err := fetcher.FetchToken(&Token{})
if err == nil { if err == nil {

View File

@ -76,8 +76,9 @@ type Transport interface {
} }
type authorizedTransport struct { type authorizedTransport struct {
fetcher TokenFetcher fetcher TokenFetcher
token *Token token *Token
origTransport http.RoundTripper
// Mutex to protect token during auto refreshments. // Mutex to protect token during auto refreshments.
mu sync.RWMutex mu sync.RWMutex
@ -86,8 +87,8 @@ type authorizedTransport struct {
// NewAuthorizedTransport creates a transport that uses the provided // NewAuthorizedTransport creates a transport that uses the provided
// token fetcher to retrieve new tokens if there is no access token // token fetcher to retrieve new tokens if there is no access token
// provided or it is expired. // provided or it is expired.
func NewAuthorizedTransport(fetcher TokenFetcher, token *Token) Transport { func NewAuthorizedTransport(origTransport http.RoundTripper, fetcher TokenFetcher, token *Token) Transport {
return &authorizedTransport{fetcher: fetcher, token: token} return &authorizedTransport{origTransport: origTransport, fetcher: fetcher, token: token}
} }
// RoundTrip authorizes the request with the existing token. // RoundTrip authorizes the request with the existing token.
@ -118,7 +119,7 @@ func (t *authorizedTransport) RoundTrip(req *http.Request) (resp *http.Response,
req.Header.Set("Authorization", typ+" "+token.AccessToken) req.Header.Set("Authorization", typ+" "+token.AccessToken)
// Make the HTTP request. // Make the HTTP request.
return DefaultTransport.RoundTrip(req) return t.origTransport.RoundTrip(req)
} }
// Token returns the existing token that authorizes the Transport. // Token returns the existing token that authorizes the Transport.

View File

@ -14,7 +14,7 @@ func (f *mockTokenFetcher) FetchToken(existing *Token) (*Token, error) {
} }
func TestInitialTokenRead(t *testing.T) { func TestInitialTokenRead(t *testing.T) {
tr := NewAuthorizedTransport(nil, &Token{AccessToken: "abc"}) tr := NewAuthorizedTransport(http.DefaultTransport, nil, &Token{AccessToken: "abc"})
server := newMockServer(func(w http.ResponseWriter, r *http.Request) { server := newMockServer(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "Bearer abc" { if r.Header.Get("Authorization") != "Bearer abc" {
t.Errorf("Transport doesn't set the Authorization header from the initial token") t.Errorf("Transport doesn't set the Authorization header from the initial token")
@ -31,7 +31,7 @@ func TestTokenFetch(t *testing.T) {
AccessToken: "abc", AccessToken: "abc",
}, },
} }
tr := NewAuthorizedTransport(fetcher, nil) tr := NewAuthorizedTransport(http.DefaultTransport, fetcher, nil)
server := newMockServer(func(w http.ResponseWriter, r *http.Request) { server := newMockServer(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "Bearer abc" { if r.Header.Get("Authorization") != "Bearer abc" {
t.Errorf("Transport doesn't set the Authorization header from the fetched token") t.Errorf("Transport doesn't set the Authorization header from the fetched token")