mirror of https://github.com/grafana/grafana
Updated golang/x/oauth2 dependency, #1710
parent
e86bedddb2
commit
b8c378f2f0
@ -0,0 +1,16 @@ |
||||
// Copyright 2015 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 facebook provides constants for using OAuth2 to access Facebook.
|
||||
package facebook // import "golang.org/x/oauth2/facebook"
|
||||
|
||||
import ( |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
// Endpoint is Facebook's OAuth 2.0 endpoint.
|
||||
var Endpoint = oauth2.Endpoint{ |
||||
AuthURL: "https://www.facebook.com/dialog/oauth", |
||||
TokenURL: "https://graph.facebook.com/oauth/access_token", |
||||
} |
||||
@ -0,0 +1,13 @@ |
||||
// Copyright 2015 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.
|
||||
|
||||
// +build appengine appenginevm
|
||||
|
||||
package google |
||||
|
||||
import "google.golang.org/appengine" |
||||
|
||||
func init() { |
||||
appengineTokenFunc = appengine.AccessToken |
||||
} |
||||
@ -1,36 +0,0 @@ |
||||
// 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.
|
||||
|
||||
// +build appenginevm !appengine
|
||||
|
||||
package google |
||||
|
||||
import ( |
||||
"time" |
||||
|
||||
"golang.org/x/oauth2" |
||||
"google.golang.org/appengine" |
||||
) |
||||
|
||||
// AppEngineTokenSource returns a token source that fetches tokens
|
||||
// issued to the current App Engine application's service account.
|
||||
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine
|
||||
// that involves user accounts, see oauth2.Config instead.
|
||||
//
|
||||
// You are required to provide a valid appengine.Context as context.
|
||||
func AppEngineTokenSource(ctx appengine.Context, scope ...string) oauth2.TokenSource { |
||||
return &appEngineTokenSource{ |
||||
ctx: ctx, |
||||
scopes: scope, |
||||
fetcherFunc: aeVMFetcherFunc, |
||||
} |
||||
} |
||||
|
||||
var aeVMFetcherFunc = func(ctx oauth2.Context, scope ...string) (string, time.Time, error) { |
||||
c, ok := ctx.(appengine.Context) |
||||
if !ok { |
||||
return "", time.Time{}, errInvalidContext |
||||
} |
||||
return appengine.AccessToken(c, scope...) |
||||
} |
||||
@ -0,0 +1,154 @@ |
||||
// Copyright 2015 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 |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"os" |
||||
"path/filepath" |
||||
"runtime" |
||||
|
||||
"golang.org/x/net/context" |
||||
"golang.org/x/oauth2" |
||||
"golang.org/x/oauth2/jwt" |
||||
"google.golang.org/cloud/compute/metadata" |
||||
) |
||||
|
||||
// DefaultClient returns an HTTP Client that uses the
|
||||
// DefaultTokenSource to obtain authentication credentials.
|
||||
//
|
||||
// This client should be used when developing services
|
||||
// that run on Google App Engine or Google Compute Engine
|
||||
// and use "Application Default Credentials."
|
||||
//
|
||||
// For more details, see:
|
||||
// https://developers.google.com/accounts/application-default-credentials
|
||||
//
|
||||
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { |
||||
ts, err := DefaultTokenSource(ctx, scope...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return oauth2.NewClient(ctx, ts), nil |
||||
} |
||||
|
||||
// DefaultTokenSource is a token source that uses
|
||||
// "Application Default Credentials".
|
||||
//
|
||||
// It looks for credentials in the following places,
|
||||
// preferring the first location found:
|
||||
//
|
||||
// 1. A JSON file whose path is specified by the
|
||||
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
|
||||
// 2. A JSON file in a location known to the gcloud command-line tool.
|
||||
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
|
||||
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
|
||||
// 3. On Google App Engine it uses the appengine.AccessToken function.
|
||||
// 4. On Google Compute Engine, it fetches credentials from the metadata server.
|
||||
// (In this final case any provided scopes are ignored.)
|
||||
//
|
||||
// For more details, see:
|
||||
// https://developers.google.com/accounts/application-default-credentials
|
||||
//
|
||||
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) { |
||||
// First, try the environment variable.
|
||||
const envVar = "GOOGLE_APPLICATION_CREDENTIALS" |
||||
if filename := os.Getenv(envVar); filename != "" { |
||||
ts, err := tokenSourceFromFile(ctx, filename, scope) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err) |
||||
} |
||||
return ts, nil |
||||
} |
||||
|
||||
// Second, try a well-known file.
|
||||
filename := wellKnownFile() |
||||
_, err := os.Stat(filename) |
||||
if err == nil { |
||||
ts, err2 := tokenSourceFromFile(ctx, filename, scope) |
||||
if err2 == nil { |
||||
return ts, nil |
||||
} |
||||
err = err2 |
||||
} else if os.IsNotExist(err) { |
||||
err = nil // ignore this error
|
||||
} |
||||
if err != nil { |
||||
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) |
||||
} |
||||
|
||||
// Third, if we're on Google App Engine use those credentials.
|
||||
if appengineTokenFunc != nil { |
||||
return AppEngineTokenSource(ctx, scope...), nil |
||||
} |
||||
|
||||
// Fourth, if we're on Google Compute Engine use the metadata server.
|
||||
if metadata.OnGCE() { |
||||
return ComputeTokenSource(""), nil |
||||
} |
||||
|
||||
// None are found; return helpful error.
|
||||
const url = "https://developers.google.com/accounts/application-default-credentials" |
||||
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) |
||||
} |
||||
|
||||
func wellKnownFile() string { |
||||
const f = "application_default_credentials.json" |
||||
if runtime.GOOS == "windows" { |
||||
return filepath.Join(os.Getenv("APPDATA"), "gcloud", f) |
||||
} |
||||
return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f) |
||||
} |
||||
|
||||
func tokenSourceFromFile(ctx context.Context, filename string, scopes []string) (oauth2.TokenSource, error) { |
||||
b, err := ioutil.ReadFile(filename) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
var d struct { |
||||
// Common fields
|
||||
Type string |
||||
ClientID string `json:"client_id"` |
||||
|
||||
// User Credential fields
|
||||
ClientSecret string `json:"client_secret"` |
||||
RefreshToken string `json:"refresh_token"` |
||||
|
||||
// Service Account fields
|
||||
ClientEmail string `json:"client_email"` |
||||
PrivateKeyID string `json:"private_key_id"` |
||||
PrivateKey string `json:"private_key"` |
||||
} |
||||
if err := json.Unmarshal(b, &d); err != nil { |
||||
return nil, err |
||||
} |
||||
switch d.Type { |
||||
case "authorized_user": |
||||
cfg := &oauth2.Config{ |
||||
ClientID: d.ClientID, |
||||
ClientSecret: d.ClientSecret, |
||||
Scopes: append([]string{}, scopes...), // copy
|
||||
Endpoint: Endpoint, |
||||
} |
||||
tok := &oauth2.Token{RefreshToken: d.RefreshToken} |
||||
return cfg.TokenSource(ctx, tok), nil |
||||
case "service_account": |
||||
cfg := &jwt.Config{ |
||||
Email: d.ClientEmail, |
||||
PrivateKey: []byte(d.PrivateKey), |
||||
Scopes: append([]string{}, scopes...), // copy
|
||||
TokenURL: JWTTokenURL, |
||||
} |
||||
return cfg.TokenSource(ctx), nil |
||||
case "": |
||||
return nil, errors.New("missing 'type' field in credentials") |
||||
default: |
||||
return nil, fmt.Errorf("unknown credential type: %q", d.Type) |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@ |
||||
// Copyright 2015 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 |
||||
|
||||
import ( |
||||
"strings" |
||||
"testing" |
||||
) |
||||
|
||||
var webJSONKey = []byte(` |
||||
{ |
||||
"web": { |
||||
"auth_uri": "https://google.com/o/oauth2/auth", |
||||
"client_secret": "3Oknc4jS_wA2r9i", |
||||
"token_uri": "https://google.com/o/oauth2/token", |
||||
"client_email": "222-nprqovg5k43uum874cs9osjt2koe97g8@developer.gserviceaccount.com", |
||||
"redirect_uris": ["https://www.example.com/oauth2callback"], |
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/222-nprqovg5k43uum874cs9osjt2koe97g8@developer.gserviceaccount.com", |
||||
"client_id": "222-nprqovg5k43uum874cs9osjt2koe97g8.apps.googleusercontent.com", |
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", |
||||
"javascript_origins": ["https://www.example.com"] |
||||
} |
||||
}`) |
||||
|
||||
var installedJSONKey = []byte(`{ |
||||
"installed": { |
||||
"client_id": "222-installed.apps.googleusercontent.com", |
||||
"redirect_uris": ["https://www.example.com/oauth2callback"] |
||||
} |
||||
}`) |
||||
|
||||
func TestConfigFromJSON(t *testing.T) { |
||||
conf, err := ConfigFromJSON(webJSONKey, "scope1", "scope2") |
||||
if err != nil { |
||||
t.Error(err) |
||||
} |
||||
if got, want := conf.ClientID, "222-nprqovg5k43uum874cs9osjt2koe97g8.apps.googleusercontent.com"; got != want { |
||||
t.Errorf("ClientID = %q; want %q", got, want) |
||||
} |
||||
if got, want := conf.ClientSecret, "3Oknc4jS_wA2r9i"; got != want { |
||||
t.Errorf("ClientSecret = %q; want %q", got, want) |
||||
} |
||||
if got, want := conf.RedirectURL, "https://www.example.com/oauth2callback"; got != want { |
||||
t.Errorf("RedictURL = %q; want %q", got, want) |
||||
} |
||||
if got, want := strings.Join(conf.Scopes, ","), "scope1,scope2"; got != want { |
||||
t.Errorf("Scopes = %q; want %q", got, want) |
||||
} |
||||
if got, want := conf.Endpoint.AuthURL, "https://google.com/o/oauth2/auth"; got != want { |
||||
t.Errorf("AuthURL = %q; want %q", got, want) |
||||
} |
||||
if got, want := conf.Endpoint.TokenURL, "https://google.com/o/oauth2/token"; got != want { |
||||
t.Errorf("TokenURL = %q; want %q", got, want) |
||||
} |
||||
} |
||||
|
||||
func TestConfigFromJSON_Installed(t *testing.T) { |
||||
conf, err := ConfigFromJSON(installedJSONKey) |
||||
if err != nil { |
||||
t.Error(err) |
||||
} |
||||
if got, want := conf.ClientID, "222-installed.apps.googleusercontent.com"; got != want { |
||||
t.Errorf("ClientID = %q; want %q", got, want) |
||||
} |
||||
} |
||||
@ -0,0 +1,168 @@ |
||||
// Copyright 2015 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 |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"os" |
||||
"os/user" |
||||
"path/filepath" |
||||
"runtime" |
||||
"strings" |
||||
"time" |
||||
|
||||
"golang.org/x/net/context" |
||||
"golang.org/x/oauth2" |
||||
"golang.org/x/oauth2/internal" |
||||
) |
||||
|
||||
type sdkCredentials struct { |
||||
Data []struct { |
||||
Credential struct { |
||||
ClientID string `json:"client_id"` |
||||
ClientSecret string `json:"client_secret"` |
||||
AccessToken string `json:"access_token"` |
||||
RefreshToken string `json:"refresh_token"` |
||||
TokenExpiry *time.Time `json:"token_expiry"` |
||||
} `json:"credential"` |
||||
Key struct { |
||||
Account string `json:"account"` |
||||
Scope string `json:"scope"` |
||||
} `json:"key"` |
||||
} |
||||
} |
||||
|
||||
// An SDKConfig provides access to tokens from an account already
|
||||
// authorized via the Google Cloud SDK.
|
||||
type SDKConfig struct { |
||||
conf oauth2.Config |
||||
initialToken *oauth2.Token |
||||
} |
||||
|
||||
// NewSDKConfig creates an SDKConfig for the given Google Cloud SDK
|
||||
// account. If account is empty, the account currently active in
|
||||
// Google Cloud SDK properties is used.
|
||||
// Google Cloud SDK credentials must be created by running `gcloud auth`
|
||||
// before using this function.
|
||||
// The Google Cloud SDK is available at https://cloud.google.com/sdk/.
|
||||
func NewSDKConfig(account string) (*SDKConfig, error) { |
||||
configPath, err := sdkConfigPath() |
||||
if err != nil { |
||||
return nil, fmt.Errorf("oauth2/google: error getting SDK config path: %v", err) |
||||
} |
||||
credentialsPath := filepath.Join(configPath, "credentials") |
||||
f, err := os.Open(credentialsPath) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("oauth2/google: failed to load SDK credentials: %v", err) |
||||
} |
||||
defer f.Close() |
||||
|
||||
var c sdkCredentials |
||||
if err := json.NewDecoder(f).Decode(&c); err != nil { |
||||
return nil, fmt.Errorf("oauth2/google: failed to decode SDK credentials from %q: %v", credentialsPath, err) |
||||
} |
||||
if len(c.Data) == 0 { |
||||
return nil, fmt.Errorf("oauth2/google: no credentials found in %q, run `gcloud auth login` to create one", credentialsPath) |
||||
} |
||||
if account == "" { |
||||
propertiesPath := filepath.Join(configPath, "properties") |
||||
f, err := os.Open(propertiesPath) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("oauth2/google: failed to load SDK properties: %v", err) |
||||
} |
||||
defer f.Close() |
||||
ini, err := internal.ParseINI(f) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("oauth2/google: failed to parse SDK properties %q: %v", propertiesPath, err) |
||||
} |
||||
core, ok := ini["core"] |
||||
if !ok { |
||||
return nil, fmt.Errorf("oauth2/google: failed to find [core] section in %v", ini) |
||||
} |
||||
active, ok := core["account"] |
||||
if !ok { |
||||
return nil, fmt.Errorf("oauth2/google: failed to find %q attribute in %v", "account", core) |
||||
} |
||||
account = active |
||||
} |
||||
|
||||
for _, d := range c.Data { |
||||
if account == "" || d.Key.Account == account { |
||||
if d.Credential.AccessToken == "" && d.Credential.RefreshToken == "" { |
||||
return nil, fmt.Errorf("oauth2/google: no token available for account %q", account) |
||||
} |
||||
var expiry time.Time |
||||
if d.Credential.TokenExpiry != nil { |
||||
expiry = *d.Credential.TokenExpiry |
||||
} |
||||
return &SDKConfig{ |
||||
conf: oauth2.Config{ |
||||
ClientID: d.Credential.ClientID, |
||||
ClientSecret: d.Credential.ClientSecret, |
||||
Scopes: strings.Split(d.Key.Scope, " "), |
||||
Endpoint: Endpoint, |
||||
RedirectURL: "oob", |
||||
}, |
||||
initialToken: &oauth2.Token{ |
||||
AccessToken: d.Credential.AccessToken, |
||||
RefreshToken: d.Credential.RefreshToken, |
||||
Expiry: expiry, |
||||
}, |
||||
}, nil |
||||
} |
||||
} |
||||
return nil, fmt.Errorf("oauth2/google: no such credentials for account %q", account) |
||||
} |
||||
|
||||
// Client returns an HTTP client using Google Cloud SDK credentials to
|
||||
// authorize requests. The token will auto-refresh as necessary. The
|
||||
// underlying http.RoundTripper will be obtained using the provided
|
||||
// context. The returned client and its Transport should not be
|
||||
// modified.
|
||||
func (c *SDKConfig) Client(ctx context.Context) *http.Client { |
||||
return &http.Client{ |
||||
Transport: &oauth2.Transport{ |
||||
Source: c.TokenSource(ctx), |
||||
}, |
||||
} |
||||
} |
||||
|
||||
// TokenSource returns an oauth2.TokenSource that retrieve tokens from
|
||||
// Google Cloud SDK credentials using the provided context.
|
||||
// It will returns the current access token stored in the credentials,
|
||||
// and refresh it when it expires, but it won't update the credentials
|
||||
// with the new access token.
|
||||
func (c *SDKConfig) TokenSource(ctx context.Context) oauth2.TokenSource { |
||||
return c.conf.TokenSource(ctx, c.initialToken) |
||||
} |
||||
|
||||
// Scopes are the OAuth 2.0 scopes the current account is authorized for.
|
||||
func (c *SDKConfig) Scopes() []string { |
||||
return c.conf.Scopes |
||||
} |
||||
|
||||
// sdkConfigPath tries to guess where the gcloud config is located.
|
||||
// It can be overridden during tests.
|
||||
var sdkConfigPath = func() (string, error) { |
||||
if runtime.GOOS == "windows" { |
||||
return filepath.Join(os.Getenv("APPDATA"), "gcloud"), nil |
||||
} |
||||
homeDir := guessUnixHomeDir() |
||||
if homeDir == "" { |
||||
return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty") |
||||
} |
||||
return filepath.Join(homeDir, ".config", "gcloud"), nil |
||||
} |
||||
|
||||
func guessUnixHomeDir() string { |
||||
usr, err := user.Current() |
||||
if err == nil { |
||||
return usr.HomeDir |
||||
} |
||||
return os.Getenv("HOME") |
||||
} |
||||
@ -0,0 +1,46 @@ |
||||
// Copyright 2015 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 |
||||
|
||||
import "testing" |
||||
|
||||
func TestSDKConfig(t *testing.T) { |
||||
sdkConfigPath = func() (string, error) { |
||||
return "testdata/gcloud", nil |
||||
} |
||||
|
||||
tests := []struct { |
||||
account string |
||||
accessToken string |
||||
err bool |
||||
}{ |
||||
{"", "bar_access_token", false}, |
||||
{"foo@example.com", "foo_access_token", false}, |
||||
{"bar@example.com", "bar_access_token", false}, |
||||
{"baz@serviceaccount.example.com", "", true}, |
||||
} |
||||
for _, tt := range tests { |
||||
c, err := NewSDKConfig(tt.account) |
||||
if got, want := err != nil, tt.err; got != want { |
||||
if !tt.err { |
||||
t.Errorf("expected no error, got error: %v", tt.err, err) |
||||
} else { |
||||
t.Errorf("expected error, got none") |
||||
} |
||||
continue |
||||
} |
||||
if err != nil { |
||||
continue |
||||
} |
||||
tok := c.initialToken |
||||
if tok == nil { |
||||
t.Errorf("expected token %q, got: nil", tt.accessToken) |
||||
continue |
||||
} |
||||
if tok.AccessToken != tt.accessToken { |
||||
t.Errorf("expected token %q, got: %q", tt.accessToken, tok.AccessToken) |
||||
} |
||||
} |
||||
} |
||||
@ -1,68 +0,0 @@ |
||||
// 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 |
||||
|
||||
import ( |
||||
"errors" |
||||
"sort" |
||||
"strings" |
||||
"sync" |
||||
"time" |
||||
|
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
var ( |
||||
aeTokensMu sync.Mutex // guards aeTokens and appEngineTokenSource.key
|
||||
|
||||
// aeTokens helps the fetched tokens to be reused until their expiration.
|
||||
aeTokens = make(map[string]*tokenLock) // key is '\0'-separated scopes
|
||||
) |
||||
|
||||
var errInvalidContext = errors.New("oauth2: a valid appengine.Context is required") |
||||
|
||||
type tokenLock struct { |
||||
mu sync.Mutex // guards t; held while updating t
|
||||
t *oauth2.Token |
||||
} |
||||
|
||||
type appEngineTokenSource struct { |
||||
ctx oauth2.Context |
||||
scopes []string |
||||
key string // guarded by package-level mutex, aeTokensMu
|
||||
|
||||
// fetcherFunc makes the actual RPC to fetch a new access token with an expiry time.
|
||||
// Provider of this function is responsible to assert that the given context is valid.
|
||||
fetcherFunc func(ctx oauth2.Context, scope ...string) (string, time.Time, error) |
||||
} |
||||
|
||||
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) { |
||||
aeTokensMu.Lock() |
||||
if ts.key == "" { |
||||
sort.Sort(sort.StringSlice(ts.scopes)) |
||||
ts.key = strings.Join(ts.scopes, string(0)) |
||||
} |
||||
tok, ok := aeTokens[ts.key] |
||||
if !ok { |
||||
tok = &tokenLock{} |
||||
aeTokens[ts.key] = tok |
||||
} |
||||
aeTokensMu.Unlock() |
||||
|
||||
tok.mu.Lock() |
||||
defer tok.mu.Unlock() |
||||
if tok.t != nil && !tok.t.Expired() { |
||||
return tok.t, nil |
||||
} |
||||
access, exp, err := ts.fetcherFunc(ts.ctx, ts.scopes...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
tok.t = &oauth2.Token{ |
||||
AccessToken: access, |
||||
Expiry: exp, |
||||
} |
||||
return tok.t, nil |
||||
} |
||||
@ -0,0 +1,122 @@ |
||||
{ |
||||
"data": [ |
||||
{ |
||||
"credential": { |
||||
"_class": "OAuth2Credentials", |
||||
"_module": "oauth2client.client", |
||||
"access_token": "foo_access_token", |
||||
"client_id": "foo_client_id", |
||||
"client_secret": "foo_client_secret", |
||||
"id_token": { |
||||
"at_hash": "foo_at_hash", |
||||
"aud": "foo_aud", |
||||
"azp": "foo_azp", |
||||
"cid": "foo_cid", |
||||
"email": "foo@example.com", |
||||
"email_verified": true, |
||||
"exp": 1420573614, |
||||
"iat": 1420569714, |
||||
"id": "1337", |
||||
"iss": "accounts.google.com", |
||||
"sub": "1337", |
||||
"token_hash": "foo_token_hash", |
||||
"verified_email": true |
||||
}, |
||||
"invalid": false, |
||||
"refresh_token": "foo_refresh_token", |
||||
"revoke_uri": "https://accounts.google.com/o/oauth2/revoke", |
||||
"token_expiry": "2015-01-09T00:51:51Z", |
||||
"token_response": { |
||||
"access_token": "foo_access_token", |
||||
"expires_in": 3600, |
||||
"id_token": "foo_id_token", |
||||
"token_type": "Bearer" |
||||
}, |
||||
"token_uri": "https://accounts.google.com/o/oauth2/token", |
||||
"user_agent": "Cloud SDK Command Line Tool" |
||||
}, |
||||
"key": { |
||||
"account": "foo@example.com", |
||||
"clientId": "foo_client_id", |
||||
"scope": "https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/bigquery https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/ndev.cloudman https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.admin https://www.googleapis.com/auth/prediction https://www.googleapis.com/auth/projecthosting", |
||||
"type": "google-cloud-sdk" |
||||
} |
||||
}, |
||||
{ |
||||
"credential": { |
||||
"_class": "OAuth2Credentials", |
||||
"_module": "oauth2client.client", |
||||
"access_token": "bar_access_token", |
||||
"client_id": "bar_client_id", |
||||
"client_secret": "bar_client_secret", |
||||
"id_token": { |
||||
"at_hash": "bar_at_hash", |
||||
"aud": "bar_aud", |
||||
"azp": "bar_azp", |
||||
"cid": "bar_cid", |
||||
"email": "bar@example.com", |
||||
"email_verified": true, |
||||
"exp": 1420573614, |
||||
"iat": 1420569714, |
||||
"id": "1337", |
||||
"iss": "accounts.google.com", |
||||
"sub": "1337", |
||||
"token_hash": "bar_token_hash", |
||||
"verified_email": true |
||||
}, |
||||
"invalid": false, |
||||
"refresh_token": "bar_refresh_token", |
||||
"revoke_uri": "https://accounts.google.com/o/oauth2/revoke", |
||||
"token_expiry": "2015-01-09T00:51:51Z", |
||||
"token_response": { |
||||
"access_token": "bar_access_token", |
||||
"expires_in": 3600, |
||||
"id_token": "bar_id_token", |
||||
"token_type": "Bearer" |
||||
}, |
||||
"token_uri": "https://accounts.google.com/o/oauth2/token", |
||||
"user_agent": "Cloud SDK Command Line Tool" |
||||
}, |
||||
"key": { |
||||
"account": "bar@example.com", |
||||
"clientId": "bar_client_id", |
||||
"scope": "https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/bigquery https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/ndev.cloudman https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.admin https://www.googleapis.com/auth/prediction https://www.googleapis.com/auth/projecthosting", |
||||
"type": "google-cloud-sdk" |
||||
} |
||||
}, |
||||
{ |
||||
"credential": { |
||||
"_class": "ServiceAccountCredentials", |
||||
"_kwargs": {}, |
||||
"_module": "oauth2client.client", |
||||
"_private_key_id": "00000000000000000000000000000000", |
||||
"_private_key_pkcs8_text": "-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQCt3fpiynPSaUhWSIKMGV331zudwJ6GkGmvQtwsoK2S2LbvnSwU\nNxgj4fp08kIDR5p26wF4+t/HrKydMwzftXBfZ9UmLVJgRdSswmS5SmChCrfDS5OE\nvFFcN5+6w1w8/Nu657PF/dse8T0bV95YrqyoR0Osy8WHrUOMSIIbC3hRuwIDAQAB\nAoGAJrGE/KFjn0sQ7yrZ6sXmdLawrM3mObo/2uI9T60+k7SpGbBX0/Pi6nFrJMWZ\nTVONG7P3Mu5aCPzzuVRYJB0j8aldSfzABTY3HKoWCczqw1OztJiEseXGiYz4QOyr\nYU3qDyEpdhS6q6wcoLKGH+hqRmz6pcSEsc8XzOOu7s4xW8kCQQDkc75HjhbarCnd\nJJGMe3U76+6UGmdK67ltZj6k6xoB5WbTNChY9TAyI2JC+ppYV89zv3ssj4L+02u3\nHIHFGxsHAkEAwtU1qYb1tScpchPobnYUFiVKJ7KA8EZaHVaJJODW/cghTCV7BxcJ\nbgVvlmk4lFKn3lPKAgWw7PdQsBTVBUcCrQJATPwoIirizrv3u5soJUQxZIkENAqV\nxmybZx9uetrzP7JTrVbFRf0SScMcyN90hdLJiQL8+i4+gaszgFht7sNMnwJAAbfj\nq0UXcauQwALQ7/h2oONfTg5S+MuGC/AxcXPSMZbMRGGoPh3D5YaCv27aIuS/ukQ+\n6dmm/9AGlCb64fsIWQJAPaokbjIifo+LwC5gyK73Mc4t8nAOSZDenzd/2f6TCq76\nS1dcnKiPxaED7W/y6LJiuBT2rbZiQ2L93NJpFZD/UA==\n-----END RSA PRIVATE KEY-----\n", |
||||
"_revoke_uri": "https://accounts.google.com/o/oauth2/revoke", |
||||
"_scopes": "https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/bigquery https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/ndev.cloudman https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.admin https://www.googleapis.com/auth/prediction https://www.googleapis.com/auth/projecthosting", |
||||
"_service_account_email": "baz@serviceaccount.example.com", |
||||
"_service_account_id": "baz.serviceaccount.example.com", |
||||
"_token_uri": "https://accounts.google.com/o/oauth2/token", |
||||
"_user_agent": "Cloud SDK Command Line Tool", |
||||
"access_token": null, |
||||
"assertion_type": null, |
||||
"client_id": null, |
||||
"client_secret": null, |
||||
"id_token": null, |
||||
"invalid": false, |
||||
"refresh_token": null, |
||||
"revoke_uri": "https://accounts.google.com/o/oauth2/revoke", |
||||
"service_account_name": "baz@serviceaccount.example.com", |
||||
"token_expiry": null, |
||||
"token_response": null, |
||||
"user_agent": "Cloud SDK Command Line Tool" |
||||
}, |
||||
"key": { |
||||
"account": "baz@serviceaccount.example.com", |
||||
"clientId": "baz_client_id", |
||||
"scope": "https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/bigquery https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/ndev.cloudman https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.admin https://www.googleapis.com/auth/prediction https://www.googleapis.com/auth/projecthosting", |
||||
"type": "google-cloud-sdk" |
||||
} |
||||
} |
||||
], |
||||
"file_version": 1 |
||||
} |
||||
@ -0,0 +1,2 @@ |
||||
[core] |
||||
account = bar@example.com |
||||
@ -0,0 +1,62 @@ |
||||
// 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 internal contains support packages for oauth2 package.
|
||||
package internal |
||||
|
||||
import ( |
||||
"reflect" |
||||
"strings" |
||||
"testing" |
||||
) |
||||
|
||||
func TestParseINI(t *testing.T) { |
||||
tests := []struct { |
||||
ini string |
||||
want map[string]map[string]string |
||||
}{ |
||||
{ |
||||
`root = toor |
||||
[foo]
|
||||
bar = hop |
||||
ini = nin |
||||
`, |
||||
map[string]map[string]string{ |
||||
"": map[string]string{"root": "toor"}, |
||||
"foo": map[string]string{"bar": "hop", "ini": "nin"}, |
||||
}, |
||||
}, |
||||
{ |
||||
`[empty] |
||||
[section] |
||||
empty= |
||||
`, |
||||
map[string]map[string]string{ |
||||
"": map[string]string{}, |
||||
"empty": map[string]string{}, |
||||
"section": map[string]string{"empty": ""}, |
||||
}, |
||||
}, |
||||
{ |
||||
`ignore |
||||
[invalid |
||||
=stuff |
||||
;comment=true |
||||
`, |
||||
map[string]map[string]string{ |
||||
"": map[string]string{}, |
||||
}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
result, err := ParseINI(strings.NewReader(tt.ini)) |
||||
if err != nil { |
||||
t.Errorf("ParseINI(%q) error %v, want: no error", tt.ini, err) |
||||
continue |
||||
} |
||||
if !reflect.DeepEqual(result, tt.want) { |
||||
t.Errorf("ParseINI(%q) = %#v, want: %#v", tt.ini, result, tt.want) |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,31 @@ |
||||
// 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 jwt_test |
||||
|
||||
import ( |
||||
"golang.org/x/oauth2" |
||||
"golang.org/x/oauth2/jwt" |
||||
) |
||||
|
||||
func ExampleJWTConfig() { |
||||
conf := &jwt.Config{ |
||||
Email: "xxx@developer.com", |
||||
// The contents of your RSA private key or your PEM file
|
||||
// that contains a private key.
|
||||
// If you have a p12 file instead, you
|
||||
// can use `openssl` to export the private key into a pem file.
|
||||
//
|
||||
// $ openssl pkcs12 -in key.p12 -out key.pem -nodes
|
||||
//
|
||||
// It only supports PEM containers with no passphrase.
|
||||
PrivateKey: []byte("-----BEGIN RSA PRIVATE KEY-----..."), |
||||
Subject: "user@example.com", |
||||
TokenURL: "https://provider.com/o/oauth2/token", |
||||
} |
||||
// Initiate an http.Client, the following GET request will be
|
||||
// authorized and authenticated on the behalf of user@example.com.
|
||||
client := conf.Client(oauth2.NoContext) |
||||
client.Get("...") |
||||
} |
||||
@ -0,0 +1,16 @@ |
||||
// Copyright 2015 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 linkedin provides constants for using OAuth2 to access LinkedIn.
|
||||
package linkedin // import "golang.org/x/oauth2/linkedin"
|
||||
|
||||
import ( |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
// Endpoint is LinkedIn's OAuth 2.0 endpoint.
|
||||
var Endpoint = oauth2.Endpoint{ |
||||
AuthURL: "https://www.linkedin.com/uas/oauth2/authorization", |
||||
TokenURL: "https://www.linkedin.com/uas/oauth2/accessToken", |
||||
} |
||||
@ -0,0 +1,16 @@ |
||||
// Copyright 2015 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 odnoklassniki provides constants for using OAuth2 to access Odnoklassniki.
|
||||
package odnoklassniki // import "golang.org/x/oauth2/odnoklassniki"
|
||||
|
||||
import ( |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
// Endpoint is Odnoklassniki's OAuth 2.0 endpoint.
|
||||
var Endpoint = oauth2.Endpoint{ |
||||
AuthURL: "https://www.odnoklassniki.ru/oauth/authorize", |
||||
TokenURL: "https://api.odnoklassniki.ru/oauth/token.do", |
||||
} |
||||
@ -0,0 +1,22 @@ |
||||
// Copyright 2015 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 paypal provides constants for using OAuth2 to access PayPal.
|
||||
package paypal // import "golang.org/x/oauth2/paypal"
|
||||
|
||||
import ( |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
// Endpoint is PayPal's OAuth 2.0 endpoint in live (production) environment.
|
||||
var Endpoint = oauth2.Endpoint{ |
||||
AuthURL: "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize", |
||||
TokenURL: "https://api.paypal.com/v1/identity/openidconnect/tokenservice", |
||||
} |
||||
|
||||
// SandboxEndpoint is PayPal's OAuth 2.0 endpoint in sandbox (testing) environment.
|
||||
var SandboxEndpoint = oauth2.Endpoint{ |
||||
AuthURL: "https://www.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize", |
||||
TokenURL: "https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice", |
||||
} |
||||
@ -0,0 +1,50 @@ |
||||
// 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 oauth2 |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
) |
||||
|
||||
func TestTokenExtra(t *testing.T) { |
||||
type testCase struct { |
||||
key string |
||||
val interface{} |
||||
want interface{} |
||||
} |
||||
const key = "extra-key" |
||||
cases := []testCase{ |
||||
{key: key, val: "abc", want: "abc"}, |
||||
{key: key, val: 123, want: 123}, |
||||
{key: key, val: "", want: ""}, |
||||
{key: "other-key", val: "def", want: nil}, |
||||
} |
||||
for _, tc := range cases { |
||||
extra := make(map[string]interface{}) |
||||
extra[tc.key] = tc.val |
||||
tok := &Token{raw: extra} |
||||
if got, want := tok.Extra(key), tc.want; got != want { |
||||
t.Errorf("Extra(%q) = %q; want %q", key, got, want) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestTokenExpiry(t *testing.T) { |
||||
now := time.Now() |
||||
cases := []struct { |
||||
name string |
||||
tok *Token |
||||
want bool |
||||
}{ |
||||
{name: "12 seconds", tok: &Token{Expiry: now.Add(12 * time.Second)}, want: false}, |
||||
{name: "10 seconds", tok: &Token{Expiry: now.Add(expiryDelta)}, want: true}, |
||||
} |
||||
for _, tc := range cases { |
||||
if got, want := tc.tok.expired(), tc.want; got != want { |
||||
t.Errorf("expired (%q) = %v; want %v", tc.name, got, want) |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,16 @@ |
||||
// Copyright 2015 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 vk provides constants for using OAuth2 to access VK.com.
|
||||
package vk // import "golang.org/x/oauth2/vk"
|
||||
|
||||
import ( |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
// Endpoint is VK's OAuth 2.0 endpoint.
|
||||
var Endpoint = oauth2.Endpoint{ |
||||
AuthURL: "https://oauth.vk.com/authorize", |
||||
TokenURL: "https://oauth.vk.com/access_token", |
||||
} |
||||
Loading…
Reference in new issue