mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Updated golang/x/oauth2 dependency, #1710
This commit is contained in:
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ImportPath": "github.com/grafana/grafana",
|
||||
"GoVersion": "go1.4.2",
|
||||
"GoVersion": "go1.3",
|
||||
"Packages": [
|
||||
"./pkg/..."
|
||||
],
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/oauth2",
|
||||
"Rev": "e5909d4679a1926c774c712b343f10b8298687a3"
|
||||
"Rev": "c58fcf0ffc1c772aa2e1ee4894bc19f2649263b2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/bufio.v1",
|
||||
|
||||
4
Godeps/_workspace/src/golang.org/x/oauth2/.travis.yml
generated
vendored
4
Godeps/_workspace/src/golang.org/x/oauth2/.travis.yml
generated
vendored
@@ -8,7 +8,7 @@ install:
|
||||
- export GOPATH="$HOME/gopath"
|
||||
- mkdir -p "$GOPATH/src/golang.org/x"
|
||||
- mv "$TRAVIS_BUILD_DIR" "$GOPATH/src/golang.org/x/oauth2"
|
||||
- go get -v -t -d -tags='appengine appenginevm' golang.org/x/oauth2/...
|
||||
- go get -v -t -d golang.org/x/oauth2/...
|
||||
|
||||
script:
|
||||
- go test -v -tags='appengine appenginevm' golang.org/x/oauth2/...
|
||||
- go test -v golang.org/x/oauth2/...
|
||||
|
||||
44
Godeps/_workspace/src/golang.org/x/oauth2/CONTRIBUTING.md
generated
vendored
44
Godeps/_workspace/src/golang.org/x/oauth2/CONTRIBUTING.md
generated
vendored
@@ -1,25 +1,31 @@
|
||||
# Contributing
|
||||
# Contributing to Go
|
||||
|
||||
We don't use GitHub pull requests but use Gerrit for code reviews,
|
||||
similar to the Go project.
|
||||
Go is an open source project.
|
||||
|
||||
1. Sign one of the contributor license agreements below.
|
||||
2. `go get golang.org/x/review/git-codereview` to install the code reviewing tool.
|
||||
3. Get the package by running `go get -d golang.org/x/oauth2`.
|
||||
Make changes and create a change by running `git codereview change <name>`, provide a command message, and use `git codereview mail` to create a Gerrit CL.
|
||||
Keep amending to the change and mail as your recieve feedback.
|
||||
It is the work of hundreds of contributors. We appreciate your help!
|
||||
|
||||
For more information about the workflow, see Go's [Contribution Guidelines](https://golang.org/doc/contribute.html).
|
||||
|
||||
Before we can accept any pull requests
|
||||
we have to jump through a couple of legal hurdles,
|
||||
primarily a Contributor License Agreement (CLA):
|
||||
## Filing issues
|
||||
|
||||
- **If you are an individual writing original source code**
|
||||
and you're sure you own the intellectual property,
|
||||
then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html).
|
||||
- **If you work for a company that wants to allow you to contribute your work**,
|
||||
then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html).
|
||||
When [filing an issue](https://github.com/golang/oauth2/issues), make sure to answer these five questions:
|
||||
|
||||
1. What version of Go are you using (`go version`)?
|
||||
2. What operating system and processor architecture are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
|
||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||
|
||||
## Contributing code
|
||||
|
||||
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
|
||||
before sending patches.
|
||||
|
||||
**We do not accept GitHub pull requests**
|
||||
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed under
|
||||
the BSD-style license found in the LICENSE file.
|
||||
|
||||
You can sign these electronically (just scroll to the bottom).
|
||||
After that, we'll be able to accept your pull requests.
|
||||
|
||||
46
Godeps/_workspace/src/golang.org/x/oauth2/README.md
generated
vendored
46
Godeps/_workspace/src/golang.org/x/oauth2/README.md
generated
vendored
@@ -16,3 +16,49 @@ See godoc for further documentation and examples.
|
||||
* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google)
|
||||
|
||||
|
||||
## App Engine
|
||||
|
||||
In change 96e89be (March 2015) we removed the `oauth2.Context2` type in favor
|
||||
of the [`context.Context`](https://golang.org/x/net/context#Context) type from
|
||||
the `golang.org/x/net/context` package
|
||||
|
||||
This means its no longer possible to use the "Classic App Engine"
|
||||
`appengine.Context` type with the `oauth2` package. (You're using
|
||||
Classic App Engine if you import the package `"appengine"`.)
|
||||
|
||||
To work around this, you may use the new `"google.golang.org/appengine"`
|
||||
package. This package has almost the same API as the `"appengine"` package,
|
||||
but it can be fetched with `go get` and used on "Managed VMs" and well as
|
||||
Classic App Engine.
|
||||
|
||||
See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app)
|
||||
for information on updating your app.
|
||||
|
||||
If you don't want to update your entire app to use the new App Engine packages,
|
||||
you may use both sets of packages in parallel, using only the new packages
|
||||
with the `oauth2` package.
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
newappengine "google.golang.org/appengine"
|
||||
newurlftech "google.golang.org/urlfetch"
|
||||
|
||||
"appengine"
|
||||
)
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
var c appengine.Context = appengine.NewContext(r)
|
||||
c.Infof("Logging a message with the old package")
|
||||
|
||||
var ctx context.Context = newappengine.NewContext(r)
|
||||
client := &http.Client{
|
||||
Transport: &oauth2.Transport{
|
||||
Source: google.AppEngineTokenSource(ctx, "scope"),
|
||||
Base: &newurlfetch.Transport{Context: ctx},
|
||||
},
|
||||
}
|
||||
client.Get("...")
|
||||
}
|
||||
|
||||
|
||||
25
Godeps/_workspace/src/golang.org/x/oauth2/client_appengine.go
generated
vendored
25
Godeps/_workspace/src/golang.org/x/oauth2/client_appengine.go
generated
vendored
@@ -2,38 +2,23 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine,!appenginevm
|
||||
// +build appengine appenginevm
|
||||
|
||||
// App Engine hooks.
|
||||
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"appengine"
|
||||
"appengine/urlfetch"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/appengine/urlfetch"
|
||||
)
|
||||
|
||||
var warnOnce sync.Once
|
||||
|
||||
func init() {
|
||||
registerContextClientFunc(contextClientAppEngine)
|
||||
}
|
||||
|
||||
func contextClientAppEngine(ctx Context) (*http.Client, error) {
|
||||
if actx, ok := ctx.(appengine.Context); ok {
|
||||
return urlfetch.Client(actx), nil
|
||||
}
|
||||
// The user did it wrong. We'll log once (and hope they see it
|
||||
// in dev_appserver), but stil return (nil, nil) in case some
|
||||
// other contextClientFunc hook finds a way to proceed.
|
||||
warnOnce.Do(gaeDoingItWrongHelp)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func gaeDoingItWrongHelp() {
|
||||
log.Printf("WARNING: you attempted to use the oauth2 package without passing a valid appengine.Context or *http.Request as the oauth2.Context. App Engine requires that all service RPCs (including urlfetch) be associated with an *http.Request/appengine.Context.")
|
||||
func contextClientAppEngine(ctx context.Context) (*http.Client, error) {
|
||||
return urlfetch.Client(ctx), nil
|
||||
}
|
||||
|
||||
27
Godeps/_workspace/src/golang.org/x/oauth2/example_test.go
generated
vendored
27
Godeps/_workspace/src/golang.org/x/oauth2/example_test.go
generated
vendored
@@ -7,15 +7,10 @@ package oauth2_test
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// TODO(jbd): Remove after Go 1.4.
|
||||
// Related to https://codereview.appspot.com/107320046
|
||||
func TestA(t *testing.T) {}
|
||||
|
||||
func ExampleConfig() {
|
||||
conf := &oauth2.Config{
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
@@ -48,25 +43,3 @@ func ExampleConfig() {
|
||||
client := conf.Client(oauth2.NoContext, tok)
|
||||
client.Get("...")
|
||||
}
|
||||
|
||||
func ExampleJWTConfig() {
|
||||
var initialToken *oauth2.Token // nil means no initial token
|
||||
conf := &oauth2.JWTConfig{
|
||||
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, initialToken)
|
||||
client.Get("...")
|
||||
}
|
||||
|
||||
16
Godeps/_workspace/src/golang.org/x/oauth2/facebook/facebook.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/oauth2/facebook/facebook.go
generated
vendored
Normal file
@@ -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",
|
||||
}
|
||||
2
Godeps/_workspace/src/golang.org/x/oauth2/github/github.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/oauth2/github/github.go
generated
vendored
@@ -3,7 +3,7 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package github provides constants for using OAuth2 to access Github.
|
||||
package github
|
||||
package github // import "golang.org/x/oauth2/github"
|
||||
|
||||
import (
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
76
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine.go
generated
vendored
76
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine.go
generated
vendored
@@ -2,36 +2,82 @@
|
||||
// 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"appengine"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
|
||||
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
|
||||
|
||||
// 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 {
|
||||
// The provided context must have come from appengine.NewContext.
|
||||
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
|
||||
if appengineTokenFunc == nil {
|
||||
panic("google: AppEngineTokenSource can only be used on App Engine.")
|
||||
}
|
||||
scopes := append([]string{}, scope...)
|
||||
sort.Strings(scopes)
|
||||
return &appEngineTokenSource{
|
||||
ctx: ctx,
|
||||
scopes: scope,
|
||||
fetcherFunc: aeFetcherFunc,
|
||||
ctx: ctx,
|
||||
scopes: scopes,
|
||||
key: strings.Join(scopes, " "),
|
||||
}
|
||||
}
|
||||
|
||||
var aeFetcherFunc = 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...)
|
||||
// aeTokens helps the fetched tokens to be reused until their expiration.
|
||||
var (
|
||||
aeTokensMu sync.Mutex
|
||||
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
|
||||
)
|
||||
|
||||
type tokenLock struct {
|
||||
mu sync.Mutex // guards t; held while fetching or updating t
|
||||
t *oauth2.Token
|
||||
}
|
||||
|
||||
type appEngineTokenSource struct {
|
||||
ctx context.Context
|
||||
scopes []string
|
||||
key string // to aeTokens map; space-separated scopes
|
||||
}
|
||||
|
||||
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) {
|
||||
if appengineTokenFunc == nil {
|
||||
panic("google: AppEngineTokenSource can only be used on App Engine.")
|
||||
}
|
||||
|
||||
aeTokensMu.Lock()
|
||||
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.Valid() {
|
||||
return tok.t, nil
|
||||
}
|
||||
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tok.t = &oauth2.Token{
|
||||
AccessToken: access,
|
||||
Expiry: exp,
|
||||
}
|
||||
return tok.t, nil
|
||||
}
|
||||
|
||||
13
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
Normal file
13
Godeps/_workspace/src/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
36
Godeps/_workspace/src/golang.org/x/oauth2/google/appenginevm.go
generated
vendored
36
Godeps/_workspace/src/golang.org/x/oauth2/google/appenginevm.go
generated
vendored
@@ -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...)
|
||||
}
|
||||
154
Godeps/_workspace/src/golang.org/x/oauth2/google/default.go
generated
vendored
Normal file
154
Godeps/_workspace/src/golang.org/x/oauth2/google/default.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
34
Godeps/_workspace/src/golang.org/x/oauth2/google/example_test.go
generated
vendored
34
Godeps/_workspace/src/golang.org/x/oauth2/google/example_test.go
generated
vendored
@@ -11,17 +11,22 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/urlfetch"
|
||||
)
|
||||
|
||||
// Remove after Go 1.4.
|
||||
// Related to https://codereview.appspot.com/107320046
|
||||
func TestA(t *testing.T) {}
|
||||
func ExampleDefaultClient() {
|
||||
client, err := google.DefaultClient(oauth2.NoContext,
|
||||
"https://www.googleapis.com/auth/devstorage.full_control")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
client.Get("...")
|
||||
}
|
||||
|
||||
func Example_webServer() {
|
||||
// Your credentials should be obtained from the Google
|
||||
@@ -62,21 +67,34 @@ func ExampleJWTConfigFromJSON() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
conf, err := google.JWTConfigFromJSON(oauth2.NoContext, data, "https://www.googleapis.com/auth/bigquery")
|
||||
conf, err := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/bigquery")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Initiate an http.Client. The following GET request will be
|
||||
// authorized and authenticated on the behalf of
|
||||
// your service account.
|
||||
client := conf.Client(oauth2.NoContext, nil)
|
||||
client := conf.Client(oauth2.NoContext)
|
||||
client.Get("...")
|
||||
}
|
||||
|
||||
func ExampleSDKConfig() {
|
||||
// The credentials will be obtained from the first account that
|
||||
// has been authorized with `gcloud auth login`.
|
||||
conf, err := google.NewSDKConfig("")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Initiate an http.Client. The following GET request will be
|
||||
// authorized and authenticated on the behalf of the SDK user.
|
||||
client := conf.Client(oauth2.NoContext)
|
||||
client.Get("...")
|
||||
}
|
||||
|
||||
func Example_serviceAccount() {
|
||||
// Your credentials should be obtained from the Google
|
||||
// Developer Console (https://console.developers.google.com).
|
||||
conf := &oauth2.JWTConfig{
|
||||
conf := &jwt.Config{
|
||||
Email: "xxx@developer.gserviceaccount.com",
|
||||
// The contents of your RSA private key or your PEM file
|
||||
// that contains a private key.
|
||||
@@ -101,7 +119,7 @@ func Example_serviceAccount() {
|
||||
}
|
||||
// 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, nil)
|
||||
client := conf.Client(oauth2.NoContext)
|
||||
client.Get("...")
|
||||
}
|
||||
|
||||
|
||||
124
Godeps/_workspace/src/golang.org/x/oauth2/google/google.go
generated
vendored
124
Godeps/_workspace/src/golang.org/x/oauth2/google/google.go
generated
vendored
@@ -2,26 +2,28 @@
|
||||
// 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:
|
||||
// Package google provides support for making OAuth2 authorized and
|
||||
// authenticated HTTP requests to Google APIs.
|
||||
// It supports the Web server flow, client-side credentials, service accounts,
|
||||
// Google Compute Engine service accounts, and Google App Engine service
|
||||
// accounts.
|
||||
//
|
||||
// For more information, please read
|
||||
// https://developers.google.com/accounts/docs/OAuth2.
|
||||
package google
|
||||
// https://developers.google.com/accounts/docs/OAuth2
|
||||
// and
|
||||
// https://developers.google.com/accounts/application-default-credentials.
|
||||
package google // import "golang.org/x/oauth2/google"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/cloud/compute/metadata"
|
||||
)
|
||||
|
||||
// Endpoint is Google's OAuth 2.0 endpoint.
|
||||
@@ -33,11 +35,55 @@ var Endpoint = oauth2.Endpoint{
|
||||
// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
|
||||
const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
|
||||
|
||||
// ConfigFromJSON uses a Google Developers Console client_credentials.json
|
||||
// file to construct a config.
|
||||
// client_credentials.json can be downloadable from https://console.developers.google.com,
|
||||
// under "APIs & Auth" > "Credentials". Download the Web application credentials in the
|
||||
// JSON format and provide the contents of the file as jsonKey.
|
||||
func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
|
||||
type cred struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
RedirectURIs []string `json:"redirect_uris"`
|
||||
AuthURI string `json:"auth_uri"`
|
||||
TokenURI string `json:"token_uri"`
|
||||
}
|
||||
var j struct {
|
||||
Web *cred `json:"web"`
|
||||
Installed *cred `json:"installed"`
|
||||
}
|
||||
if err := json.Unmarshal(jsonKey, &j); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var c *cred
|
||||
switch {
|
||||
case j.Web != nil:
|
||||
c = j.Web
|
||||
case j.Installed != nil:
|
||||
c = j.Installed
|
||||
default:
|
||||
return nil, fmt.Errorf("oauth2/google: no credentials found")
|
||||
}
|
||||
if len(c.RedirectURIs) < 1 {
|
||||
return nil, errors.New("oauth2/google: missing redirect URL in the client_credentials.json")
|
||||
}
|
||||
return &oauth2.Config{
|
||||
ClientID: c.ClientID,
|
||||
ClientSecret: c.ClientSecret,
|
||||
RedirectURL: c.RedirectURIs[0],
|
||||
Scopes: scope,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: c.AuthURI,
|
||||
TokenURL: c.TokenURI,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
|
||||
var key struct {
|
||||
Email string `json:"client_email"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
@@ -45,7 +91,7 @@ func JWTConfigFromJSON(ctx oauth2.Context, jsonKey []byte, scope ...string) (*oa
|
||||
if err := json.Unmarshal(jsonKey, &key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oauth2.JWTConfig{
|
||||
return &jwt.Config{
|
||||
Email: key.Email,
|
||||
PrivateKey: []byte(key.PrivateKey),
|
||||
Scopes: scope,
|
||||
@@ -53,12 +99,6 @@ func JWTConfigFromJSON(ctx oauth2.Context, jsonKey []byte, scope ...string) (*oa
|
||||
}, nil
|
||||
}
|
||||
|
||||
type metaTokenRespBody struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn time.Duration `json:"expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -66,50 +106,40 @@ type metaTokenRespBody struct {
|
||||
// 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}
|
||||
return oauth2.ReuseTokenSource(nil, computeSource{account: account})
|
||||
}
|
||||
|
||||
type computeSource struct {
|
||||
account string
|
||||
}
|
||||
|
||||
var metaClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 750 * time.Millisecond,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
ResponseHeaderTimeout: 750 * time.Millisecond,
|
||||
},
|
||||
}
|
||||
|
||||
func (cs *computeSource) Token() (*oauth2.Token, error) {
|
||||
func (cs computeSource) Token() (*oauth2.Token, error) {
|
||||
if !metadata.OnGCE() {
|
||||
return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE")
|
||||
}
|
||||
acct := cs.account
|
||||
if acct == "" {
|
||||
acct = "default"
|
||||
}
|
||||
u := "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" + acct + "/token"
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token")
|
||||
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
|
||||
var res struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresInSec int `json:"expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
}
|
||||
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)
|
||||
err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err)
|
||||
}
|
||||
if res.ExpiresInSec == 0 || res.AccessToken == "" {
|
||||
return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
|
||||
}
|
||||
return &oauth2.Token{
|
||||
AccessToken: tokenResp.AccessToken,
|
||||
TokenType: tokenResp.TokenType,
|
||||
Expiry: time.Now().Add(tokenResp.ExpiresIn * time.Second),
|
||||
AccessToken: res.AccessToken,
|
||||
TokenType: res.TokenType,
|
||||
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
|
||||
}, nil
|
||||
}
|
||||
|
||||
67
Godeps/_workspace/src/golang.org/x/oauth2/google/google_test.go
generated
vendored
Normal file
67
Godeps/_workspace/src/golang.org/x/oauth2/google/google_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
168
Godeps/_workspace/src/golang.org/x/oauth2/google/sdk.go
generated
vendored
Normal file
168
Godeps/_workspace/src/golang.org/x/oauth2/google/sdk.go
generated
vendored
Normal file
@@ -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")
|
||||
}
|
||||
46
Godeps/_workspace/src/golang.org/x/oauth2/google/sdk_test.go
generated
vendored
Normal file
46
Godeps/_workspace/src/golang.org/x/oauth2/google/sdk_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Godeps/_workspace/src/golang.org/x/oauth2/google/source_appengine.go
generated
vendored
68
Godeps/_workspace/src/golang.org/x/oauth2/google/source_appengine.go
generated
vendored
@@ -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
|
||||
}
|
||||
122
Godeps/_workspace/src/golang.org/x/oauth2/google/testdata/gcloud/credentials
generated
vendored
Normal file
122
Godeps/_workspace/src/golang.org/x/oauth2/google/testdata/gcloud/credentials
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
2
Godeps/_workspace/src/golang.org/x/oauth2/google/testdata/gcloud/properties
generated
vendored
Normal file
2
Godeps/_workspace/src/golang.org/x/oauth2/google/testdata/gcloud/properties
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[core]
|
||||
account = bar@example.com
|
||||
36
Godeps/_workspace/src/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
36
Godeps/_workspace/src/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
@@ -6,10 +6,14 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseKey converts the binary contents of a private key file
|
||||
@@ -26,12 +30,40 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
||||
if err != nil {
|
||||
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err)
|
||||
}
|
||||
}
|
||||
parsed, ok := parsedKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("oauth2: private key is invalid")
|
||||
return nil, errors.New("private key is invalid")
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
|
||||
result := map[string]map[string]string{
|
||||
"": map[string]string{}, // root section
|
||||
}
|
||||
scanner := bufio.NewScanner(ini)
|
||||
currentSection := ""
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if strings.HasPrefix(line, ";") {
|
||||
// comment.
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
||||
currentSection = strings.TrimSpace(line[1 : len(line)-1])
|
||||
result[currentSection] = map[string]string{}
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) == 2 && parts[0] != "" {
|
||||
result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error scanning ini: %v", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
62
Godeps/_workspace/src/golang.org/x/oauth2/internal/oauth2_test.go
generated
vendored
Normal file
62
Godeps/_workspace/src/golang.org/x/oauth2/internal/oauth2_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Godeps/_workspace/src/golang.org/x/oauth2/jws/jws.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/oauth2/jws/jws.go
generated
vendored
@@ -4,7 +4,7 @@
|
||||
|
||||
// Package jws provides encoding and decoding utilities for
|
||||
// signed JWS messages.
|
||||
package jws
|
||||
package jws // import "golang.org/x/oauth2/jws"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
31
Godeps/_workspace/src/golang.org/x/oauth2/jwt/example_test.go
generated
vendored
Normal file
31
Godeps/_workspace/src/golang.org/x/oauth2/jwt/example_test.go
generated
vendored
Normal file
@@ -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("...")
|
||||
}
|
||||
@@ -2,7 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package oauth2
|
||||
// Package jwt implements the OAuth 2.0 JSON Web Token flow, commonly
|
||||
// known as "two-legged OAuth 2.0".
|
||||
//
|
||||
// See: https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -14,6 +18,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/internal"
|
||||
"golang.org/x/oauth2/jws"
|
||||
)
|
||||
@@ -23,9 +29,9 @@ var (
|
||||
defaultHeader = &jws.Header{Algorithm: "RS256", Typ: "JWT"}
|
||||
)
|
||||
|
||||
// JWTConfig is the configuration for using JWT to fetch tokens,
|
||||
// commonly known as "two-legged OAuth".
|
||||
type JWTConfig struct {
|
||||
// Config is the configuration for using JWT to fetch tokens,
|
||||
// commonly known as "two-legged OAuth 2.0".
|
||||
type Config struct {
|
||||
// Email is the OAuth client identifier used when communicating with
|
||||
// the configured OAuth provider.
|
||||
Email string
|
||||
@@ -52,47 +58,32 @@ type JWTConfig struct {
|
||||
|
||||
// TokenSource returns a JWT TokenSource using the configuration
|
||||
// in c and the HTTP client from the provided context.
|
||||
//
|
||||
// The returned TokenSource only does JWT requests when necessary but
|
||||
// otherwise returns the same token repeatedly until it expires.
|
||||
//
|
||||
// The provided initialToken may be nil, in which case the first
|
||||
// call to TokenSource will do a new JWT request.
|
||||
func (c *JWTConfig) TokenSource(ctx Context, initialToken *Token) TokenSource {
|
||||
return &newWhenNeededSource{
|
||||
t: initialToken,
|
||||
new: jwtSource{ctx, c},
|
||||
}
|
||||
func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
|
||||
return oauth2.ReuseTokenSource(nil, jwtSource{ctx, c})
|
||||
}
|
||||
|
||||
// Client returns an HTTP client wrapping the context's
|
||||
// HTTP transport and adding Authorization headers with tokens
|
||||
// obtained from c.
|
||||
//
|
||||
// The provided initialToken may be nil, in which case the first
|
||||
// call to TokenSource will do a new JWT request.
|
||||
//
|
||||
// The returned client and its Transport should not be modified.
|
||||
func (c *JWTConfig) Client(ctx Context, initialToken *Token) *http.Client {
|
||||
return NewClient(ctx, c.TokenSource(ctx, initialToken))
|
||||
func (c *Config) Client(ctx context.Context) *http.Client {
|
||||
return oauth2.NewClient(ctx, c.TokenSource(ctx))
|
||||
}
|
||||
|
||||
// jwtSource is a source that always does a signed JWT request for a token.
|
||||
// It should typically be wrapped with a newWhenNeededSource.
|
||||
// It should typically be wrapped with a reuseTokenSource.
|
||||
type jwtSource struct {
|
||||
ctx Context
|
||||
conf *JWTConfig
|
||||
ctx context.Context
|
||||
conf *Config
|
||||
}
|
||||
|
||||
func (js jwtSource) Token() (*Token, error) {
|
||||
func (js jwtSource) Token() (*oauth2.Token, error) {
|
||||
pk, err := internal.ParseKey(js.conf.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hc, err := contextClient(js.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hc := oauth2.NewClient(js.ctx, nil)
|
||||
claimSet := &jws.ClaimSet{
|
||||
Iss: js.conf.Email,
|
||||
Scope: strings.Join(js.conf.Scopes, " "),
|
||||
@@ -133,12 +124,13 @@ func (js jwtSource) Token() (*Token, error) {
|
||||
if err := json.Unmarshal(body, &tokenRes); err != nil {
|
||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||
}
|
||||
token := &Token{
|
||||
token := &oauth2.Token{
|
||||
AccessToken: tokenRes.AccessToken,
|
||||
TokenType: tokenRes.TokenType,
|
||||
raw: make(map[string]interface{}),
|
||||
}
|
||||
json.Unmarshal(body, &token.raw) // no error checks for optional fields
|
||||
raw := make(map[string]interface{})
|
||||
json.Unmarshal(body, &raw) // no error checks for optional fields
|
||||
token = token.WithExtra(raw)
|
||||
|
||||
if secs := tokenRes.ExpiresIn; secs > 0 {
|
||||
token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
|
||||
@@ -2,12 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package oauth2
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var dummyPrivateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
@@ -50,17 +52,17 @@ func TestJWTFetch_JSONResponse(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
conf := &JWTConfig{
|
||||
conf := &Config{
|
||||
Email: "aaa@xxx.com",
|
||||
PrivateKey: dummyPrivateKey,
|
||||
TokenURL: ts.URL,
|
||||
}
|
||||
tok, err := conf.TokenSource(NoContext, nil).Token()
|
||||
tok, err := conf.TokenSource(oauth2.NoContext).Token()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tok.Expired() {
|
||||
t.Errorf("Token shouldn't be expired")
|
||||
if !tok.Valid() {
|
||||
t.Errorf("Token invalid")
|
||||
}
|
||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
||||
t.Errorf("Unexpected access token, %#v", tok.AccessToken)
|
||||
@@ -84,24 +86,30 @@ func TestJWTFetch_BadResponse(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
conf := &JWTConfig{
|
||||
conf := &Config{
|
||||
Email: "aaa@xxx.com",
|
||||
PrivateKey: dummyPrivateKey,
|
||||
TokenURL: ts.URL,
|
||||
}
|
||||
tok, err := conf.TokenSource(NoContext, nil).Token()
|
||||
tok, err := conf.TokenSource(oauth2.NoContext).Token()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tok.AccessToken != "" {
|
||||
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||
if tok == nil {
|
||||
t.Fatalf("token is nil")
|
||||
}
|
||||
if tok.TokenType != "bearer" {
|
||||
t.Errorf("Unexpected token type, %#v.", tok.TokenType)
|
||||
if tok.Valid() {
|
||||
t.Errorf("token is valid. want invalid.")
|
||||
}
|
||||
if tok.AccessToken != "" {
|
||||
t.Errorf("Unexpected non-empty access token %q.", tok.AccessToken)
|
||||
}
|
||||
if want := "bearer"; tok.TokenType != want {
|
||||
t.Errorf("TokenType = %q; want %q", tok.TokenType, want)
|
||||
}
|
||||
scope := tok.Extra("scope")
|
||||
if scope != "user" {
|
||||
t.Errorf("Unexpected value for scope: %v", scope)
|
||||
if want := "user"; scope != want {
|
||||
t.Errorf("token scope = %q; want %q", scope, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,12 +119,12 @@ func TestJWTFetch_BadResponseType(t *testing.T) {
|
||||
w.Write([]byte(`{"access_token":123, "scope": "user", "token_type": "bearer"}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
conf := &JWTConfig{
|
||||
conf := &Config{
|
||||
Email: "aaa@xxx.com",
|
||||
PrivateKey: dummyPrivateKey,
|
||||
TokenURL: ts.URL,
|
||||
}
|
||||
tok, err := conf.TokenSource(NoContext, nil).Token()
|
||||
tok, err := conf.TokenSource(oauth2.NoContext).Token()
|
||||
if err == nil {
|
||||
t.Error("got a token; expected error")
|
||||
if tok.AccessToken != "" {
|
||||
16
Godeps/_workspace/src/golang.org/x/oauth2/linkedin/linkedin.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/oauth2/linkedin/linkedin.go
generated
vendored
Normal file
@@ -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",
|
||||
}
|
||||
262
Godeps/_workspace/src/golang.org/x/oauth2/oauth2.go
generated
vendored
262
Godeps/_workspace/src/golang.org/x/oauth2/oauth2.go
generated
vendored
@@ -5,7 +5,7 @@
|
||||
// Package oauth2 provides support for making
|
||||
// OAuth2 authorized and authenticated HTTP requests.
|
||||
// It can additionally grant authorization with Bearer JWT.
|
||||
package oauth2
|
||||
package oauth2 // import "golang.org/x/oauth2"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -25,18 +25,12 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Context can be an golang.org/x/net.Context, or an App Engine Context.
|
||||
// In the future these will be unified.
|
||||
// If you don't care and aren't running on App Engine, you may use NoContext.
|
||||
type Context interface{}
|
||||
|
||||
// NoContext is the default context. If you're not running this code
|
||||
// on App Engine or not using golang.org/x/net.Context to provide a custom
|
||||
// HTTP client, you should use NoContext.
|
||||
var NoContext Context = nil
|
||||
// NoContext is the default context you should supply if not using
|
||||
// your own context.Context (see https://golang.org/x/net/context).
|
||||
var NoContext = context.TODO()
|
||||
|
||||
// Config describes a typical 3-legged OAuth2 flow, with both the
|
||||
// client application information and the server's URLs.
|
||||
// client application information and the server's endpoint URLs.
|
||||
type Config struct {
|
||||
// ClientID is the application's ID.
|
||||
ClientID string
|
||||
@@ -45,9 +39,9 @@ type Config struct {
|
||||
ClientSecret string
|
||||
|
||||
// Endpoint contains the resource server's token endpoint
|
||||
// URLs. These are supplied by the server and are often
|
||||
// available via site-specific packages (for example,
|
||||
// google.Endpoint or github.Endpoint)
|
||||
// URLs. These are constants specific to each server and are
|
||||
// often available via site-specific packages, such as
|
||||
// google.Endpoint or github.Endpoint.
|
||||
Endpoint Endpoint
|
||||
|
||||
// RedirectURL is the URL to redirect users going through
|
||||
@@ -61,6 +55,8 @@ type Config struct {
|
||||
// A TokenSource is anything that can return a token.
|
||||
type TokenSource interface {
|
||||
// Token returns a token or an error.
|
||||
// Token must be safe for concurrent use by multiple goroutines.
|
||||
// The returned Token must not be modified.
|
||||
Token() (*Token, error)
|
||||
}
|
||||
|
||||
@@ -77,28 +73,34 @@ var (
|
||||
// "access_type" field that gets sent in the URL returned by
|
||||
// AuthCodeURL.
|
||||
//
|
||||
// Online (the default if neither is specified) is the default.
|
||||
// If your application needs to refresh access tokens when the
|
||||
// user is not present at the browser, then use offline. This
|
||||
// will result in your application obtaining a refresh token
|
||||
// the first time your application exchanges an authorization
|
||||
// Online is the default if neither is specified. If your
|
||||
// application needs to refresh access tokens when the user
|
||||
// is not present at the browser, then use offline. This will
|
||||
// result in your application obtaining a refresh token the
|
||||
// first time your application exchanges an authorization
|
||||
// code for a user.
|
||||
AccessTypeOnline AuthCodeOption = setParam{"access_type", "online"}
|
||||
AccessTypeOffline AuthCodeOption = setParam{"access_type", "offline"}
|
||||
AccessTypeOnline AuthCodeOption = SetParam("access_type", "online")
|
||||
AccessTypeOffline AuthCodeOption = SetParam("access_type", "offline")
|
||||
|
||||
// ApprovalForce forces the users to view the consent dialog
|
||||
// and confirm the permissions request at the URL returned
|
||||
// from AuthCodeURL, even if they've already done so.
|
||||
ApprovalForce AuthCodeOption = setParam{"approval_prompt", "force"}
|
||||
ApprovalForce AuthCodeOption = SetParam("approval_prompt", "force")
|
||||
)
|
||||
|
||||
// An AuthCodeOption is passed to Config.AuthCodeURL.
|
||||
type AuthCodeOption interface {
|
||||
setValue(url.Values)
|
||||
}
|
||||
|
||||
type setParam struct{ k, v string }
|
||||
|
||||
func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) }
|
||||
|
||||
// An AuthCodeOption is passed to Config.AuthCodeURL.
|
||||
type AuthCodeOption interface {
|
||||
setValue(url.Values)
|
||||
// SetParam builds an AuthCodeOption which passes key/value parameters
|
||||
// to a provider's authorization endpoint.
|
||||
func SetParam(key, value string) AuthCodeOption {
|
||||
return setParam{key, value}
|
||||
}
|
||||
|
||||
// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
|
||||
@@ -133,17 +135,37 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// PasswordCredentialsToken converts a resource owner username and password
|
||||
// pair into a token.
|
||||
//
|
||||
// Per the RFC, this grant type should only be used "when there is a high
|
||||
// degree of trust between the resource owner and the client (e.g., the client
|
||||
// is part of the device operating system or a highly privileged application),
|
||||
// and when other authorization grant types are not available."
|
||||
// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
|
||||
//
|
||||
// The HTTP client to use is derived from the context.
|
||||
// If nil, http.DefaultClient is used.
|
||||
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
|
||||
return retrieveToken(ctx, c, url.Values{
|
||||
"grant_type": {"password"},
|
||||
"username": {username},
|
||||
"password": {password},
|
||||
"scope": condVal(strings.Join(c.Scopes, " ")),
|
||||
})
|
||||
}
|
||||
|
||||
// Exchange converts an authorization code into a token.
|
||||
//
|
||||
// It is used after a resource provider redirects the user back
|
||||
// to the Redirect URI (the URL obtained from AuthCodeURL).
|
||||
//
|
||||
// The HTTP client to use is derived from the context. If nil,
|
||||
// http.DefaultClient is used. See the Context type's documentation.
|
||||
// The HTTP client to use is derived from the context.
|
||||
// If a client is not provided via the context, http.DefaultClient is used.
|
||||
//
|
||||
// The code will be in the *http.Request.FormValue("code"). Before
|
||||
// calling Exchange, be sure to validate FormValue("state").
|
||||
func (c *Config) Exchange(ctx Context, code string) (*Token, error) {
|
||||
func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) {
|
||||
return retrieveToken(ctx, c, url.Values{
|
||||
"grant_type": {"authorization_code"},
|
||||
"code": {code},
|
||||
@@ -156,7 +178,7 @@ func (c *Config) Exchange(ctx Context, code string) (*Token, error) {
|
||||
// given a Context value. If it returns an error, the search stops
|
||||
// with that error. If it returns (nil, nil), the search continues
|
||||
// down the list of registered funcs.
|
||||
type contextClientFunc func(Context) (*http.Client, error)
|
||||
type contextClientFunc func(context.Context) (*http.Client, error)
|
||||
|
||||
var contextClientFuncs []contextClientFunc
|
||||
|
||||
@@ -164,7 +186,7 @@ func registerContextClientFunc(fn contextClientFunc) {
|
||||
contextClientFuncs = append(contextClientFuncs, fn)
|
||||
}
|
||||
|
||||
func contextClient(ctx Context) (*http.Client, error) {
|
||||
func contextClient(ctx context.Context) (*http.Client, error) {
|
||||
for _, fn := range contextClientFuncs {
|
||||
c, err := fn(ctx)
|
||||
if err != nil {
|
||||
@@ -174,15 +196,13 @@ func contextClient(ctx Context) (*http.Client, error) {
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
if xc, ok := ctx.(context.Context); ok {
|
||||
if hc, ok := xc.Value(HTTPClient).(*http.Client); ok {
|
||||
return hc, nil
|
||||
}
|
||||
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
|
||||
return hc, nil
|
||||
}
|
||||
return http.DefaultClient, nil
|
||||
}
|
||||
|
||||
func contextTransport(ctx Context) http.RoundTripper {
|
||||
func contextTransport(ctx context.Context) http.RoundTripper {
|
||||
hc, err := contextClient(ctx)
|
||||
if err != nil {
|
||||
// This is a rare error case (somebody using nil on App Engine),
|
||||
@@ -198,54 +218,64 @@ func contextTransport(ctx Context) http.RoundTripper {
|
||||
// The token will auto-refresh as necessary. The underlying
|
||||
// HTTP transport will be obtained using the provided context.
|
||||
// The returned client and its Transport should not be modified.
|
||||
func (c *Config) Client(ctx Context, t *Token) *http.Client {
|
||||
func (c *Config) Client(ctx context.Context, t *Token) *http.Client {
|
||||
return NewClient(ctx, c.TokenSource(ctx, t))
|
||||
}
|
||||
|
||||
// TokenSource returns a TokenSource that returns t until t expires,
|
||||
// automatically refreshing it as necessary using the provided context.
|
||||
// See the the Context documentation.
|
||||
//
|
||||
// Most users will use Config.Client instead.
|
||||
func (c *Config) TokenSource(ctx Context, t *Token) TokenSource {
|
||||
nwn := &newWhenNeededSource{t: t}
|
||||
nwn.new = tokenRefresher{
|
||||
ctx: ctx,
|
||||
conf: c,
|
||||
oldToken: &nwn.t,
|
||||
func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource {
|
||||
tkr := &tokenRefresher{
|
||||
ctx: ctx,
|
||||
conf: c,
|
||||
}
|
||||
if t != nil {
|
||||
tkr.refreshToken = t.RefreshToken
|
||||
}
|
||||
return &reuseTokenSource{
|
||||
t: t,
|
||||
new: tkr,
|
||||
}
|
||||
return nwn
|
||||
}
|
||||
|
||||
// tokenRefresher is a TokenSource that makes "grant_type"=="refresh_token"
|
||||
// HTTP requests to renew a token using a RefreshToken.
|
||||
type tokenRefresher struct {
|
||||
ctx Context // used to get HTTP requests
|
||||
conf *Config
|
||||
oldToken **Token // pointer to old *Token w/ RefreshToken
|
||||
ctx context.Context // used to get HTTP requests
|
||||
conf *Config
|
||||
refreshToken string
|
||||
}
|
||||
|
||||
func (tf tokenRefresher) Token() (*Token, error) {
|
||||
t := *tf.oldToken
|
||||
if t == nil {
|
||||
return nil, errors.New("oauth2: attempted use of nil Token")
|
||||
}
|
||||
if t.RefreshToken == "" {
|
||||
// WARNING: Token is not safe for concurrent access, as it
|
||||
// updates the tokenRefresher's refreshToken field.
|
||||
// Within this package, it is used by reuseTokenSource which
|
||||
// synchronizes calls to this method with its own mutex.
|
||||
func (tf *tokenRefresher) Token() (*Token, error) {
|
||||
if tf.refreshToken == "" {
|
||||
return nil, errors.New("oauth2: token expired and refresh token is not set")
|
||||
}
|
||||
return retrieveToken(tf.ctx, tf.conf, url.Values{
|
||||
|
||||
tk, err := retrieveToken(tf.ctx, tf.conf, url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"refresh_token": {t.RefreshToken},
|
||||
"refresh_token": {tf.refreshToken},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tf.refreshToken != tk.RefreshToken {
|
||||
tf.refreshToken = tk.RefreshToken
|
||||
}
|
||||
return tk, err
|
||||
}
|
||||
|
||||
// newWhenNeededSource is a TokenSource that holds a single token in memory
|
||||
// reuseTokenSource is a TokenSource that holds a single token in memory
|
||||
// and validates its expiry before each call to retrieve it with
|
||||
// Token. If it's expired, it will be auto-refreshed using the
|
||||
// new TokenSource.
|
||||
//
|
||||
// The first call to TokenRefresher must be SetToken.
|
||||
type newWhenNeededSource struct {
|
||||
type reuseTokenSource struct {
|
||||
new TokenSource // called when t is expired.
|
||||
|
||||
mu sync.Mutex // guards t
|
||||
@@ -255,10 +285,10 @@ type newWhenNeededSource struct {
|
||||
// Token returns the current token if it's still valid, else will
|
||||
// refresh the current token (using r.Context for HTTP client
|
||||
// information) and return the new one.
|
||||
func (s *newWhenNeededSource) Token() (*Token, error) {
|
||||
func (s *reuseTokenSource) Token() (*Token, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.t != nil && !s.t.Expired() {
|
||||
if s.t.Valid() {
|
||||
return s.t, nil
|
||||
}
|
||||
t, err := s.new.Token()
|
||||
@@ -269,7 +299,7 @@ func (s *newWhenNeededSource) Token() (*Token, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func retrieveToken(ctx Context, c *Config, v url.Values) (*Token, error) {
|
||||
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
|
||||
hc, err := contextClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -284,7 +314,7 @@ func retrieveToken(ctx Context, c *Config, v url.Values) (*Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
if !bustedAuth && c.ClientSecret != "" {
|
||||
if !bustedAuth {
|
||||
req.SetBasicAuth(c.ClientID, c.ClientSecret)
|
||||
}
|
||||
r, err := hc.Do(req)
|
||||
@@ -350,11 +380,11 @@ func retrieveToken(ctx Context, c *Config, v url.Values) (*Token, error) {
|
||||
// tokenJSON is the struct representing the HTTP response from OAuth2
|
||||
// providers returning a token in JSON form.
|
||||
type tokenJSON struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresIn int32 `json:"expires_in"`
|
||||
Expires int32 `json:"expires"` // broken Facebook spelling of expires_in
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
|
||||
Expires expirationTime `json:"expires"` // broken Facebook spelling of expires_in
|
||||
}
|
||||
|
||||
func (e *tokenJSON) expiry() (t time.Time) {
|
||||
@@ -367,6 +397,22 @@ func (e *tokenJSON) expiry() (t time.Time) {
|
||||
return
|
||||
}
|
||||
|
||||
type expirationTime int32
|
||||
|
||||
func (e *expirationTime) UnmarshalJSON(b []byte) error {
|
||||
var n json.Number
|
||||
err := json.Unmarshal(b, &n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i, err := n.Int64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e = expirationTime(i)
|
||||
return nil
|
||||
}
|
||||
|
||||
func condVal(v string) []string {
|
||||
if v == "" {
|
||||
return nil
|
||||
@@ -374,6 +420,25 @@ func condVal(v string) []string {
|
||||
return []string{v}
|
||||
}
|
||||
|
||||
var brokenAuthHeaderProviders = []string{
|
||||
"https://accounts.google.com/",
|
||||
"https://www.googleapis.com/",
|
||||
"https://github.com/",
|
||||
"https://api.instagram.com/",
|
||||
"https://www.douban.com/",
|
||||
"https://api.dropbox.com/",
|
||||
"https://api.soundcloud.com/",
|
||||
"https://www.linkedin.com/",
|
||||
"https://api.twitch.tv/",
|
||||
"https://oauth.vk.com/",
|
||||
"https://api.odnoklassniki.ru/",
|
||||
"https://connect.stripe.com/",
|
||||
"https://api.pushbullet.com/",
|
||||
"https://oauth.sandbox.trainingpeaks.com/",
|
||||
"https://oauth.trainingpeaks.com/",
|
||||
"https://www.strava.com/oauth/",
|
||||
}
|
||||
|
||||
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
|
||||
// implements the OAuth2 spec correctly
|
||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
|
||||
@@ -381,16 +446,13 @@ func condVal(v string) []string {
|
||||
// - Reddit only accepts client secret in the Authorization header
|
||||
// - Dropbox accepts either it in URL param or Auth header, but not both.
|
||||
// - Google only accepts URL param (not spec compliant?), not Auth header
|
||||
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
|
||||
func providerAuthHeaderWorks(tokenURL string) bool {
|
||||
if strings.HasPrefix(tokenURL, "https://accounts.google.com/") ||
|
||||
strings.HasPrefix(tokenURL, "https://github.com/") ||
|
||||
strings.HasPrefix(tokenURL, "https://api.instagram.com/") ||
|
||||
strings.HasPrefix(tokenURL, "https://www.douban.com/") ||
|
||||
strings.HasPrefix(tokenURL, "https://api.dropbox.com/") ||
|
||||
strings.HasPrefix(tokenURL, "https://api.soundcloud.com/") ||
|
||||
strings.HasPrefix(tokenURL, "https://www.linkedin.com/") {
|
||||
// Some sites fail to implement the OAuth2 spec fully.
|
||||
return false
|
||||
for _, s := range brokenAuthHeaderProviders {
|
||||
if strings.HasPrefix(tokenURL, s) {
|
||||
// Some sites fail to implement the OAuth2 spec fully.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Assume the provider implements the spec properly
|
||||
@@ -410,12 +472,52 @@ var HTTPClient contextKey
|
||||
type contextKey struct{}
|
||||
|
||||
// NewClient creates an *http.Client from a Context and TokenSource.
|
||||
// The client's lifetime does not extend beyond the lifetime of the context.
|
||||
func NewClient(ctx Context, src TokenSource) *http.Client {
|
||||
// The returned client is not valid beyond the lifetime of the context.
|
||||
//
|
||||
// As a special case, if src is nil, a non-OAuth2 client is returned
|
||||
// using the provided context. This exists to support related OAuth2
|
||||
// packages.
|
||||
func NewClient(ctx context.Context, src TokenSource) *http.Client {
|
||||
if src == nil {
|
||||
c, err := contextClient(ctx)
|
||||
if err != nil {
|
||||
return &http.Client{Transport: errorTransport{err}}
|
||||
}
|
||||
return c
|
||||
}
|
||||
return &http.Client{
|
||||
Transport: &Transport{
|
||||
Base: contextTransport(ctx),
|
||||
Source: src,
|
||||
Source: ReuseTokenSource(nil, src),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ReuseTokenSource returns a TokenSource which repeatedly returns the
|
||||
// same token as long as it's valid, starting with t.
|
||||
// When its cached token is invalid, a new token is obtained from src.
|
||||
//
|
||||
// ReuseTokenSource is typically used to reuse tokens from a cache
|
||||
// (such as a file on disk) between runs of a program, rather than
|
||||
// obtaining new tokens unnecessarily.
|
||||
//
|
||||
// The initial token t may be nil, in which case the TokenSource is
|
||||
// wrapped in a caching version if it isn't one already. This also
|
||||
// means it's always safe to wrap ReuseTokenSource around any other
|
||||
// TokenSource without adverse effects.
|
||||
func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
|
||||
// Don't wrap a reuseTokenSource in itself. That would work,
|
||||
// but cause an unnecessary number of mutex operations.
|
||||
// Just build the equivalent one.
|
||||
if rt, ok := src.(*reuseTokenSource); ok {
|
||||
if t == nil {
|
||||
// Just use it directly.
|
||||
return rt
|
||||
}
|
||||
src = rt.new
|
||||
}
|
||||
return &reuseTokenSource{
|
||||
t: t,
|
||||
new: src,
|
||||
}
|
||||
}
|
||||
|
||||
187
Godeps/_workspace/src/golang.org/x/oauth2/oauth2_test.go
generated
vendored
187
Godeps/_workspace/src/golang.org/x/oauth2/oauth2_test.go
generated
vendored
@@ -5,11 +5,16 @@
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
@@ -56,6 +61,15 @@ func TestAuthCodeURL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthCodeURL_CustomParam(t *testing.T) {
|
||||
conf := newConf("server")
|
||||
param := SetParam("foo", "bar")
|
||||
url := conf.AuthCodeURL("baz", param)
|
||||
if url != "server/auth?client_id=CLIENT_ID&foo=bar&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=baz" {
|
||||
t.Errorf("Auth code URL doesn't match the expected, found: %v", url)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthCodeURL_Optional(t *testing.T) {
|
||||
conf := &Config{
|
||||
ClientID: "CLIENT_ID",
|
||||
@@ -99,8 +113,8 @@ func TestExchangeRequest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if tok.Expired() {
|
||||
t.Errorf("Token shouldn't be expired.")
|
||||
if !tok.Valid() {
|
||||
t.Fatalf("Token invalid. Got: %#v", tok)
|
||||
}
|
||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
||||
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||
@@ -143,8 +157,8 @@ func TestExchangeRequest_JSONResponse(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if tok.Expired() {
|
||||
t.Errorf("Token shouldn't be expired.")
|
||||
if !tok.Valid() {
|
||||
t.Fatalf("Token invalid. Got: %#v", tok)
|
||||
}
|
||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
||||
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||
@@ -158,6 +172,60 @@ func TestExchangeRequest_JSONResponse(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
const day = 24 * time.Hour
|
||||
|
||||
func TestExchangeRequest_JSONResponse_Expiry(t *testing.T) {
|
||||
seconds := int32(day.Seconds())
|
||||
jsonNumberType := reflect.TypeOf(json.Number("0"))
|
||||
for _, c := range []struct {
|
||||
expires string
|
||||
expect error
|
||||
}{
|
||||
{fmt.Sprintf(`"expires_in": %d`, seconds), nil},
|
||||
{fmt.Sprintf(`"expires_in": "%d"`, seconds), nil}, // PayPal case
|
||||
{fmt.Sprintf(`"expires": %d`, seconds), nil}, // Facebook case
|
||||
{`"expires": false`, &json.UnmarshalTypeError{Value: "bool", Type: jsonNumberType}}, // wrong type
|
||||
{`"expires": {}`, &json.UnmarshalTypeError{Value: "object", Type: jsonNumberType}}, // wrong type
|
||||
{`"expires": "zzz"`, &strconv.NumError{Func: "ParseInt", Num: "zzz", Err: strconv.ErrSyntax}}, // wrong value
|
||||
} {
|
||||
testExchangeRequest_JSONResponse_expiry(t, c.expires, c.expect)
|
||||
}
|
||||
}
|
||||
|
||||
func testExchangeRequest_JSONResponse_expiry(t *testing.T, exp string, expect error) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(fmt.Sprintf(`{"access_token": "90d", "scope": "user", "token_type": "bearer", %s}`, exp)))
|
||||
}))
|
||||
defer ts.Close()
|
||||
conf := newConf(ts.URL)
|
||||
t1 := time.Now().Add(day)
|
||||
tok, err := conf.Exchange(NoContext, "exchange-code")
|
||||
t2 := time.Now().Add(day)
|
||||
// Do a fmt.Sprint comparison so either side can be
|
||||
// nil. fmt.Sprint just stringifies them to "<nil>", and no
|
||||
// non-nil expected error ever stringifies as "<nil>", so this
|
||||
// isn't terribly disgusting. We do this because Go 1.4 and
|
||||
// Go 1.5 return a different deep value for
|
||||
// json.UnmarshalTypeError. In Go 1.5, the
|
||||
// json.UnmarshalTypeError contains a new field with a new
|
||||
// non-zero value. Rather than ignore it here with reflect or
|
||||
// add new files and +build tags, just look at the strings.
|
||||
if fmt.Sprint(err) != fmt.Sprint(expect) {
|
||||
t.Errorf("Error = %v; want %v", err, expect)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !tok.Valid() {
|
||||
t.Fatalf("Token invalid. Got: %#v", tok)
|
||||
}
|
||||
expiry := tok.Expiry
|
||||
if expiry.Before(t1) || expiry.After(t2) {
|
||||
t.Errorf("Unexpected value for Expiry: %v (shold be between %v and %v)", expiry, t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExchangeRequest_BadResponse(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -210,6 +278,53 @@ func TestExchangeRequest_NonBasicAuth(t *testing.T) {
|
||||
conf.Exchange(ctx, "code")
|
||||
}
|
||||
|
||||
func TestPasswordCredentialsTokenRequest(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
expected := "/token"
|
||||
if r.URL.String() != expected {
|
||||
t.Errorf("URL = %q; want %q", r.URL, expected)
|
||||
}
|
||||
headerAuth := r.Header.Get("Authorization")
|
||||
expected = "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ="
|
||||
if headerAuth != expected {
|
||||
t.Errorf("Authorization header = %q; want %q", headerAuth, expected)
|
||||
}
|
||||
headerContentType := r.Header.Get("Content-Type")
|
||||
expected = "application/x-www-form-urlencoded"
|
||||
if headerContentType != expected {
|
||||
t.Errorf("Content-Type header = %q; want %q", headerContentType, expected)
|
||||
}
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Failed reading request body: %s.", err)
|
||||
}
|
||||
expected = "client_id=CLIENT_ID&grant_type=password&password=password1&scope=scope1+scope2&username=user1"
|
||||
if string(body) != expected {
|
||||
t.Errorf("res.Body = %q; want %q", string(body), expected)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer"))
|
||||
}))
|
||||
defer ts.Close()
|
||||
conf := newConf(ts.URL)
|
||||
tok, err := conf.PasswordCredentialsToken(NoContext, "user1", "password1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !tok.Valid() {
|
||||
t.Fatalf("Token invalid. Got: %#v", tok)
|
||||
}
|
||||
expected := "90d64460d14870c08c81352a05dedd3465940a7c"
|
||||
if tok.AccessToken != expected {
|
||||
t.Errorf("AccessToken = %q; want %q", tok.AccessToken, expected)
|
||||
}
|
||||
expected = "bearer"
|
||||
if tok.TokenType != expected {
|
||||
t.Errorf("TokenType = %q; want %q", tok.TokenType, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenRefreshRequest(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.String() == "/somethingelse" {
|
||||
@@ -258,3 +373,67 @@ func TestFetchWithNoRefreshToken(t *testing.T) {
|
||||
t.Errorf("Fetch should return an error if no refresh token is set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshToken_RefreshTokenReplacement(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"access_token":"ACCESS TOKEN", "scope": "user", "token_type": "bearer", "refresh_token": "NEW REFRESH TOKEN"}`))
|
||||
return
|
||||
}))
|
||||
defer ts.Close()
|
||||
conf := newConf(ts.URL)
|
||||
tkr := tokenRefresher{
|
||||
conf: conf,
|
||||
ctx: NoContext,
|
||||
refreshToken: "OLD REFRESH TOKEN",
|
||||
}
|
||||
tk, err := tkr.Token()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected refreshToken error returned: %v", err)
|
||||
return
|
||||
}
|
||||
if tk.RefreshToken != tkr.refreshToken {
|
||||
t.Errorf("tokenRefresher.refresh_token = %s; want %s", tkr.refreshToken, tk.RefreshToken)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigClientWithToken(t *testing.T) {
|
||||
tok := &Token{
|
||||
AccessToken: "abc123",
|
||||
}
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if got, want := r.Header.Get("Authorization"), fmt.Sprintf("Bearer %s", tok.AccessToken); got != want {
|
||||
t.Errorf("Authorization header = %q; want %q", got, want)
|
||||
}
|
||||
return
|
||||
}))
|
||||
defer ts.Close()
|
||||
conf := newConf(ts.URL)
|
||||
|
||||
c := conf.Client(NoContext, tok)
|
||||
req, err := http.NewRequest("GET", ts.URL, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = c.Do(req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_providerAuthHeaderWorks(t *testing.T) {
|
||||
for _, p := range brokenAuthHeaderProviders {
|
||||
if providerAuthHeaderWorks(p) {
|
||||
t.Errorf("URL: %s not found in list", p)
|
||||
}
|
||||
p := fmt.Sprintf("%ssomesuffix", p)
|
||||
if providerAuthHeaderWorks(p) {
|
||||
t.Errorf("URL: %s not found in list", p)
|
||||
}
|
||||
}
|
||||
p := "https://api.not-in-the-list-example.com/"
|
||||
if !providerAuthHeaderWorks(p) {
|
||||
t.Errorf("URL: %s found in list", p)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
16
Godeps/_workspace/src/golang.org/x/oauth2/odnoklassniki/odnoklassniki.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/oauth2/odnoklassniki/odnoklassniki.go
generated
vendored
Normal file
@@ -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",
|
||||
}
|
||||
22
Godeps/_workspace/src/golang.org/x/oauth2/paypal/paypal.go
generated
vendored
Normal file
22
Godeps/_workspace/src/golang.org/x/oauth2/paypal/paypal.go
generated
vendored
Normal file
@@ -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",
|
||||
}
|
||||
47
Godeps/_workspace/src/golang.org/x/oauth2/token.go
generated
vendored
47
Godeps/_workspace/src/golang.org/x/oauth2/token.go
generated
vendored
@@ -10,13 +10,18 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// expiryDelta determines how earlier a token should be considered
|
||||
// expired than its actual expiration time. It is used to avoid late
|
||||
// expirations due to client-server time mismatches.
|
||||
const expiryDelta = 10 * time.Second
|
||||
|
||||
// Token represents the crendentials used to authorize
|
||||
// the requests to access protected resources on the OAuth 2.0
|
||||
// provider's backend.
|
||||
//
|
||||
// Most users of this package should not access fields of Token
|
||||
// directly. They're exported mostly for use by related packages
|
||||
// implementing derivate OAuth2 flows.
|
||||
// implementing derivative OAuth2 flows.
|
||||
type Token struct {
|
||||
// AccessToken is the token that authorizes and authenticates
|
||||
// the requests.
|
||||
@@ -60,28 +65,40 @@ func (t *Token) SetAuthHeader(r *http.Request) {
|
||||
r.Header.Set("Authorization", t.Type()+" "+t.AccessToken)
|
||||
}
|
||||
|
||||
// Extra returns an extra field returned from the server during token
|
||||
// retrieval.
|
||||
func (t *Token) Extra(key string) string {
|
||||
// WithExtra returns a new Token that's a clone of t, but using the
|
||||
// provided raw extra map. This is only intended for use by packages
|
||||
// implementing derivative OAuth2 flows.
|
||||
func (t *Token) WithExtra(extra interface{}) *Token {
|
||||
t2 := new(Token)
|
||||
*t2 = *t
|
||||
t2.raw = extra
|
||||
return t2
|
||||
}
|
||||
|
||||
// Extra returns an extra field.
|
||||
// Extra fields are key-value pairs returned by the server as a
|
||||
// part of the token retrieval response.
|
||||
func (t *Token) Extra(key string) interface{} {
|
||||
if vals, ok := t.raw.(url.Values); ok {
|
||||
// TODO(jbd): Cast numeric values to int64 or float64.
|
||||
return vals.Get(key)
|
||||
}
|
||||
if raw, ok := t.raw.(map[string]interface{}); ok {
|
||||
if val, ok := raw[key].(string); ok {
|
||||
return val
|
||||
}
|
||||
return raw[key]
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
// Expired returns true if there is no access token or the
|
||||
// access token is expired.
|
||||
func (t *Token) Expired() bool {
|
||||
if t.AccessToken == "" {
|
||||
return true
|
||||
}
|
||||
// expired reports whether the token is expired.
|
||||
// t must be non-nil.
|
||||
func (t *Token) expired() bool {
|
||||
if t.Expiry.IsZero() {
|
||||
return false
|
||||
}
|
||||
return t.Expiry.Before(time.Now())
|
||||
return t.Expiry.Add(-expiryDelta).Before(time.Now())
|
||||
}
|
||||
|
||||
// Valid reports whether t is non-nil, has an AccessToken, and is not expired.
|
||||
func (t *Token) Valid() bool {
|
||||
return t != nil && t.AccessToken != "" && !t.expired()
|
||||
}
|
||||
|
||||
50
Godeps/_workspace/src/golang.org/x/oauth2/token_test.go
generated
vendored
Normal file
50
Godeps/_workspace/src/golang.org/x/oauth2/token_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Godeps/_workspace/src/golang.org/x/oauth2/transport_test.go
generated
vendored
10
Godeps/_workspace/src/golang.org/x/oauth2/transport_test.go
generated
vendored
@@ -32,10 +32,10 @@ func TestTransportTokenSource(t *testing.T) {
|
||||
client.Get(server.URL)
|
||||
}
|
||||
|
||||
func TestExpiredWithNoAccessToken(t *testing.T) {
|
||||
func TestTokenValidNoAccessToken(t *testing.T) {
|
||||
token := &Token{}
|
||||
if !token.Expired() {
|
||||
t.Errorf("Token should be expired if no access token is provided")
|
||||
if token.Valid() {
|
||||
t.Errorf("Token should not be valid with no access token")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ func TestExpiredWithExpiry(t *testing.T) {
|
||||
token := &Token{
|
||||
Expiry: time.Now().Add(-5 * time.Hour),
|
||||
}
|
||||
if !token.Expired() {
|
||||
t.Errorf("Token should be expired if no access token is provided")
|
||||
if token.Valid() {
|
||||
t.Errorf("Token should not be valid if it expired in the past")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
16
Godeps/_workspace/src/golang.org/x/oauth2/vk/vk.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/oauth2/vk/vk.go
generated
vendored
Normal file
@@ -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",
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
@@ -24,7 +25,7 @@ type SocialConnector interface {
|
||||
UserInfo(token *oauth2.Token) (*BasicUserInfo, error)
|
||||
|
||||
AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string
|
||||
Exchange(ctx oauth2.Context, code string) (*oauth2.Token, error)
|
||||
Exchange(ctx context.Context, code string) (*oauth2.Token, error)
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
Reference in New Issue
Block a user