forked from Mirrors/oauth2
147 lines
4.3 KiB
Go
147 lines
4.3 KiB
Go
// 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.
|
|
|
|
// Package google provides support for making
|
|
// OAuth2 authorized and authenticated HTTP requests
|
|
// 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:
|
|
//
|
|
// For more information, please read
|
|
// https://developers.google.com/accounts/docs/OAuth2.
|
|
package google
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/golang/oauth2"
|
|
)
|
|
|
|
const (
|
|
// Google endpoints.
|
|
uriGoogleAuth = "https://accounts.google.com/o/oauth2/auth"
|
|
uriGoogleToken = "https://accounts.google.com/o/oauth2/token"
|
|
)
|
|
|
|
type metaTokenRespBody struct {
|
|
AccessToken string `json:"access_token"`
|
|
ExpiresIn time.Duration `json:"expires_in"`
|
|
TokenType string `json:"token_type"`
|
|
}
|
|
|
|
// ComputeEngineConfig represents a OAuth 2.0 consumer client
|
|
// running on Google Compute Engine.
|
|
type ComputeEngineConfig struct {
|
|
// Client is the HTTP client to be used to retrieve
|
|
// tokens from the OAuth 2.0 provider.
|
|
Client *http.Client
|
|
|
|
// Transport is the round tripper to be used
|
|
// to construct new oauth2.Transport instances from
|
|
// this configuration.
|
|
Transport http.RoundTripper
|
|
|
|
account string
|
|
}
|
|
|
|
// NewConfig creates a new OAuth2 config that uses Google
|
|
// endpoints.
|
|
func NewConfig(opts *oauth2.Options) (*oauth2.Config, error) {
|
|
return oauth2.NewConfig(opts, uriGoogleAuth, uriGoogleToken)
|
|
}
|
|
|
|
// NewServiceAccountConfig creates a new JWT config that can
|
|
// fetch Bearer JWT tokens from Google endpoints.
|
|
func NewServiceAccountConfig(opts *oauth2.JWTOptions) (*oauth2.JWTConfig, error) {
|
|
return oauth2.NewJWTConfig(opts, uriGoogleToken)
|
|
}
|
|
|
|
// NewServiceAccountJSONConfig creates a new JWT config from a
|
|
// JSON key file downloaded from the Google Developers Console.
|
|
// See the "Credentials" page under "APIs & Auth" for your project
|
|
// at https://console.developers.google.com.
|
|
func NewServiceAccountJSONConfig(filename string, scopes ...string) (*oauth2.JWTConfig, error) {
|
|
b, err := ioutil.ReadFile(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var key struct {
|
|
Email string `json:"client_email"`
|
|
PrivateKey string `json:"private_key"`
|
|
}
|
|
if err := json.Unmarshal(b, &key); err != nil {
|
|
return nil, err
|
|
}
|
|
opts := &oauth2.JWTOptions{
|
|
Email: key.Email,
|
|
PrivateKey: []byte(key.PrivateKey),
|
|
Scopes: scopes,
|
|
}
|
|
return NewServiceAccountConfig(opts)
|
|
}
|
|
|
|
// NewComputeEngineConfig creates a new config that can fetch tokens
|
|
// from Google Compute Engine instance's metaserver. If no account is
|
|
// provided, default is used.
|
|
func NewComputeEngineConfig(account string) *ComputeEngineConfig {
|
|
return &ComputeEngineConfig{account: account}
|
|
}
|
|
|
|
// NewTransport creates an authorized transport.
|
|
func (c *ComputeEngineConfig) NewTransport() *oauth2.Transport {
|
|
return oauth2.NewTransport(c.transport(), c, nil)
|
|
}
|
|
|
|
// FetchToken retrieves a new access token via metadata server.
|
|
func (c *ComputeEngineConfig) FetchToken(existing *oauth2.Token) (token *oauth2.Token, err error) {
|
|
account := "default"
|
|
if c.account != "" {
|
|
account = c.account
|
|
}
|
|
u := "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" + account + "/token"
|
|
req, err := http.NewRequest("GET", u, nil)
|
|
if err != nil {
|
|
return
|
|
}
|
|
req.Header.Add("X-Google-Metadata-Request", "True")
|
|
resp, err := c.client().Do(req)
|
|
if err != nil {
|
|
return
|
|
}
|
|
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
|
|
}
|
|
token = &oauth2.Token{
|
|
AccessToken: tokenResp.AccessToken,
|
|
TokenType: tokenResp.TokenType,
|
|
Expiry: time.Now().Add(tokenResp.ExpiresIn * time.Second),
|
|
}
|
|
return
|
|
}
|
|
|
|
func (c *ComputeEngineConfig) transport() http.RoundTripper {
|
|
if c.Transport != nil {
|
|
return c.Transport
|
|
}
|
|
return http.DefaultTransport
|
|
}
|
|
|
|
func (c *ComputeEngineConfig) client() *http.Client {
|
|
if c.Client != nil {
|
|
return c.Client
|
|
}
|
|
return http.DefaultClient
|
|
}
|