2014-05-17 19:26:57 +04:00
|
|
|
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
2014-05-13 22:06:46 +04:00
|
|
|
|
2014-05-06 01:54:23 +04:00
|
|
|
// Package google provides support for making
|
|
|
|
// OAuth2 authorized and authenticated HTTP requests
|
2014-05-10 15:50:51 +04:00
|
|
|
// to Google APIs. It supports Web server, client-side,
|
|
|
|
// service accounts, Google Compute Engine service accounts,
|
|
|
|
// and Google App Engine service accounts authorization
|
|
|
|
// and authentications flows:
|
2014-05-06 01:54:23 +04:00
|
|
|
//
|
|
|
|
// For more information, please read
|
|
|
|
// https://developers.google.com/accounts/docs/OAuth2.
|
2014-11-26 22:44:45 +03:00
|
|
|
package google // import "golang.org/x/oauth2/google"
|
2014-05-06 01:54:23 +04:00
|
|
|
|
|
|
|
import (
|
2014-05-11 19:06:03 +04:00
|
|
|
"encoding/json"
|
2014-10-23 21:06:00 +04:00
|
|
|
"fmt"
|
2014-12-11 10:30:13 +03:00
|
|
|
"net"
|
2014-05-11 19:06:03 +04:00
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
2014-11-26 22:44:45 +03:00
|
|
|
"golang.org/x/oauth2"
|
2014-12-31 02:11:02 +03:00
|
|
|
"golang.org/x/oauth2/jwt"
|
2014-05-06 01:54:23 +04:00
|
|
|
)
|
|
|
|
|
2014-12-31 00:25:01 +03:00
|
|
|
// TODO(bradfitz,jbd): import "google.golang.org/cloud/compute/metadata" instead of
|
|
|
|
// the metaClient and metadata.google.internal stuff below.
|
|
|
|
|
2014-12-11 10:30:13 +03:00
|
|
|
// Endpoint is Google's OAuth 2.0 endpoint.
|
|
|
|
var Endpoint = oauth2.Endpoint{
|
|
|
|
AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
|
|
|
TokenURL: "https://accounts.google.com/o/oauth2/token",
|
|
|
|
}
|
|
|
|
|
|
|
|
// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
|
|
|
|
const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
|
|
|
|
|
|
|
|
// JWTConfigFromJSON uses a Google Developers service account JSON key file to read
|
|
|
|
// the credentials that authorize and authenticate the requests.
|
|
|
|
// Create a service account on "Credentials" page under "APIs & Auth" for your
|
|
|
|
// project at https://console.developers.google.com to download a JSON key file.
|
2014-12-31 02:11:02 +03:00
|
|
|
func JWTConfigFromJSON(ctx oauth2.Context, jsonKey []byte, scope ...string) (*jwt.Config, error) {
|
2014-12-11 10:30:13 +03:00
|
|
|
var key struct {
|
|
|
|
Email string `json:"client_email"`
|
|
|
|
PrivateKey string `json:"private_key"`
|
|
|
|
}
|
|
|
|
if err := json.Unmarshal(jsonKey, &key); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2014-12-31 02:11:02 +03:00
|
|
|
return &jwt.Config{
|
2014-12-11 10:30:13 +03:00
|
|
|
Email: key.Email,
|
|
|
|
PrivateKey: []byte(key.PrivateKey),
|
|
|
|
Scopes: scope,
|
|
|
|
TokenURL: JWTTokenURL,
|
|
|
|
}, nil
|
|
|
|
}
|
2014-05-06 01:54:23 +04:00
|
|
|
|
2014-05-11 19:06:03 +04:00
|
|
|
type metaTokenRespBody struct {
|
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
ExpiresIn time.Duration `json:"expires_in"`
|
|
|
|
TokenType string `json:"token_type"`
|
|
|
|
}
|
|
|
|
|
2014-12-11 10:30:13 +03:00
|
|
|
// ComputeTokenSource returns a token source that fetches access tokens
|
|
|
|
// from Google Compute Engine (GCE)'s metadata server. It's only valid to use
|
|
|
|
// this token source if your program is running on a GCE instance.
|
|
|
|
// If no account is specified, "default" is used.
|
|
|
|
// Further information about retrieving access tokens from the GCE metadata
|
|
|
|
// server can be found at https://cloud.google.com/compute/docs/authentication.
|
|
|
|
func ComputeTokenSource(account string) oauth2.TokenSource {
|
2014-12-31 00:25:01 +03:00
|
|
|
return oauth2.ReuseTokenSource(nil, &computeSource{account: account})
|
2014-09-03 22:40:47 +04:00
|
|
|
}
|
|
|
|
|
2014-12-11 10:30:13 +03:00
|
|
|
type computeSource struct {
|
|
|
|
account string
|
2014-05-10 11:41:39 +04:00
|
|
|
}
|
|
|
|
|
2014-12-11 10:30:13 +03:00
|
|
|
var metaClient = &http.Client{
|
|
|
|
Transport: &http.Transport{
|
|
|
|
Dial: (&net.Dialer{
|
|
|
|
Timeout: 750 * time.Millisecond,
|
|
|
|
KeepAlive: 30 * time.Second,
|
|
|
|
}).Dial,
|
|
|
|
ResponseHeaderTimeout: 750 * time.Millisecond,
|
|
|
|
},
|
2014-05-06 01:54:23 +04:00
|
|
|
}
|
2014-09-03 01:06:51 +04:00
|
|
|
|
2014-12-11 10:30:13 +03:00
|
|
|
func (cs *computeSource) Token() (*oauth2.Token, error) {
|
|
|
|
acct := cs.account
|
|
|
|
if acct == "" {
|
|
|
|
acct = "default"
|
2014-09-03 01:06:51 +04:00
|
|
|
}
|
2014-12-11 10:30:13 +03:00
|
|
|
u := "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" + acct + "/token"
|
|
|
|
req, err := http.NewRequest("GET", u, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req.Header.Add("X-Google-Metadata-Request", "True")
|
|
|
|
resp, err := metaClient.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
|
|
|
return nil, fmt.Errorf("oauth2: can't retrieve a token from metadata server, status code: %d", resp.StatusCode)
|
|
|
|
}
|
|
|
|
var tokenResp metaTokenRespBody
|
|
|
|
err = json.NewDecoder(resp.Body).Decode(&tokenResp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2014-09-03 01:06:51 +04:00
|
|
|
}
|
2014-12-11 10:30:13 +03:00
|
|
|
return &oauth2.Token{
|
|
|
|
AccessToken: tokenResp.AccessToken,
|
|
|
|
TokenType: tokenResp.TokenType,
|
|
|
|
Expiry: time.Now().Add(tokenResp.ExpiresIn * time.Second),
|
|
|
|
}, nil
|
2014-09-03 01:06:51 +04:00
|
|
|
}
|