2014-05-17 11: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 14:06:46 -04:00
|
|
|
|
2014-05-05 17:54:23 -04:00
|
|
|
// Package google provides support for making
|
|
|
|
// OAuth2 authorized and authenticated HTTP requests
|
2014-05-10 07: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-05 17:54:23 -04:00
|
|
|
//
|
|
|
|
// For more information, please read
|
|
|
|
// https://developers.google.com/accounts/docs/OAuth2.
|
2014-11-26 14:44:45 -05:00
|
|
|
package google // import "golang.org/x/oauth2/google"
|
2014-05-05 17:54:23 -04:00
|
|
|
|
|
|
|
import (
|
2014-05-11 11:06:03 -04:00
|
|
|
"encoding/json"
|
2014-11-06 19:36:41 -05:00
|
|
|
|
2014-10-23 13:06:00 -04:00
|
|
|
"fmt"
|
2014-09-03 14:40:47 -04:00
|
|
|
"io/ioutil"
|
2014-05-11 11:06:03 -04:00
|
|
|
"net/http"
|
2014-11-06 19:36:41 -05:00
|
|
|
"net/url"
|
2014-05-11 11:06:03 -04:00
|
|
|
"time"
|
|
|
|
|
2014-11-26 14:44:45 -05:00
|
|
|
"golang.org/x/oauth2"
|
|
|
|
"golang.org/x/oauth2/internal"
|
2014-05-05 17:54:23 -04:00
|
|
|
)
|
|
|
|
|
2014-11-06 19:36:41 -05:00
|
|
|
var (
|
|
|
|
uriGoogleAuth, _ = url.Parse("https://accounts.google.com/o/oauth2/auth")
|
|
|
|
uriGoogleToken, _ = url.Parse("https://accounts.google.com/o/oauth2/token")
|
2014-05-05 17:54:23 -04:00
|
|
|
)
|
|
|
|
|
2014-05-11 11:06:03 -04:00
|
|
|
type metaTokenRespBody struct {
|
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
ExpiresIn time.Duration `json:"expires_in"`
|
|
|
|
TokenType string `json:"token_type"`
|
|
|
|
}
|
|
|
|
|
2014-11-06 19:36:41 -05:00
|
|
|
// 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
|
2014-09-03 14:40:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-06 19:36:41 -05:00
|
|
|
// 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
|
|
|
|
}
|
2014-05-10 03:41:39 -04:00
|
|
|
}
|
|
|
|
|
2014-11-06 19:36:41 -05:00
|
|
|
// 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
|
2014-05-11 11:06:03 -04:00
|
|
|
}
|
2014-05-05 17:54:23 -04:00
|
|
|
}
|
2014-09-02 17:06:51 -04:00
|
|
|
|
2014-11-06 19:36:41 -05:00
|
|
|
// 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
|
2014-09-02 17:06:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-06 19:36:41 -05:00
|
|
|
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
|
2014-09-02 17:06:51 -04:00
|
|
|
}
|
|
|
|
}
|