Fail during conf init if auth or token URL is not valid.

This commit is contained in:
Burcu Dogan 2014-07-20 16:56:38 -07:00
parent 7935ece62b
commit 70bd497612
5 changed files with 35 additions and 41 deletions

View File

@ -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.

View File

@ -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

15
jwt.go
View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}