diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 741eed6490..7d0a8adac5 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -54,11 +54,6 @@ "github.com/docker/machine/version" ], "Deps": [ - { - "ImportPath": "code.google.com/p/goauth2/oauth", - "Comment": "weekly-56", - "Rev": "afe77d958c701557ec5dc56f6936fcc194d15520" - }, { "ImportPath": "github.com/MSOpenTech/azure-sdk-for-go", "Comment": "v1.1-17-g515f3ec", diff --git a/drivers/digitalocean/digitalocean.go b/drivers/digitalocean/digitalocean.go index 366802d1f5..0b7274b1ca 100644 --- a/drivers/digitalocean/digitalocean.go +++ b/drivers/digitalocean/digitalocean.go @@ -5,13 +5,13 @@ import ( "io/ioutil" "time" - "code.google.com/p/goauth2/oauth" "github.com/digitalocean/godo" "github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/log" "github.com/docker/machine/libmachine/mcnflag" "github.com/docker/machine/libmachine/ssh" "github.com/docker/machine/libmachine/state" + "golang.org/x/oauth2" ) type Driver struct { @@ -293,11 +293,11 @@ func (d *Driver) Kill() error { } func (d *Driver) getClient() *godo.Client { - t := &oauth.Transport{ - Token: &oauth.Token{AccessToken: d.AccessToken}, - } + token := &oauth2.Token{AccessToken: d.AccessToken} + tokenSource := oauth2.StaticTokenSource(token) + client := oauth2.NewClient(oauth2.NoContext, tokenSource) - return godo.NewClient(t.Client()) + return godo.NewClient(client) } func (d *Driver) publicSSHKeyPath() string { diff --git a/vendor/code.google.com/p/goauth2/oauth/example/oauthreq.go b/vendor/code.google.com/p/goauth2/oauth/example/oauthreq.go deleted file mode 100644 index f9651bd090..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/example/oauthreq.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2011 The goauth2 Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This program makes a call to the specified API, authenticated with OAuth2. -// a list of example APIs can be found at https://code.google.com/oauthplayground/ -package main - -import ( - "flag" - "fmt" - "io" - "log" - "os" - - "code.google.com/p/goauth2/oauth" -) - -var ( - clientId = flag.String("id", "", "Client ID") - clientSecret = flag.String("secret", "", "Client Secret") - scope = flag.String("scope", "https://www.googleapis.com/auth/userinfo.profile", "OAuth scope") - redirectURL = flag.String("redirect_url", "oob", "Redirect URL") - authURL = flag.String("auth_url", "https://accounts.google.com/o/oauth2/auth", "Authentication URL") - tokenURL = flag.String("token_url", "https://accounts.google.com/o/oauth2/token", "Token URL") - requestURL = flag.String("request_url", "https://www.googleapis.com/oauth2/v1/userinfo", "API request") - code = flag.String("code", "", "Authorization Code") - cachefile = flag.String("cache", "cache.json", "Token cache file") -) - -const usageMsg = ` -To obtain a request token you must specify both -id and -secret. - -To obtain Client ID and Secret, see the "OAuth 2 Credentials" section under -the "API Access" tab on this page: https://code.google.com/apis/console/ - -Once you have completed the OAuth flow, the credentials should be stored inside -the file specified by -cache and you may run without the -id and -secret flags. -` - -func main() { - flag.Parse() - - // Set up a configuration. - config := &oauth.Config{ - ClientId: *clientId, - ClientSecret: *clientSecret, - RedirectURL: *redirectURL, - Scope: *scope, - AuthURL: *authURL, - TokenURL: *tokenURL, - TokenCache: oauth.CacheFile(*cachefile), - } - - // Set up a Transport using the config. - transport := &oauth.Transport{Config: config} - - // Try to pull the token from the cache; if this fails, we need to get one. - token, err := config.TokenCache.Token() - if err != nil { - if *clientId == "" || *clientSecret == "" { - flag.Usage() - fmt.Fprint(os.Stderr, usageMsg) - os.Exit(2) - } - if *code == "" { - // Get an authorization code from the data provider. - // ("Please ask the user if I can access this resource.") - url := config.AuthCodeURL("") - fmt.Print("Visit this URL to get a code, then run again with -code=YOUR_CODE\n\n") - fmt.Println(url) - return - } - // Exchange the authorization code for an access token. - // ("Here's the code you gave the user, now give me a token!") - token, err = transport.Exchange(*code) - if err != nil { - log.Fatal("Exchange:", err) - } - // (The Exchange method will automatically cache the token.) - fmt.Printf("Token is cached in %v\n", config.TokenCache) - } - - // Make the actual request using the cached token to authenticate. - // ("Here's the token, let me in!") - transport.Token = token - - // Make the request. - r, err := transport.Client().Get(*requestURL) - if err != nil { - log.Fatal("Get:", err) - } - defer r.Body.Close() - - // Write the response to standard output. - io.Copy(os.Stdout, r.Body) - - // Send final carriage return, just to be neat. - fmt.Println() -} diff --git a/vendor/code.google.com/p/goauth2/oauth/jwt/example/example.client_secrets.json b/vendor/code.google.com/p/goauth2/oauth/jwt/example/example.client_secrets.json deleted file mode 100644 index 2ea86f2fc2..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/jwt/example/example.client_secrets.json +++ /dev/null @@ -1 +0,0 @@ -{"web":{"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","client_email":"XXXXXXXXXXXX@developer.gserviceaccount.com","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/XXXXXXXXXXXX@developer.gserviceaccount.com","client_id":"XXXXXXXXXXXX.apps.googleusercontent.com","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"}} diff --git a/vendor/code.google.com/p/goauth2/oauth/jwt/example/example.pem b/vendor/code.google.com/p/goauth2/oauth/jwt/example/example.pem deleted file mode 100644 index 8f78b922d6..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/jwt/example/example.pem +++ /dev/null @@ -1,20 +0,0 @@ -Bag Attributes - friendlyName: privatekey - localKeyID: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -Key Attributes: ------BEGIN PRIVATE KEY----- -XXXXxyXXXXXXXxxyxxxX9y0XXYXXXXYXXxXyxxXxXxXXXyXXXXx4yx1xy1xyYxxY -1XxYy38YxXxxxyXxyyxx+xxxxyx1Y1xYx7yx2/Y1XyyXYYYxY5YXxX0xY/Y642yX -zYYxYXzXYxY0Y8y9YxyYXxxX40YyXxxXX4XXxx7XxXxxXyXxYYXxXyxX5XY0Yy2X -1YX0XXyy6YXyXx9XxXxyXX9XXYXxXxXXXXXXxYXYY3Y8Yy311XYYY81XyY14Xyyx -xXyx7xxXXXxxxxyyyX4YYYXyYyYXyxX4XYXYyxXYyx9xy23xXYyXyxYxXxx1XXXY -y98yX6yYxyyyX4Xyx1Xy/0yxxYxXxYYx2xx7yYXXXxYXXXxyXyyYYxx5XX2xxyxy -y6Yyyx0XX3YYYyx9YYXXXX7y0yxXXy+90XYz1y2xyx7yXxX+8X0xYxXXYxxyxYYy -YXx8Yy4yX0Xyxxx6yYX92yxy1YYYzyyyyxy55x/yyXXXYYXYXXzXXxYYxyXY8XXX -+y9+yXxX7XxxyYYxxXYxyY623xxXxYX59x5Y6yYyXYY4YxXXYXXXYxXYxXxXXx6x -YXX7XxXX2X0XY7YXyYy1XXxYXxXxYY1xXXxxxyy+07zXYxYxxXyyxxyxXx1XYy5X -5XYzyxYxXXYyX9XX7xX8xXxx+XXYyYXXXX5YY1x8Yxyx54Xy/1XXyyYXY5YxYyxY -XyyxXyX/YxxXXXxXXYXxyxx63xX/xxyYXXyYzx0XY+YxX5xyYyyxxxXXYX/94XXy -Xx63xYxXyXY3/XXxyyXX15XXXyz08XYY5YYXY/YXy/96x68XyyXXxYyXy4xYXx5x -7yxxyxxYxXxyx3y= ------END PRIVATE KEY----- diff --git a/vendor/code.google.com/p/goauth2/oauth/jwt/example/main.go b/vendor/code.google.com/p/goauth2/oauth/jwt/example/main.go deleted file mode 100644 index 2256e9c621..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/jwt/example/main.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2011 The goauth2 Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This program makes a read only call to the Google Cloud Storage API, -// authenticated with OAuth2. A list of example APIs can be found at -// https://code.google.com/oauthplayground/ -package main - -import ( - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "log" - "net/http" - "strings" - - "code.google.com/p/goauth2/oauth/jwt" -) - -const scope = "https://www.googleapis.com/auth/devstorage.read_only" - -var ( - secretsFile = flag.String("s", "", "JSON encoded secrets for the service account") - pemFile = flag.String("k", "", "private pem key file for the service account") -) - -const usageMsg = ` -You must specify -k and -s. - -To obtain client secrets and pem, see the "OAuth 2 Credentials" section under -the "API Access" tab on this page: https://code.google.com/apis/console/ - -Google Cloud Storage must also be turned on in the API console. -` - -func main() { - flag.Parse() - - if *secretsFile == "" || *pemFile == "" { - flag.Usage() - fmt.Println(usageMsg) - return - } - - // Read the secret file bytes into the config. - secretBytes, err := ioutil.ReadFile(*secretsFile) - if err != nil { - log.Fatal("error reading secerets file:", err) - } - var config struct { - Web struct { - ClientEmail string `json:"client_email"` - ClientID string `json:"client_id"` - TokenURI string `json:"token_uri"` - } - } - err = json.Unmarshal(secretBytes, &config) - if err != nil { - log.Fatal("error unmarshalling secerets:", err) - } - - // Get the project ID from the client ID. - projectID := strings.SplitN(config.Web.ClientID, "-", 2)[0] - - // Read the pem file bytes for the private key. - keyBytes, err := ioutil.ReadFile(*pemFile) - if err != nil { - log.Fatal("error reading private key file:", err) - } - - // Craft the ClaimSet and JWT token. - t := jwt.NewToken(config.Web.ClientEmail, scope, keyBytes) - t.ClaimSet.Aud = config.Web.TokenURI - - // We need to provide a client. - c := &http.Client{} - - // Get the access token. - o, err := t.Assert(c) - if err != nil { - log.Fatal("assertion error:", err) - } - - // Refresh token will be missing, but this access_token will be good - // for one hour. - fmt.Printf("access_token = %v\n", o.AccessToken) - fmt.Printf("refresh_token = %v\n", o.RefreshToken) - fmt.Printf("expires %v\n", o.Expiry) - - // Form the request to list Google Cloud Storage buckets. - req, err := http.NewRequest("GET", "https://storage.googleapis.com/", nil) - if err != nil { - log.Fatal("http.NewRequest:", err) - } - req.Header.Set("Authorization", "OAuth "+o.AccessToken) - req.Header.Set("x-goog-api-version", "2") - req.Header.Set("x-goog-project-id", projectID) - - // Make the request. - r, err := c.Do(req) - if err != nil { - log.Fatal("API request error:", err) - } - defer r.Body.Close() - - // Write the response to standard output. - res, err := ioutil.ReadAll(r.Body) - if err != nil { - log.Fatal("error reading API request results:", err) - } - fmt.Printf("\nRESULT:\n%s\n", res) -} diff --git a/vendor/code.google.com/p/goauth2/oauth/jwt/jwt.go b/vendor/code.google.com/p/goauth2/oauth/jwt/jwt.go deleted file mode 100644 index 61bf5ce936..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/jwt/jwt.go +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright 2012 The goauth2 Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The jwt package provides support for creating credentials for OAuth2 service -// account requests. -// -// For examples of the package usage please see jwt_test.go. -// Example usage (error handling omitted for brevity): -// -// // Craft the ClaimSet and JWT token. -// iss := "XXXXXXXXXXXX@developer.gserviceaccount.com" -// scope := "https://www.googleapis.com/auth/devstorage.read_only" -// t := jwt.NewToken(iss, scope, pemKeyBytes) -// -// // We need to provide a client. -// c := &http.Client{} -// -// // Get the access token. -// o, _ := t.Assert(c) -// -// // Form the request to the service. -// req, _ := http.NewRequest("GET", "https://storage.googleapis.com/", nil) -// req.Header.Set("Authorization", "OAuth "+o.AccessToken) -// req.Header.Set("x-goog-api-version", "2") -// req.Header.Set("x-goog-project-id", "XXXXXXXXXXXX") -// -// // Make the request. -// result, _ := c.Do(req) -// -// For info on OAuth2 service accounts please see the online documentation. -// https://developers.google.com/accounts/docs/OAuth2ServiceAccount -// -package jwt - -import ( - "bytes" - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "encoding/base64" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "net/http" - "net/url" - "strings" - "time" - - "code.google.com/p/goauth2/oauth" -) - -// These are the default/standard values for this to work for Google service accounts. -const ( - stdAlgorithm = "RS256" - stdType = "JWT" - stdAssertionType = "http://oauth.net/grant_type/jwt/1.0/bearer" - stdGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer" - stdAud = "https://accounts.google.com/o/oauth2/token" -) - -var ( - ErrInvalidKey = errors.New("Invalid Key") -) - -// base64Encode returns and Base64url encoded version of the input string with any -// trailing "=" stripped. -func base64Encode(b []byte) string { - return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") -} - -// base64Decode decodes the Base64url encoded string -func base64Decode(s string) ([]byte, error) { - // add back missing padding - switch len(s) % 4 { - case 2: - s += "==" - case 3: - s += "=" - } - return base64.URLEncoding.DecodeString(s) -} - -// The JWT claim set contains information about the JWT including the -// permissions being requested (scopes), the target of the token, the issuer, -// the time the token was issued, and the lifetime of the token. -// -// Aud is usually https://accounts.google.com/o/oauth2/token -type ClaimSet struct { - Iss string `json:"iss"` // email address of the client_id of the application making the access token request - Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests - Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional). - Prn string `json:"prn,omitempty"` // email for which the application is requesting delegated access (Optional). - Exp int64 `json:"exp"` - Iat int64 `json:"iat"` - Typ string `json:"typ,omitempty"` - Sub string `json:"sub,omitempty"` // Add support for googleapi delegation support - - // See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3 - // This array is marshalled using custom code (see (c *ClaimSet) encode()). - PrivateClaims map[string]interface{} `json:"-"` - - exp time.Time - iat time.Time -} - -// setTimes sets iat and exp to time.Now() and iat.Add(time.Hour) respectively. -// -// Note that these times have nothing to do with the expiration time for the -// access_token returned by the server. These have to do with the lifetime of -// the encoded JWT. -// -// A JWT can be re-used for up to one hour after it was encoded. The access -// token that is granted will also be good for one hour so there is little point -// in trying to use the JWT a second time. -func (c *ClaimSet) setTimes(t time.Time) { - c.iat = t - c.exp = c.iat.Add(time.Hour) -} - -var ( - jsonStart = []byte{'{'} - jsonEnd = []byte{'}'} -) - -// encode returns the Base64url encoded form of the Signature. -func (c *ClaimSet) encode() string { - if c.exp.IsZero() || c.iat.IsZero() { - c.setTimes(time.Now()) - } - if c.Aud == "" { - c.Aud = stdAud - } - c.Exp = c.exp.Unix() - c.Iat = c.iat.Unix() - - b, err := json.Marshal(c) - if err != nil { - panic(err) - } - - if len(c.PrivateClaims) == 0 { - return base64Encode(b) - } - - // Marshal private claim set and then append it to b. - prv, err := json.Marshal(c.PrivateClaims) - if err != nil { - panic(fmt.Errorf("Invalid map of private claims %v", c.PrivateClaims)) - } - - // Concatenate public and private claim JSON objects. - if !bytes.HasSuffix(b, jsonEnd) { - panic(fmt.Errorf("Invalid JSON %s", b)) - } - if !bytes.HasPrefix(prv, jsonStart) { - panic(fmt.Errorf("Invalid JSON %s", prv)) - } - b[len(b)-1] = ',' // Replace closing curly brace with a comma. - b = append(b, prv[1:]...) // Append private claims. - - return base64Encode(b) -} - -// Header describes the algorithm and type of token being generated, -// and optionally a KeyID describing additional parameters for the -// signature. -type Header struct { - Algorithm string `json:"alg"` - Type string `json:"typ"` - KeyId string `json:"kid,omitempty"` -} - -func (h *Header) encode() string { - b, err := json.Marshal(h) - if err != nil { - panic(err) - } - return base64Encode(b) -} - -// A JWT is composed of three parts: a header, a claim set, and a signature. -// The well formed and encoded JWT can then be exchanged for an access token. -// -// The Token is not a JWT, but is is encoded to produce a well formed JWT. -// -// When obtaining a key from the Google API console it will be downloaded in a -// PKCS12 encoding. To use this key you will need to convert it to a PEM file. -// This can be achieved with openssl. -// -// $ openssl pkcs12 -in -nocerts -passin pass:notasecret -nodes -out -// -// The contents of this file can then be used as the Key. -type Token struct { - ClaimSet *ClaimSet // claim set used to construct the JWT - Header *Header // header used to construct the JWT - Key []byte // PEM printable encoding of the private key - pKey *rsa.PrivateKey - - header string - claim string - sig string - - useExternalSigner bool - signer Signer -} - -// NewToken returns a filled in *Token based on the standard header, -// and sets the Iat and Exp times based on when the call to Assert is -// made. -func NewToken(iss, scope string, key []byte) *Token { - c := &ClaimSet{ - Iss: iss, - Scope: scope, - Aud: stdAud, - } - h := &Header{ - Algorithm: stdAlgorithm, - Type: stdType, - } - t := &Token{ - ClaimSet: c, - Header: h, - Key: key, - } - return t -} - -// Signer is an interface that given a JWT token, returns the header & -// claim (serialized and urlEncoded to a byte slice), along with the -// signature and an error (if any occured). It could modify any data -// to sign (typically the KeyID). -// -// Example usage where a SHA256 hash of the original url-encoded token -// with an added KeyID and secret data is used as a signature: -// -// var privateData = "secret data added to hash, indexed by KeyID" -// -// type SigningService struct{} -// -// func (ss *SigningService) Sign(in *jwt.Token) (newTokenData, sig []byte, err error) { -// in.Header.KeyID = "signing service" -// newTokenData = in.EncodeWithoutSignature() -// dataToSign := fmt.Sprintf("%s.%s", newTokenData, privateData) -// h := sha256.New() -// _, err := h.Write([]byte(dataToSign)) -// sig = h.Sum(nil) -// return -// } -type Signer interface { - Sign(in *Token) (tokenData, signature []byte, err error) -} - -// NewSignerToken returns a *Token, using an external signer function -func NewSignerToken(iss, scope string, signer Signer) *Token { - t := NewToken(iss, scope, nil) - t.useExternalSigner = true - t.signer = signer - return t -} - -// Expired returns a boolean value letting us know if the token has expired. -func (t *Token) Expired() bool { - return t.ClaimSet.exp.Before(time.Now()) -} - -// Encode constructs and signs a Token returning a JWT ready to use for -// requesting an access token. -func (t *Token) Encode() (string, error) { - var tok string - t.header = t.Header.encode() - t.claim = t.ClaimSet.encode() - err := t.sign() - if err != nil { - return tok, err - } - tok = fmt.Sprintf("%s.%s.%s", t.header, t.claim, t.sig) - return tok, nil -} - -// EncodeWithoutSignature returns the url-encoded value of the Token -// before signing has occured (typically for use by external signers). -func (t *Token) EncodeWithoutSignature() string { - t.header = t.Header.encode() - t.claim = t.ClaimSet.encode() - return fmt.Sprintf("%s.%s", t.header, t.claim) -} - -// sign computes the signature for a Token. The details for this can be found -// in the OAuth2 Service Account documentation. -// https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature -func (t *Token) sign() error { - if t.useExternalSigner { - fulldata, sig, err := t.signer.Sign(t) - if err != nil { - return err - } - split := strings.Split(string(fulldata), ".") - if len(split) != 2 { - return errors.New("no token returned") - } - t.header = split[0] - t.claim = split[1] - t.sig = base64Encode(sig) - return err - } - ss := fmt.Sprintf("%s.%s", t.header, t.claim) - if t.pKey == nil { - err := t.parsePrivateKey() - if err != nil { - return err - } - } - h := sha256.New() - h.Write([]byte(ss)) - b, err := rsa.SignPKCS1v15(rand.Reader, t.pKey, crypto.SHA256, h.Sum(nil)) - t.sig = base64Encode(b) - return err -} - -// parsePrivateKey converts the Token's Key ([]byte) into a parsed -// rsa.PrivateKey. If the key is not well formed this method will return an -// ErrInvalidKey error. -func (t *Token) parsePrivateKey() error { - block, _ := pem.Decode(t.Key) - if block == nil { - return ErrInvalidKey - } - parsedKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) - if err != nil { - parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return err - } - } - var ok bool - t.pKey, ok = parsedKey.(*rsa.PrivateKey) - if !ok { - return ErrInvalidKey - } - return nil -} - -// Assert obtains an *oauth.Token from the remote server by encoding and sending -// a JWT. The access_token will expire in one hour (3600 seconds) and cannot be -// refreshed (no refresh_token is returned with the response). Once this token -// expires call this method again to get a fresh one. -func (t *Token) Assert(c *http.Client) (*oauth.Token, error) { - var o *oauth.Token - t.ClaimSet.setTimes(time.Now()) - u, v, err := t.buildRequest() - if err != nil { - return o, err - } - resp, err := c.PostForm(u, v) - if err != nil { - return o, err - } - o, err = handleResponse(resp) - return o, err -} - -// buildRequest sets up the URL values and the proper URL string for making our -// access_token request. -func (t *Token) buildRequest() (string, url.Values, error) { - v := url.Values{} - j, err := t.Encode() - if err != nil { - return t.ClaimSet.Aud, v, err - } - v.Set("grant_type", stdGrantType) - v.Set("assertion", j) - return t.ClaimSet.Aud, v, nil -} - -// Used for decoding the response body. -type respBody struct { - IdToken string `json:"id_token"` - Access string `json:"access_token"` - Type string `json:"token_type"` - ExpiresIn time.Duration `json:"expires_in"` -} - -// handleResponse returns a filled in *oauth.Token given the *http.Response from -// a *http.Request created by buildRequest. -func handleResponse(r *http.Response) (*oauth.Token, error) { - o := &oauth.Token{} - defer r.Body.Close() - if r.StatusCode != 200 { - return o, errors.New("invalid response: " + r.Status) - } - b := &respBody{} - err := json.NewDecoder(r.Body).Decode(b) - if err != nil { - return o, err - } - o.AccessToken = b.Access - if b.IdToken != "" { - // decode returned id token to get expiry - o.AccessToken = b.IdToken - s := strings.Split(b.IdToken, ".") - if len(s) < 2 { - return nil, errors.New("invalid token received") - } - d, err := base64Decode(s[1]) - if err != nil { - return o, err - } - c := &ClaimSet{} - err = json.NewDecoder(bytes.NewBuffer(d)).Decode(c) - if err != nil { - return o, err - } - o.Expiry = time.Unix(c.Exp, 0) - return o, nil - } - o.Expiry = time.Now().Add(b.ExpiresIn * time.Second) - return o, nil -} - -// Transport implements http.RoundTripper. When configured with a valid -// JWT and OAuth tokens it can be used to make authenticated HTTP requests. -// -// t := &jwt.Transport{jwtToken, oauthToken} -// r, _, err := t.Client().Get("http://example.org/url/requiring/auth") -// -// It will automatically refresh the OAuth token if it can, updating in place. -type Transport struct { - JWTToken *Token - OAuthToken *oauth.Token - - // Transport is the HTTP transport to use when making requests. - // It will default to http.DefaultTransport if nil. - Transport http.RoundTripper -} - -// Creates a new authenticated transport. -func NewTransport(token *Token) (*Transport, error) { - oa, err := token.Assert(new(http.Client)) - if err != nil { - return nil, err - } - return &Transport{ - JWTToken: token, - OAuthToken: oa, - }, nil -} - -// Client returns an *http.Client that makes OAuth-authenticated requests. -func (t *Transport) Client() *http.Client { - return &http.Client{Transport: t} -} - -// Fetches the internal transport. -func (t *Transport) transport() http.RoundTripper { - if t.Transport != nil { - return t.Transport - } - return http.DefaultTransport -} - -// RoundTrip executes a single HTTP transaction using the Transport's -// OAuthToken as authorization headers. -// -// This method will attempt to renew the token if it has expired and may return -// an error related to that token renewal before attempting the client request. -// If the token cannot be renewed a non-nil os.Error value will be returned. -// If the token is invalid callers should expect HTTP-level errors, -// as indicated by the Response's StatusCode. -func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { - // Sanity check the two tokens - if t.JWTToken == nil { - return nil, fmt.Errorf("no JWT token supplied") - } - if t.OAuthToken == nil { - return nil, fmt.Errorf("no OAuth token supplied") - } - // Refresh the OAuth token if it has expired - if t.OAuthToken.Expired() { - if oa, err := t.JWTToken.Assert(new(http.Client)); err != nil { - return nil, err - } else { - t.OAuthToken = oa - } - } - // To set the Authorization header, we must make a copy of the Request - // so that we don't modify the Request we were given. - // This is required by the specification of http.RoundTripper. - req = cloneRequest(req) - req.Header.Set("Authorization", "Bearer "+t.OAuthToken.AccessToken) - - // Make the HTTP request. - return t.transport().RoundTrip(req) -} - -// cloneRequest returns a clone of the provided *http.Request. -// The clone is a shallow copy of the struct and its Header map. -func cloneRequest(r *http.Request) *http.Request { - // shallow copy of the struct - r2 := new(http.Request) - *r2 = *r - // deep copy of the Header - r2.Header = make(http.Header) - for k, s := range r.Header { - r2.Header[k] = s - } - return r2 -} diff --git a/vendor/code.google.com/p/goauth2/oauth/jwt/jwt_test.go b/vendor/code.google.com/p/goauth2/oauth/jwt/jwt_test.go deleted file mode 100644 index 622843e168..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/jwt/jwt_test.go +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright 2012 The goauth2 Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// For package documentation please see jwt.go. -// -package jwt - -import ( - "bytes" - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "encoding/json" - "encoding/pem" - "io/ioutil" - "net/http" - "testing" - "time" -) - -const ( - stdHeaderStr = `{"alg":"RS256","typ":"JWT"}` - iss = "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com" - scope = "https://www.googleapis.com/auth/prediction" - exp = 1328554385 - iat = 1328550785 // exp + 1 hour -) - -// Base64url encoded Header -const headerEnc = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9" - -// Base64url encoded ClaimSet -const claimSetEnc = "eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ" - -// Base64url encoded Signature -const sigEnc = "olukbHreNiYrgiGCTEmY3eWGeTvYDSUHYoE84Jz3BRPBSaMdZMNOn_0CYK7UHPO7OdvUofjwft1dH59UxE9GWS02pjFti1uAQoImaqjLZoTXr8qiF6O_kDa9JNoykklWlRAIwGIZkDupCS-8cTAnM_ksSymiH1coKJrLDUX_BM0x2f4iMFQzhL5vT1ll-ZipJ0lNlxb5QsyXxDYcxtHYguF12-vpv3ItgT0STfcXoWzIGQoEbhwB9SBp9JYcQ8Ygz6pYDjm0rWX9LrchmTyDArCodpKLFtutNgcIFUP9fWxvwd1C2dNw5GjLcKr9a_SAERyoJ2WnCR1_j9N0wD2o0g" - -// Base64url encoded Token -const tokEnc = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.olukbHreNiYrgiGCTEmY3eWGeTvYDSUHYoE84Jz3BRPBSaMdZMNOn_0CYK7UHPO7OdvUofjwft1dH59UxE9GWS02pjFti1uAQoImaqjLZoTXr8qiF6O_kDa9JNoykklWlRAIwGIZkDupCS-8cTAnM_ksSymiH1coKJrLDUX_BM0x2f4iMFQzhL5vT1ll-ZipJ0lNlxb5QsyXxDYcxtHYguF12-vpv3ItgT0STfcXoWzIGQoEbhwB9SBp9JYcQ8Ygz6pYDjm0rWX9LrchmTyDArCodpKLFtutNgcIFUP9fWxvwd1C2dNw5GjLcKr9a_SAERyoJ2WnCR1_j9N0wD2o0g" - -// Private key for testing -const privateKeyPem = `-----BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA4ej0p7bQ7L/r4rVGUz9RN4VQWoej1Bg1mYWIDYslvKrk1gpj -7wZgkdmM7oVK2OfgrSj/FCTkInKPqaCR0gD7K80q+mLBrN3PUkDrJQZpvRZIff3/ -xmVU1WeruQLFJjnFb2dqu0s/FY/2kWiJtBCakXvXEOb7zfbINuayL+MSsCGSdVYs -SliS5qQpgyDap+8b5fpXZVJkq92hrcNtbkg7hCYUJczt8n9hcCTJCfUpApvaFQ18 -pe+zpyl4+WzkP66I28hniMQyUlA1hBiskT7qiouq0m8IOodhv2fagSZKjOTTU2xk -SBc//fy3ZpsL7WqgsZS7Q+0VRK8gKfqkxg5OYQIDAQABAoIBAQDGGHzQxGKX+ANk -nQi53v/c6632dJKYXVJC+PDAz4+bzU800Y+n/bOYsWf/kCp94XcG4Lgsdd0Gx+Zq -HD9CI1IcqqBRR2AFscsmmX6YzPLTuEKBGMW8twaYy3utlFxElMwoUEsrSWRcCA1y -nHSDzTt871c7nxCXHxuZ6Nm/XCL7Bg8uidRTSC1sQrQyKgTPhtQdYrPQ4WZ1A4J9 -IisyDYmZodSNZe5P+LTJ6M1SCgH8KH9ZGIxv3diMwzNNpk3kxJc9yCnja4mjiGE2 -YCNusSycU5IhZwVeCTlhQGcNeV/skfg64xkiJE34c2y2ttFbdwBTPixStGaF09nU -Z422D40BAoGBAPvVyRRsC3BF+qZdaSMFwI1yiXY7vQw5+JZh01tD28NuYdRFzjcJ -vzT2n8LFpj5ZfZFvSMLMVEFVMgQvWnN0O6xdXvGov6qlRUSGaH9u+TCPNnIldjMP -B8+xTwFMqI7uQr54wBB+Poq7dVRP+0oHb0NYAwUBXoEuvYo3c/nDoRcZAoGBAOWl -aLHjMv4CJbArzT8sPfic/8waSiLV9Ixs3Re5YREUTtnLq7LoymqB57UXJB3BNz/2 -eCueuW71avlWlRtE/wXASj5jx6y5mIrlV4nZbVuyYff0QlcG+fgb6pcJQuO9DxMI -aqFGrWP3zye+LK87a6iR76dS9vRU+bHZpSVvGMKJAoGAFGt3TIKeQtJJyqeUWNSk -klORNdcOMymYMIlqG+JatXQD1rR6ThgqOt8sgRyJqFCVT++YFMOAqXOBBLnaObZZ -CFbh1fJ66BlSjoXff0W+SuOx5HuJJAa5+WtFHrPajwxeuRcNa8jwxUsB7n41wADu -UqWWSRedVBg4Ijbw3nWwYDECgYB0pLew4z4bVuvdt+HgnJA9n0EuYowVdadpTEJg -soBjNHV4msLzdNqbjrAqgz6M/n8Ztg8D2PNHMNDNJPVHjJwcR7duSTA6w2p/4k28 -bvvk/45Ta3XmzlxZcZSOct3O31Cw0i2XDVc018IY5be8qendDYM08icNo7vQYkRH -504kQQKBgQDjx60zpz8ozvm1XAj0wVhi7GwXe+5lTxiLi9Fxq721WDxPMiHDW2XL -YXfFVy/9/GIMvEiGYdmarK1NW+VhWl1DC5xhDg0kvMfxplt4tynoq1uTsQTY31Mx -BeF5CT/JuNYk3bEBF0H/Q3VGO1/ggVS+YezdFbLWIRoMnLj6XCFEGg== ------END RSA PRIVATE KEY-----` - -// Public key to go with the private key for testing -const publicKeyPem = `-----BEGIN CERTIFICATE----- -MIIDIzCCAgugAwIBAgIJAMfISuBQ5m+5MA0GCSqGSIb3DQEBBQUAMBUxEzARBgNV -BAMTCnVuaXQtdGVzdHMwHhcNMTExMjA2MTYyNjAyWhcNMjExMjAzMTYyNjAyWjAV -MRMwEQYDVQQDEwp1bml0LXRlc3RzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA4ej0p7bQ7L/r4rVGUz9RN4VQWoej1Bg1mYWIDYslvKrk1gpj7wZgkdmM -7oVK2OfgrSj/FCTkInKPqaCR0gD7K80q+mLBrN3PUkDrJQZpvRZIff3/xmVU1Wer -uQLFJjnFb2dqu0s/FY/2kWiJtBCakXvXEOb7zfbINuayL+MSsCGSdVYsSliS5qQp -gyDap+8b5fpXZVJkq92hrcNtbkg7hCYUJczt8n9hcCTJCfUpApvaFQ18pe+zpyl4 -+WzkP66I28hniMQyUlA1hBiskT7qiouq0m8IOodhv2fagSZKjOTTU2xkSBc//fy3 -ZpsL7WqgsZS7Q+0VRK8gKfqkxg5OYQIDAQABo3YwdDAdBgNVHQ4EFgQU2RQ8yO+O -gN8oVW2SW7RLrfYd9jEwRQYDVR0jBD4wPIAU2RQ8yO+OgN8oVW2SW7RLrfYd9jGh -GaQXMBUxEzARBgNVBAMTCnVuaXQtdGVzdHOCCQDHyErgUOZvuTAMBgNVHRMEBTAD -AQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBRv+M/6+FiVu7KXNjFI5pSN17OcW5QUtPr -odJMlWrJBtynn/TA1oJlYu3yV5clc/71Vr/AxuX5xGP+IXL32YDF9lTUJXG/uUGk -+JETpKmQviPbRsvzYhz4pf6ZIOZMc3/GIcNq92ECbseGO+yAgyWUVKMmZM0HqXC9 -ovNslqe0M8C1sLm1zAR5z/h/litE7/8O2ietija3Q/qtl2TOXJdCA6sgjJX2WUql -ybrC55ct18NKf3qhpcEkGQvFU40rVYApJpi98DiZPYFdx1oBDp/f4uZ3ojpxRVFT -cDwcJLfNRCPUhormsY7fDS9xSyThiHsW9mjJYdcaKQkwYZ0F11yB ------END CERTIFICATE-----` - -var ( - privateKeyPemBytes = []byte(privateKeyPem) - publicKeyPemBytes = []byte(publicKeyPem) - stdHeader = &Header{Algorithm: stdAlgorithm, Type: stdType} -) - -// Testing the urlEncode function. -func TestUrlEncode(t *testing.T) { - enc := base64Encode([]byte(stdHeaderStr)) - b := []byte(enc) - if b[len(b)-1] == 61 { - t.Error("TestUrlEncode: last chat == \"=\"") - } - if enc != headerEnc { - t.Error("TestUrlEncode: enc != headerEnc") - t.Errorf(" enc = %s", enc) - t.Errorf(" headerEnc = %s", headerEnc) - } -} - -// Test that the times are set properly. -func TestClaimSetSetTimes(t *testing.T) { - c := &ClaimSet{ - Iss: iss, - Scope: scope, - } - iat := time.Unix(iat, 0) - c.setTimes(iat) - if c.exp.Unix() != exp { - t.Error("TestClaimSetSetTimes: c.exp != exp") - t.Errorf(" c.Exp = %d", c.exp.Unix()) - t.Errorf(" exp = %d", exp) - } -} - -// Given a well formed ClaimSet, test for proper encoding. -func TestClaimSetEncode(t *testing.T) { - c := &ClaimSet{ - Iss: iss, - Scope: scope, - exp: time.Unix(exp, 0), - iat: time.Unix(iat, 0), - } - enc := c.encode() - re, err := base64Decode(enc) - if err != nil { - t.Fatalf("error decoding encoded claim set: %v", err) - } - - wa, err := base64Decode(claimSetEnc) - if err != nil { - t.Fatalf("error decoding encoded expected claim set: %v", err) - } - - if enc != claimSetEnc { - t.Error("TestClaimSetEncode: enc != claimSetEnc") - t.Errorf(" enc = %s", string(re)) - t.Errorf(" claimSetEnc = %s", string(wa)) - } -} - -// Test that claim sets with private claim names are encoded correctly. -func TestClaimSetWithPrivateNameEncode(t *testing.T) { - iatT := time.Unix(iat, 0) - expT := time.Unix(exp, 0) - - i, err := json.Marshal(iatT.Unix()) - if err != nil { - t.Fatalf("error marshaling iatT value of %v: %v", iatT.Unix(), err) - } - iatStr := string(i) - e, err := json.Marshal(expT.Unix()) - if err != nil { - t.Fatalf("error marshaling expT value of %v: %v", expT.Unix(), err) - } - - expStr := string(e) - - testCases := []struct { - desc string - input map[string]interface{} - want string - }{ - // Test a simple int field. - { - "single simple field", - map[string]interface{}{"amount": 22}, - `{` + - `"iss":"` + iss + `",` + - `"scope":"` + scope + `",` + - `"aud":"` + stdAud + `",` + - `"exp":` + expStr + `,` + - `"iat":` + iatStr + `,` + - `"amount":22` + - `}`, - }, - { - "multiple simple fields", - map[string]interface{}{"tracking_code": "axZf", "amount": 22}, - `{` + - `"iss":"` + iss + `",` + - `"scope":"` + scope + `",` + - `"aud":"` + stdAud + `",` + - `"exp":` + expStr + `,` + - `"iat":` + iatStr + `,` + - `"amount":22,` + - `"tracking_code":"axZf"` + - `}`, - }, - { - "nested struct fields", - map[string]interface{}{ - "tracking_code": "axZf", - "purchase": struct { - Description string `json:"desc"` - Quantity int32 `json:"q"` - Time int64 `json:"t"` - }{ - "toaster", - 5, - iat, - }, - }, - `{` + - `"iss":"` + iss + `",` + - `"scope":"` + scope + `",` + - `"aud":"` + stdAud + `",` + - `"exp":` + expStr + `,` + - `"iat":` + iatStr + `,` + - `"purchase":{"desc":"toaster","q":5,"t":` + iatStr + `},` + - `"tracking_code":"axZf"` + - `}`, - }, - } - - for _, testCase := range testCases { - c := &ClaimSet{ - Iss: iss, - Scope: scope, - Aud: stdAud, - iat: iatT, - exp: expT, - PrivateClaims: testCase.input, - } - cJSON, err := base64Decode(c.encode()) - if err != nil { - t.Fatalf("error decoding claim set: %v", err) - } - if string(cJSON) != testCase.want { - t.Errorf("TestClaimSetWithPrivateNameEncode: enc != want in case %s", testCase.desc) - t.Errorf(" enc = %s", cJSON) - t.Errorf(" want = %s", testCase.want) - } - } -} - -// Test the NewToken constructor. -func TestNewToken(t *testing.T) { - tok := NewToken(iss, scope, privateKeyPemBytes) - if tok.ClaimSet.Iss != iss { - t.Error("TestNewToken: tok.ClaimSet.Iss != iss") - t.Errorf(" tok.ClaimSet.Iss = %s", tok.ClaimSet.Iss) - t.Errorf(" iss = %s", iss) - } - if tok.ClaimSet.Scope != scope { - t.Error("TestNewToken: tok.ClaimSet.Scope != scope") - t.Errorf(" tok.ClaimSet.Scope = %s", tok.ClaimSet.Scope) - t.Errorf(" scope = %s", scope) - } - if tok.ClaimSet.Aud != stdAud { - t.Error("TestNewToken: tok.ClaimSet.Aud != stdAud") - t.Errorf(" tok.ClaimSet.Aud = %s", tok.ClaimSet.Aud) - t.Errorf(" stdAud = %s", stdAud) - } - if !bytes.Equal(tok.Key, privateKeyPemBytes) { - t.Error("TestNewToken: tok.Key != privateKeyPemBytes") - t.Errorf(" tok.Key = %s", tok.Key) - t.Errorf(" privateKeyPemBytes = %s", privateKeyPemBytes) - } -} - -// Make sure the private key parsing functions work. -func TestParsePrivateKey(t *testing.T) { - tok := &Token{ - Key: privateKeyPemBytes, - } - err := tok.parsePrivateKey() - if err != nil { - t.Errorf("TestParsePrivateKey:tok.parsePrivateKey: %v", err) - } -} - -// Test that the token signature generated matches the golden standard. -func TestTokenSign(t *testing.T) { - tok := &Token{ - Key: privateKeyPemBytes, - claim: claimSetEnc, - header: headerEnc, - } - err := tok.parsePrivateKey() - if err != nil { - t.Errorf("TestTokenSign:tok.parsePrivateKey: %v", err) - } - err = tok.sign() - if err != nil { - t.Errorf("TestTokenSign:tok.sign: %v", err) - } - if tok.sig != sigEnc { - t.Error("TestTokenSign: tok.sig != sigEnc") - t.Errorf(" tok.sig = %s", tok.sig) - t.Errorf(" sigEnc = %s", sigEnc) - } -} - -// Test that the token expiration function is working. -func TestTokenExpired(t *testing.T) { - c := &ClaimSet{} - tok := &Token{ - ClaimSet: c, - } - now := time.Now() - c.setTimes(now) - if tok.Expired() != false { - t.Error("TestTokenExpired: tok.Expired != false") - } - // Set the times as if they were set 2 hours ago. - c.setTimes(now.Add(-2 * time.Hour)) - if tok.Expired() != true { - t.Error("TestTokenExpired: tok.Expired != true") - } -} - -// Given a well formed Token, test for proper encoding. -func TestTokenEncode(t *testing.T) { - c := &ClaimSet{ - Iss: iss, - Scope: scope, - exp: time.Unix(exp, 0), - iat: time.Unix(iat, 0), - } - tok := &Token{ - ClaimSet: c, - Header: stdHeader, - Key: privateKeyPemBytes, - } - enc, err := tok.Encode() - if err != nil { - t.Errorf("TestTokenEncode:tok.Assertion: %v", err) - } - if enc != tokEnc { - t.Error("TestTokenEncode: enc != tokEnc") - t.Errorf(" enc = %s", enc) - t.Errorf(" tokEnc = %s", tokEnc) - } -} - -// Given a well formed Token we should get back a well formed request. -func TestBuildRequest(t *testing.T) { - c := &ClaimSet{ - Iss: iss, - Scope: scope, - exp: time.Unix(exp, 0), - iat: time.Unix(iat, 0), - } - tok := &Token{ - ClaimSet: c, - Header: stdHeader, - Key: privateKeyPemBytes, - } - u, v, err := tok.buildRequest() - if err != nil { - t.Errorf("TestBuildRequest:BuildRequest: %v", err) - } - if u != c.Aud { - t.Error("TestBuildRequest: u != c.Aud") - t.Errorf(" u = %s", u) - t.Errorf(" c.Aud = %s", c.Aud) - } - if v.Get("grant_type") != stdGrantType { - t.Error("TestBuildRequest: grant_type != stdGrantType") - t.Errorf(" grant_type = %s", v.Get("grant_type")) - t.Errorf(" stdGrantType = %s", stdGrantType) - } - if v.Get("assertion") != tokEnc { - t.Error("TestBuildRequest: assertion != tokEnc") - t.Errorf(" assertion = %s", v.Get("assertion")) - t.Errorf(" tokEnc = %s", tokEnc) - } -} - -// Given a well formed access request response we should get back a oauth.Token. -func TestHandleResponse(t *testing.T) { - rb := &respBody{ - Access: "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", - Type: "Bearer", - ExpiresIn: 3600, - } - b, err := json.Marshal(rb) - if err != nil { - t.Errorf("TestHandleResponse:json.Marshal: %v", err) - } - r := &http.Response{ - Status: "200 OK", - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader(b)), - } - o, err := handleResponse(r) - if err != nil { - t.Errorf("TestHandleResponse:handleResponse: %v", err) - } - if o.AccessToken != rb.Access { - t.Error("TestHandleResponse: o.AccessToken != rb.Access") - t.Errorf(" o.AccessToken = %s", o.AccessToken) - t.Errorf(" rb.Access = %s", rb.Access) - } - if o.Expired() { - t.Error("TestHandleResponse: o.Expired == true") - } -} - -// passthrough signature for test -type FakeSigner struct{} - -func (f FakeSigner) Sign(tok *Token) ([]byte, []byte, error) { - block, _ := pem.Decode(privateKeyPemBytes) - pKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes) - ss := headerEnc + "." + claimSetEnc - h := sha256.New() - h.Write([]byte(ss)) - b, _ := rsa.SignPKCS1v15(rand.Reader, pKey, crypto.SHA256, h.Sum(nil)) - return []byte(ss), b, nil -} - -// Given an external signer, get back a valid and signed JWT -func TestExternalSigner(t *testing.T) { - tok := NewSignerToken(iss, scope, FakeSigner{}) - enc, _ := tok.Encode() - if enc != tokEnc { - t.Errorf("TestExternalSigner: enc != tokEnc") - t.Errorf(" enc = %s", enc) - t.Errorf(" tokEnc = %s", tokEnc) - } -} - -func TestHandleResponseWithNewExpiry(t *testing.T) { - rb := &respBody{ - IdToken: tokEnc, - } - b, err := json.Marshal(rb) - if err != nil { - t.Errorf("TestHandleResponse:json.Marshal: %v", err) - } - r := &http.Response{ - Status: "200 OK", - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader(b)), - } - o, err := handleResponse(r) - if err != nil { - t.Errorf("TestHandleResponse:handleResponse: %v", err) - } - if o.Expiry != time.Unix(exp, 0) { - t.Error("TestHandleResponse: o.Expiry != exp") - t.Errorf(" o.Expiry = %s", o.Expiry) - t.Errorf(" exp = %s", time.Unix(exp, 0)) - } -} - -// Placeholder for future Assert tests. -func TestAssert(t *testing.T) { - // Since this method makes a call to BuildRequest, an htttp.Client, and - // finally HandleResponse there is not much more to test. This is here - // as a placeholder if that changes. -} - -// Benchmark for the end-to-end encoding of a well formed token. -func BenchmarkTokenEncode(b *testing.B) { - b.StopTimer() - c := &ClaimSet{ - Iss: iss, - Scope: scope, - exp: time.Unix(exp, 0), - iat: time.Unix(iat, 0), - } - tok := &Token{ - ClaimSet: c, - Key: privateKeyPemBytes, - } - b.StartTimer() - for i := 0; i < b.N; i++ { - tok.Encode() - } -} diff --git a/vendor/code.google.com/p/goauth2/oauth/oauth.go b/vendor/code.google.com/p/goauth2/oauth/oauth.go deleted file mode 100644 index 6f1b6c1888..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/oauth.go +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright 2011 The goauth2 Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package oauth supports making OAuth2-authenticated HTTP requests. -// -// Example usage: -// -// // Specify your configuration. (typically as a global variable) -// var config = &oauth.Config{ -// ClientId: YOUR_CLIENT_ID, -// ClientSecret: YOUR_CLIENT_SECRET, -// Scope: "https://www.googleapis.com/auth/buzz", -// AuthURL: "https://accounts.google.com/o/oauth2/auth", -// TokenURL: "https://accounts.google.com/o/oauth2/token", -// RedirectURL: "http://you.example.org/handler", -// } -// -// // A landing page redirects to the OAuth provider to get the auth code. -// func landing(w http.ResponseWriter, r *http.Request) { -// http.Redirect(w, r, config.AuthCodeURL("foo"), http.StatusFound) -// } -// -// // The user will be redirected back to this handler, that takes the -// // "code" query parameter and Exchanges it for an access token. -// func handler(w http.ResponseWriter, r *http.Request) { -// t := &oauth.Transport{Config: config} -// t.Exchange(r.FormValue("code")) -// // The Transport now has a valid Token. Create an *http.Client -// // with which we can make authenticated API requests. -// c := t.Client() -// c.Post(...) -// // ... -// // btw, r.FormValue("state") == "foo" -// } -// -package oauth - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "mime" - "net/http" - "net/url" - "os" - "strconv" - "strings" - "sync" - "time" -) - -// OAuthError is the error type returned by many operations. -// -// In retrospect it should not exist. Don't depend on it. -type OAuthError struct { - prefix string - msg string -} - -func (oe OAuthError) Error() string { - return "OAuthError: " + oe.prefix + ": " + oe.msg -} - -// Cache specifies the methods that implement a Token cache. -type Cache interface { - Token() (*Token, error) - PutToken(*Token) error -} - -// CacheFile implements Cache. Its value is the name of the file in which -// the Token is stored in JSON format. -type CacheFile string - -func (f CacheFile) Token() (*Token, error) { - file, err := os.Open(string(f)) - if err != nil { - return nil, OAuthError{"CacheFile.Token", err.Error()} - } - defer file.Close() - tok := &Token{} - if err := json.NewDecoder(file).Decode(tok); err != nil { - return nil, OAuthError{"CacheFile.Token", err.Error()} - } - return tok, nil -} - -func (f CacheFile) PutToken(tok *Token) error { - file, err := os.OpenFile(string(f), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - return OAuthError{"CacheFile.PutToken", err.Error()} - } - if err := json.NewEncoder(file).Encode(tok); err != nil { - file.Close() - return OAuthError{"CacheFile.PutToken", err.Error()} - } - if err := file.Close(); err != nil { - return OAuthError{"CacheFile.PutToken", err.Error()} - } - return nil -} - -// Config is the configuration of an OAuth consumer. -type Config struct { - // ClientId is the OAuth client identifier used when communicating with - // the configured OAuth provider. - ClientId string - - // ClientSecret is the OAuth client secret used when communicating with - // the configured OAuth provider. - ClientSecret string - - // Scope identifies the level of access being requested. Multiple scope - // values should be provided as a space-delimited string. - Scope string - - // AuthURL is the URL the user will be directed to in order to grant - // access. - AuthURL string - - // TokenURL is the URL used to retrieve OAuth tokens. - TokenURL string - - // RedirectURL is the URL to which the user will be returned after - // granting (or denying) access. - RedirectURL string - - // TokenCache allows tokens to be cached for subsequent requests. - TokenCache Cache - - // AccessType is an OAuth extension that gets sent as the - // "access_type" field in the URL from AuthCodeURL. - // See https://developers.google.com/accounts/docs/OAuth2WebServer. - // It may be "online" (the default) or "offline". - // If your application needs to refresh access tokens when the - // user is not present at the browser, then use offline. This - // will result in your application obtaining a refresh token - // the first time your application exchanges an authorization - // code for a user. - AccessType string - - // ApprovalPrompt indicates whether the user should be - // re-prompted for consent. If set to "auto" (default) the - // user will be prompted only if they haven't previously - // granted consent and the code can only be exchanged for an - // access token. - // If set to "force" the user will always be prompted, and the - // code can be exchanged for a refresh token. - ApprovalPrompt string -} - -// Token contains an end-user's tokens. -// This is the data you must store to persist authentication. -type Token struct { - AccessToken string - RefreshToken string - Expiry time.Time // If zero the token has no (known) expiry time. - - // Extra optionally contains extra metadata from the server - // when updating a token. The only current key that may be - // populated is "id_token". It may be nil and will be - // initialized as needed. - Extra map[string]string -} - -// Expired reports whether the token has expired or is invalid. -func (t *Token) Expired() bool { - if t.AccessToken == "" { - return true - } - if t.Expiry.IsZero() { - return false - } - return t.Expiry.Before(time.Now()) -} - -// Transport implements http.RoundTripper. When configured with a valid -// Config and Token it can be used to make authenticated HTTP requests. -// -// t := &oauth.Transport{config} -// t.Exchange(code) -// // t now contains a valid Token -// r, _, err := t.Client().Get("http://example.org/url/requiring/auth") -// -// It will automatically refresh the Token if it can, -// updating the supplied Token in place. -type Transport struct { - *Config - *Token - - // mu guards modifying the token. - mu sync.Mutex - - // Transport is the HTTP transport to use when making requests. - // It will default to http.DefaultTransport if nil. - // (It should never be an oauth.Transport.) - Transport http.RoundTripper -} - -// Client returns an *http.Client that makes OAuth-authenticated requests. -func (t *Transport) Client() *http.Client { - return &http.Client{Transport: t} -} - -func (t *Transport) transport() http.RoundTripper { - if t.Transport != nil { - return t.Transport - } - return http.DefaultTransport -} - -// AuthCodeURL returns a URL that the end-user should be redirected to, -// so that they may obtain an authorization code. -func (c *Config) AuthCodeURL(state string) string { - url_, err := url.Parse(c.AuthURL) - if err != nil { - panic("AuthURL malformed: " + err.Error()) - } - q := url.Values{ - "response_type": {"code"}, - "client_id": {c.ClientId}, - "state": condVal(state), - "scope": condVal(c.Scope), - "redirect_uri": condVal(c.RedirectURL), - "access_type": condVal(c.AccessType), - "approval_prompt": condVal(c.ApprovalPrompt), - }.Encode() - if url_.RawQuery == "" { - url_.RawQuery = q - } else { - url_.RawQuery += "&" + q - } - return url_.String() -} - -func condVal(v string) []string { - if v == "" { - return nil - } - return []string{v} -} - -// Exchange takes a code and gets access Token from the remote server. -func (t *Transport) Exchange(code string) (*Token, error) { - if t.Config == nil { - return nil, OAuthError{"Exchange", "no Config supplied"} - } - - // If the transport or the cache already has a token, it is - // passed to `updateToken` to preserve existing refresh token. - tok := t.Token - if tok == nil && t.TokenCache != nil { - tok, _ = t.TokenCache.Token() - } - if tok == nil { - tok = new(Token) - } - err := t.updateToken(tok, url.Values{ - "grant_type": {"authorization_code"}, - "redirect_uri": {t.RedirectURL}, - "scope": {t.Scope}, - "code": {code}, - }) - if err != nil { - return nil, err - } - t.Token = tok - if t.TokenCache != nil { - return tok, t.TokenCache.PutToken(tok) - } - return tok, nil -} - -// RoundTrip executes a single HTTP transaction using the Transport's -// Token as authorization headers. -// -// This method will attempt to renew the Token if it has expired and may return -// an error related to that Token renewal before attempting the client request. -// If the Token cannot be renewed a non-nil os.Error value will be returned. -// If the Token is invalid callers should expect HTTP-level errors, -// as indicated by the Response's StatusCode. -func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { - accessToken, err := t.getAccessToken() - if err != nil { - return nil, err - } - // To set the Authorization header, we must make a copy of the Request - // so that we don't modify the Request we were given. - // This is required by the specification of http.RoundTripper. - req = cloneRequest(req) - req.Header.Set("Authorization", "Bearer "+accessToken) - - // Make the HTTP request. - return t.transport().RoundTrip(req) -} - -func (t *Transport) getAccessToken() (string, error) { - t.mu.Lock() - defer t.mu.Unlock() - - if t.Token == nil { - if t.Config == nil { - return "", OAuthError{"RoundTrip", "no Config supplied"} - } - if t.TokenCache == nil { - return "", OAuthError{"RoundTrip", "no Token supplied"} - } - var err error - t.Token, err = t.TokenCache.Token() - if err != nil { - return "", err - } - } - - // Refresh the Token if it has expired. - if t.Expired() { - if err := t.Refresh(); err != nil { - return "", err - } - } - if t.AccessToken == "" { - return "", errors.New("no access token obtained from refresh") - } - return t.AccessToken, nil -} - -// cloneRequest returns a clone of the provided *http.Request. -// The clone is a shallow copy of the struct and its Header map. -func cloneRequest(r *http.Request) *http.Request { - // shallow copy of the struct - r2 := new(http.Request) - *r2 = *r - // deep copy of the Header - r2.Header = make(http.Header) - for k, s := range r.Header { - r2.Header[k] = s - } - return r2 -} - -// Refresh renews the Transport's AccessToken using its RefreshToken. -func (t *Transport) Refresh() error { - if t.Token == nil { - return OAuthError{"Refresh", "no existing Token"} - } - if t.RefreshToken == "" { - return OAuthError{"Refresh", "Token expired; no Refresh Token"} - } - if t.Config == nil { - return OAuthError{"Refresh", "no Config supplied"} - } - - err := t.updateToken(t.Token, url.Values{ - "grant_type": {"refresh_token"}, - "refresh_token": {t.RefreshToken}, - }) - if err != nil { - return err - } - if t.TokenCache != nil { - return t.TokenCache.PutToken(t.Token) - } - return nil -} - -// AuthenticateClient gets an access Token using the client_credentials grant -// type. -func (t *Transport) AuthenticateClient() error { - if t.Config == nil { - return OAuthError{"Exchange", "no Config supplied"} - } - if t.Token == nil { - t.Token = &Token{} - } - return t.updateToken(t.Token, url.Values{"grant_type": {"client_credentials"}}) -} - -// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL -// implements the OAuth2 spec correctly -// See https://code.google.com/p/goauth2/issues/detail?id=31 for background. -// In summary: -// - Reddit only accepts client secret in the Authorization header -// - Dropbox accepts either it in URL param or Auth header, but not both. -// - Google only accepts URL param (not spec compliant?), not Auth header -func providerAuthHeaderWorks(tokenURL string) bool { - if strings.HasPrefix(tokenURL, "https://accounts.google.com/") || - strings.HasPrefix(tokenURL, "https://github.com/") || - strings.HasPrefix(tokenURL, "https://api.instagram.com/") || - strings.HasPrefix(tokenURL, "https://www.douban.com/") { - // Some sites fail to implement the OAuth2 spec fully. - return false - } - - // Assume the provider implements the spec properly - // otherwise. We can add more exceptions as they're - // discovered. We will _not_ be adding configurable hooks - // to this package to let users select server bugs. - return true -} - -// updateToken mutates both tok and v. -func (t *Transport) updateToken(tok *Token, v url.Values) error { - v.Set("client_id", t.ClientId) - bustedAuth := !providerAuthHeaderWorks(t.TokenURL) - if bustedAuth { - v.Set("client_secret", t.ClientSecret) - } - client := &http.Client{Transport: t.transport()} - req, err := http.NewRequest("POST", t.TokenURL, strings.NewReader(v.Encode())) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - if !bustedAuth { - req.SetBasicAuth(t.ClientId, t.ClientSecret) - } - r, err := client.Do(req) - if err != nil { - return err - } - defer r.Body.Close() - if r.StatusCode != 200 { - return OAuthError{"updateToken", "Unexpected HTTP status " + r.Status} - } - var b struct { - Access string `json:"access_token"` - Refresh string `json:"refresh_token"` - ExpiresIn int64 `json:"expires_in"` // seconds - Id string `json:"id_token"` - } - - body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20)) - if err != nil { - return err - } - - content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type")) - switch content { - case "application/x-www-form-urlencoded", "text/plain": - vals, err := url.ParseQuery(string(body)) - if err != nil { - return err - } - - b.Access = vals.Get("access_token") - b.Refresh = vals.Get("refresh_token") - b.ExpiresIn, _ = strconv.ParseInt(vals.Get("expires_in"), 10, 64) - b.Id = vals.Get("id_token") - default: - if err = json.Unmarshal(body, &b); err != nil { - return fmt.Errorf("got bad response from server: %q", body) - } - } - if b.Access == "" { - return errors.New("received empty access token from authorization server") - } - tok.AccessToken = b.Access - // Don't overwrite `RefreshToken` with an empty value - if b.Refresh != "" { - tok.RefreshToken = b.Refresh - } - if b.ExpiresIn == 0 { - tok.Expiry = time.Time{} - } else { - tok.Expiry = time.Now().Add(time.Duration(b.ExpiresIn) * time.Second) - } - if b.Id != "" { - if tok.Extra == nil { - tok.Extra = make(map[string]string) - } - tok.Extra["id_token"] = b.Id - } - return nil -} diff --git a/vendor/code.google.com/p/goauth2/oauth/oauth_test.go b/vendor/code.google.com/p/goauth2/oauth/oauth_test.go deleted file mode 100644 index 9fadc61990..0000000000 --- a/vendor/code.google.com/p/goauth2/oauth/oauth_test.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2011 The goauth2 Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package oauth - -import ( - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "os" - "path/filepath" - "runtime" - "testing" - "time" -) - -var requests = []struct { - path, query, auth string // request - contenttype, body string // response -}{ - { - path: "/token", - query: "grant_type=authorization_code&code=c0d3&client_id=cl13nt1d", - contenttype: "application/json", - auth: "Basic Y2wxM250MWQ6czNjcjN0", - body: ` - { - "access_token":"token1", - "refresh_token":"refreshtoken1", - "id_token":"idtoken1", - "expires_in":3600 - } - `, - }, - {path: "/secure", auth: "Bearer token1", body: "first payload"}, - { - path: "/token", - query: "grant_type=refresh_token&refresh_token=refreshtoken1&client_id=cl13nt1d", - contenttype: "application/json", - auth: "Basic Y2wxM250MWQ6czNjcjN0", - body: ` - { - "access_token":"token2", - "refresh_token":"refreshtoken2", - "id_token":"idtoken2", - "expires_in":3600 - } - `, - }, - {path: "/secure", auth: "Bearer token2", body: "second payload"}, - { - path: "/token", - query: "grant_type=refresh_token&refresh_token=refreshtoken2&client_id=cl13nt1d", - contenttype: "application/x-www-form-urlencoded", - body: "access_token=token3&refresh_token=refreshtoken3&id_token=idtoken3&expires_in=3600", - auth: "Basic Y2wxM250MWQ6czNjcjN0", - }, - {path: "/secure", auth: "Bearer token3", body: "third payload"}, - { - path: "/token", - query: "grant_type=client_credentials&client_id=cl13nt1d", - contenttype: "application/json", - auth: "Basic Y2wxM250MWQ6czNjcjN0", - body: ` - { - "access_token":"token4", - "expires_in":3600 - } - `, - }, - {path: "/secure", auth: "Bearer token4", body: "fourth payload"}, -} - -func TestOAuth(t *testing.T) { - // Set up test server. - n := 0 - handler := func(w http.ResponseWriter, r *http.Request) { - if n >= len(requests) { - t.Errorf("too many requests: %d", n) - return - } - req := requests[n] - n++ - - // Check request. - if g, w := r.URL.Path, req.path; g != w { - t.Errorf("request[%d] got path %s, want %s", n, g, w) - } - want, _ := url.ParseQuery(req.query) - for k := range want { - if g, w := r.FormValue(k), want.Get(k); g != w { - t.Errorf("query[%s] = %s, want %s", k, g, w) - } - } - if g, w := r.Header.Get("Authorization"), req.auth; w != "" && g != w { - t.Errorf("Authorization: %v, want %v", g, w) - } - - // Send response. - w.Header().Set("Content-Type", req.contenttype) - io.WriteString(w, req.body) - } - server := httptest.NewServer(http.HandlerFunc(handler)) - defer server.Close() - - config := &Config{ - ClientId: "cl13nt1d", - ClientSecret: "s3cr3t", - Scope: "https://example.net/scope", - AuthURL: server.URL + "/auth", - TokenURL: server.URL + "/token", - } - - // TODO(adg): test AuthCodeURL - - transport := &Transport{Config: config} - _, err := transport.Exchange("c0d3") - if err != nil { - t.Fatalf("Exchange: %v", err) - } - checkToken(t, transport.Token, "token1", "refreshtoken1", "idtoken1") - - c := transport.Client() - resp, err := c.Get(server.URL + "/secure") - if err != nil { - t.Fatalf("Get: %v", err) - } - checkBody(t, resp, "first payload") - - // test automatic refresh - transport.Expiry = time.Now().Add(-time.Hour) - resp, err = c.Get(server.URL + "/secure") - if err != nil { - t.Fatalf("Get: %v", err) - } - checkBody(t, resp, "second payload") - checkToken(t, transport.Token, "token2", "refreshtoken2", "idtoken2") - - // refresh one more time, but get URL-encoded token instead of JSON - transport.Expiry = time.Now().Add(-time.Hour) - resp, err = c.Get(server.URL + "/secure") - if err != nil { - t.Fatalf("Get: %v", err) - } - checkBody(t, resp, "third payload") - checkToken(t, transport.Token, "token3", "refreshtoken3", "idtoken3") - - transport.Token = &Token{} - err = transport.AuthenticateClient() - if err != nil { - t.Fatalf("AuthenticateClient: %v", err) - } - checkToken(t, transport.Token, "token4", "", "") - resp, err = c.Get(server.URL + "/secure") - if err != nil { - t.Fatalf("Get: %v", err) - } - checkBody(t, resp, "fourth payload") -} - -func checkToken(t *testing.T, tok *Token, access, refresh, id string) { - if g, w := tok.AccessToken, access; g != w { - t.Errorf("AccessToken = %q, want %q", g, w) - } - if g, w := tok.RefreshToken, refresh; g != w { - t.Errorf("RefreshToken = %q, want %q", g, w) - } - if g, w := tok.Extra["id_token"], id; g != w { - t.Errorf("Extra['id_token'] = %q, want %q", g, w) - } - if tok.Expiry.IsZero() { - t.Errorf("Expiry is zero; want ~1 hour") - } else { - exp := tok.Expiry.Sub(time.Now()) - const slop = 3 * time.Second // time moving during test - if (time.Hour-slop) > exp || exp > time.Hour { - t.Errorf("Expiry = %v, want ~1 hour", exp) - } - } -} - -func checkBody(t *testing.T, r *http.Response, body string) { - b, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Errorf("reading reponse body: %v, want %q", err, body) - } - if g, w := string(b), body; g != w { - t.Errorf("request body mismatch: got %q, want %q", g, w) - } -} - -func TestCachePermissions(t *testing.T) { - if runtime.GOOS == "windows" { - // Windows doesn't support file mode bits. - return - } - - td, err := ioutil.TempDir("", "oauth-test") - if err != nil { - t.Fatalf("ioutil.TempDir: %v", err) - } - defer os.RemoveAll(td) - tempFile := filepath.Join(td, "cache-file") - - cf := CacheFile(tempFile) - if err := cf.PutToken(new(Token)); err != nil { - t.Fatalf("PutToken: %v", err) - } - fi, err := os.Stat(tempFile) - if err != nil { - t.Fatalf("os.Stat: %v", err) - } - if fi.Mode()&0077 != 0 { - t.Errorf("Created cache file has mode %#o, want non-accessible to group+other", fi.Mode()) - } -} - -func TestTokenExpired(t *testing.T) { - tests := []struct { - token Token - expired bool - }{ - {Token{AccessToken: "foo"}, false}, - {Token{AccessToken: ""}, true}, - {Token{AccessToken: "foo", Expiry: time.Now().Add(-1 * time.Hour)}, true}, - {Token{AccessToken: "foo", Expiry: time.Now().Add(1 * time.Hour)}, false}, - } - for _, tt := range tests { - if got := tt.token.Expired(); got != tt.expired { - t.Errorf("token %+v Expired = %v; want %v", tt.token, got, !got) - } - } -}