forked from remote/oauth2
oauth2: rewrite google package, fix the broken build
Change-Id: I2753a88d7be483bdbc0cac09a1beccc4806ea4bc Reviewed-on: https://go-review.googlesource.com/1361 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Andrew Gerrand <adg@golang.org>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
a568078818
commit
9b6b7610ad
162
google/google.go
162
google/google.go
@@ -17,19 +17,41 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
uriGoogleAuth, _ = url.Parse("https://accounts.google.com/o/oauth2/auth")
|
||||
uriGoogleToken, _ = url.Parse("https://accounts.google.com/o/oauth2/token")
|
||||
)
|
||||
// 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.
|
||||
func JWTConfigFromJSON(ctx oauth2.Context, jsonKey []byte, scope ...string) (*oauth2.JWTConfig, error) {
|
||||
var key struct {
|
||||
Email string `json:"client_email"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
}
|
||||
if err := json.Unmarshal(jsonKey, &key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oauth2.JWTConfig{
|
||||
Email: key.Email,
|
||||
PrivateKey: []byte(key.PrivateKey),
|
||||
Scopes: scope,
|
||||
TokenURL: JWTTokenURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type metaTokenRespBody struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
@@ -37,93 +59,57 @@ type metaTokenRespBody struct {
|
||||
TokenType string `json:"token_type"`
|
||||
}
|
||||
|
||||
// JWTEndpoint adds the endpoints required to complete the 2-legged service account flow.
|
||||
func JWTEndpoint() oauth2.Option {
|
||||
return func(opts *oauth2.Options) error {
|
||||
opts.AUD = uriGoogleToken
|
||||
return nil
|
||||
}
|
||||
// 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 {
|
||||
return &computeSource{account: account}
|
||||
}
|
||||
|
||||
// Endpoint adds the endpoints required to do the 3-legged Web server flow.
|
||||
func Endpoint() oauth2.Option {
|
||||
return func(opts *oauth2.Options) error {
|
||||
opts.AuthURL = uriGoogleAuth
|
||||
opts.TokenURL = uriGoogleToken
|
||||
return nil
|
||||
}
|
||||
type computeSource struct {
|
||||
account string
|
||||
}
|
||||
|
||||
// ComputeEngineAccount uses the specified account to retrieve an access
|
||||
// token from the Google Compute Engine's metadata server. If no user is
|
||||
// provided, "default" is being used.
|
||||
func ComputeEngineAccount(account string) oauth2.Option {
|
||||
return func(opts *oauth2.Options) error {
|
||||
if account == "" {
|
||||
account = "default"
|
||||
}
|
||||
opts.TokenFetcherFunc = makeComputeFetcher(opts, account)
|
||||
return nil
|
||||
}
|
||||
var metaClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 750 * time.Millisecond,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
ResponseHeaderTimeout: 750 * time.Millisecond,
|
||||
},
|
||||
}
|
||||
|
||||
// ServiceAccountJSONKey uses the provided Google Developers
|
||||
// JSON key file to authorize the user. See the "Credentials" page under
|
||||
// "APIs & Auth" for your project at https://console.developers.google.com
|
||||
// to download a JSON key file.
|
||||
func ServiceAccountJSONKey(filename string) oauth2.Option {
|
||||
return func(opts *oauth2.Options) error {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var key struct {
|
||||
Email string `json:"client_email"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &key); err != nil {
|
||||
return err
|
||||
}
|
||||
pk, err := internal.ParseKey([]byte(key.PrivateKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.Email = key.Email
|
||||
opts.PrivateKey = pk
|
||||
opts.AUD = uriGoogleToken
|
||||
return nil
|
||||
func (cs *computeSource) Token() (*oauth2.Token, error) {
|
||||
acct := cs.account
|
||||
if acct == "" {
|
||||
acct = "default"
|
||||
}
|
||||
}
|
||||
|
||||
func makeComputeFetcher(opts *oauth2.Options, account string) func(*oauth2.Token) (*oauth2.Token, error) {
|
||||
return func(t *oauth2.Token) (*oauth2.Token, error) {
|
||||
u := "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" + account + "/token"
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("X-Google-Metadata-Request", "True")
|
||||
c := &http.Client{}
|
||||
if opts.Client != nil {
|
||||
c = opts.Client
|
||||
}
|
||||
resp, err := c.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
|
||||
}
|
||||
return &oauth2.Token{
|
||||
AccessToken: tokenResp.AccessToken,
|
||||
TokenType: tokenResp.TokenType,
|
||||
Expiry: time.Now().Add(tokenResp.ExpiresIn * time.Second),
|
||||
}, nil
|
||||
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
|
||||
}
|
||||
return &oauth2.Token{
|
||||
AccessToken: tokenResp.AccessToken,
|
||||
TokenType: tokenResp.TokenType,
|
||||
Expiry: time.Now().Add(tokenResp.ExpiresIn * time.Second),
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user