From 70bd497612d0486a7bdf301647834de4131eac8c Mon Sep 17 00:00:00 2001 From: Burcu Dogan Date: Sun, 20 Jul 2014 16:56:38 -0700 Subject: [PATCH] Fail during conf init if auth or token URL is not valid. --- example_test.go | 5 +---- google/example_test.go | 5 +---- jwt.go | 15 ++++++++------ oauth2.go | 46 +++++++++++++++++++++--------------------- oauth2_test.go | 5 +---- 5 files changed, 35 insertions(+), 41 deletions(-) diff --git a/example_test.go b/example_test.go index 91ddfa6..d69477e 100644 --- a/example_test.go +++ b/example_test.go @@ -28,10 +28,7 @@ func Example_config() { // Redirect user to consent page to ask for permission // for the scopes specified above. - url, err := conf.AuthCodeURL("") - if err != nil { - log.Fatal(err) - } + url := conf.AuthCodeURL("") fmt.Printf("Visit the URL for the auth dialog: %v", url) // Use the exchange code that is handled by the redirect URL. diff --git a/google/example_test.go b/google/example_test.go index cae79fa..2df6d6f 100644 --- a/google/example_test.go +++ b/google/example_test.go @@ -32,10 +32,7 @@ func Example_webServer() { // Redirect user to Google's consent page to ask for permission // for the scopes specified above. - url, err := config.AuthCodeURL("") - if err != nil { - log.Fatal(err) - } + url := config.AuthCodeURL("") fmt.Printf("Visit the URL for the auth dialog: %v", url) // Handle the exchange code to initiate a transport diff --git a/jwt.go b/jwt.go index cd8280c..ea298f0 100644 --- a/jwt.go +++ b/jwt.go @@ -42,19 +42,23 @@ type JWTOptions struct { // NewJWTConfig creates a new configuration with the specified options // and OAuth2 provider endpoint. -func NewJWTConfig(opts *JWTOptions, aud string) (*JWTConfig, error) { +func NewJWTConfig(opts *JWTOptions, aud string) (conf *JWTConfig, err error) { + var audURL *url.URL + if audURL, err = url.Parse(aud); err != nil { + return + } contents, err := ioutil.ReadFile(opts.PemFilename) if err != nil { return nil, err } - return &JWTConfig{opts: opts, aud: aud, signature: contents}, nil + return &JWTConfig{opts: opts, aud: audURL, signature: contents}, nil } // JWTConfig represents an OAuth 2.0 provider and client options to // provide authorized transports with a Bearer JWT token. type JWTConfig struct { opts *JWTOptions - aud string + aud *url.URL signature []byte } @@ -73,7 +77,6 @@ func (c *JWTConfig) NewTransportWithUser(user string) Transport { // fetchToken retrieves a new access token and updates the existing token // with the newly fetched credentials. func (c *JWTConfig) FetchToken(existing *Token) (token *Token, err error) { - if existing == nil { existing = &Token{} } @@ -81,7 +84,7 @@ func (c *JWTConfig) FetchToken(existing *Token) (token *Token, err error) { claimSet := &jws.ClaimSet{ Iss: c.opts.Email, Scope: strings.Join(c.opts.Scopes, " "), - Aud: c.aud, + Aud: c.aud.String(), } if existing.Subject != "" { @@ -100,7 +103,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, v) + resp, err := http.DefaultClient.PostForm(c.aud.String(), v) if err != nil { return nil, err } diff --git a/oauth2.go b/oauth2.go index 09783d7..77d7e27 100644 --- a/oauth2.go +++ b/oauth2.go @@ -78,16 +78,19 @@ type Options struct { // NewConfig creates a generic OAuth 2.0 configuration that talks // to an OAuth 2.0 provider specified with authURL and tokenURL. -func NewConfig(opts *Options, authURL, tokenURL string) (*Config, error) { - conf := &Config{ - opts: opts, - authURL: authURL, - tokenURL: tokenURL, +func NewConfig(opts *Options, authURL, tokenURL string) (conf *Config, err error) { + var aURL, tURL *url.URL + if aURL, err = url.Parse(authURL); err != nil { + return } - if err := conf.validate(); err != nil { + if tURL, err = url.Parse(tokenURL); err != nil { + return + } + conf = &Config{opts: opts, authURL: aURL, tokenURL: tURL} + if err = conf.validate(); err != nil { return nil, err } - return conf, nil + return } // Config represents the configuration of an OAuth 2.0 consumer client. @@ -95,17 +98,22 @@ type Config struct { opts *Options // AuthURL is the URL the user will be directed to // in order to grant access. - authURL string + authURL *url.URL // TokenURL is the URL used to retrieve OAuth tokens. - tokenURL string + tokenURL *url.URL } // AuthCodeURL returns a URL to OAuth 2.0 provider's consent page // that asks for permissions for the required scopes explicitly. -func (c *Config) AuthCodeURL(state string) (authURL string, err error) { - u, err := url.Parse(c.authURL) - if err != nil { - return +func (c *Config) AuthCodeURL(state string) (authURL string) { + u := url.URL{ + Scheme: c.authURL.Scheme, + Opaque: c.authURL.Opaque, + User: c.authURL.User, + Host: c.authURL.Host, + Path: c.authURL.Path, + RawQuery: c.authURL.RawQuery, + Fragment: c.authURL.Fragment, } q := url.Values{ "response_type": {"code"}, @@ -121,7 +129,7 @@ func (c *Config) AuthCodeURL(state string) (authURL string, err error) { } else { u.RawQuery += "&" + q } - return u.String(), nil + return u.String() } // NewTransport creates a new authorizable transport. It doesn't @@ -176,14 +184,6 @@ func (c *Config) validate() error { if c.opts.RedirectURL == "" { return errors.New("A redirect URL should be provided.") } - // TODO(jbd): Validate the URLs. Maybe convert them to URL - // objects on construction. - if c.authURL == "" { - return errors.New("An auth URL should be provided.") - } - if c.tokenURL == "" { - return errors.New("A token URL should be provided.") - } return nil } @@ -206,7 +206,7 @@ func (c *Config) exchange(exchangeCode string) (*Token, error) { func (c *Config) updateToken(tok *Token, v url.Values) error { v.Set("client_id", c.opts.ClientID) v.Set("client_secret", c.opts.ClientSecret) - r, err := http.DefaultClient.PostForm(c.tokenURL, v) + r, err := http.DefaultClient.PostForm(c.tokenURL.String(), v) if err != nil { return err } diff --git a/oauth2_test.go b/oauth2_test.go index b09a813..b502b11 100644 --- a/oauth2_test.go +++ b/oauth2_test.go @@ -36,10 +36,7 @@ func newTestConf() *Config { func TestAuthCodeURL(t *testing.T) { conf := newTestConf() - url, err := conf.AuthCodeURL("foo") - if err != nil { - t.Fatalf("Expected to generate an auth URL, failed with %v.", err) - } + url := conf.AuthCodeURL("foo") if url != "auth-url?access_type=offline&approval_prompt=force&client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=foo" { t.Fatalf("Generated auth URL is not the expected. Found %v.", url) }