mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Update oauth2 lib (#8524)
* Update to latest oauth2 library using govendor * Follow API changes
This commit is contained in:
parent
f224fd8310
commit
1efdd92ae8
@ -64,7 +64,7 @@ func OAuthLogin(ctx *middleware.Context) {
|
|||||||
if setting.OAuthService.OAuthInfos[name].HostedDomain == "" {
|
if setting.OAuthService.OAuthInfos[name].HostedDomain == "" {
|
||||||
ctx.Redirect(connect.AuthCodeURL(state, oauth2.AccessTypeOnline))
|
ctx.Redirect(connect.AuthCodeURL(state, oauth2.AccessTypeOnline))
|
||||||
} else {
|
} else {
|
||||||
ctx.Redirect(connect.AuthCodeURL(state, oauth2.SetParam("hd", setting.OAuthService.OAuthInfos[name].HostedDomain), oauth2.AccessTypeOnline))
|
ctx.Redirect(connect.AuthCodeURL(state, oauth2.SetAuthURLParam("hd", setting.OAuthService.OAuthInfos[name].HostedDomain), oauth2.AccessTypeOnline))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
14
vendor/golang.org/x/oauth2/.travis.yml
generated
vendored
14
vendor/golang.org/x/oauth2/.travis.yml
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.3
|
|
||||||
- 1.4
|
|
||||||
|
|
||||||
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 golang.org/x/oauth2/...
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go test -v golang.org/x/oauth2/...
|
|
12
vendor/golang.org/x/oauth2/README.md
generated
vendored
12
vendor/golang.org/x/oauth2/README.md
generated
vendored
@ -1,6 +1,7 @@
|
|||||||
# OAuth2 for Go
|
# OAuth2 for Go
|
||||||
|
|
||||||
[](https://travis-ci.org/golang/oauth2)
|
[](https://travis-ci.org/golang/oauth2)
|
||||||
|
[](https://godoc.org/golang.org/x/oauth2)
|
||||||
|
|
||||||
oauth2 package contains a client implementation for OAuth 2.0 spec.
|
oauth2 package contains a client implementation for OAuth 2.0 spec.
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ with the `oauth2` package.
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
newappengine "google.golang.org/appengine"
|
newappengine "google.golang.org/appengine"
|
||||||
newurlftech "google.golang.org/urlfetch"
|
newurlfetch "google.golang.org/appengine/urlfetch"
|
||||||
|
|
||||||
"appengine"
|
"appengine"
|
||||||
)
|
)
|
||||||
@ -62,3 +63,12 @@ with the `oauth2` package.
|
|||||||
client.Get("...")
|
client.Get("...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We appreciate your help!
|
||||||
|
|
||||||
|
To contribute, please read the contribution guidelines:
|
||||||
|
https://golang.org/doc/contribute.html
|
||||||
|
|
||||||
|
Note that the Go project does not use GitHub pull requests but
|
||||||
|
uses Gerrit for code reviews. See the contribution guide for details.
|
||||||
|
7
vendor/golang.org/x/oauth2/client_appengine.go
generated
vendored
7
vendor/golang.org/x/oauth2/client_appengine.go
generated
vendored
@ -1,8 +1,8 @@
|
|||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build appengine appenginevm
|
// +build appengine
|
||||||
|
|
||||||
// App Engine hooks.
|
// App Engine hooks.
|
||||||
|
|
||||||
@ -12,11 +12,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2/internal"
|
||||||
"google.golang.org/appengine/urlfetch"
|
"google.golang.org/appengine/urlfetch"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registerContextClientFunc(contextClientAppEngine)
|
internal.RegisterContextClientFunc(contextClientAppEngine)
|
||||||
}
|
}
|
||||||
|
|
||||||
func contextClientAppEngine(ctx context.Context) (*http.Client, error) {
|
func contextClientAppEngine(ctx context.Context) (*http.Client, error) {
|
||||||
|
45
vendor/golang.org/x/oauth2/example_test.go
generated
vendored
45
vendor/golang.org/x/oauth2/example_test.go
generated
vendored
@ -1,45 +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 oauth2_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleConfig() {
|
|
||||||
conf := &oauth2.Config{
|
|
||||||
ClientID: "YOUR_CLIENT_ID",
|
|
||||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
|
||||||
Scopes: []string{"SCOPE1", "SCOPE2"},
|
|
||||||
Endpoint: oauth2.Endpoint{
|
|
||||||
AuthURL: "https://provider.com/o/oauth2/auth",
|
|
||||||
TokenURL: "https://provider.com/o/oauth2/token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect user to consent page to ask for permission
|
|
||||||
// for the scopes specified above.
|
|
||||||
url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
|
|
||||||
fmt.Printf("Visit the URL for the auth dialog: %v", url)
|
|
||||||
|
|
||||||
// Use the authorization code that is pushed to the redirect URL.
|
|
||||||
// NewTransportWithCode will do the handshake to retrieve
|
|
||||||
// an access token and initiate a Transport that is
|
|
||||||
// authorized and authenticated by the retrieved token.
|
|
||||||
var code string
|
|
||||||
if _, err := fmt.Scan(&code); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
tok, err := conf.Exchange(oauth2.NoContext, code)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client := conf.Client(oauth2.NoContext, tok)
|
|
||||||
client.Get("...")
|
|
||||||
}
|
|
16
vendor/golang.org/x/oauth2/facebook/facebook.go
generated
vendored
16
vendor/golang.org/x/oauth2/facebook/facebook.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// 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",
|
|
||||||
}
|
|
16
vendor/golang.org/x/oauth2/github/github.go
generated
vendored
16
vendor/golang.org/x/oauth2/github/github.go
generated
vendored
@ -1,16 +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 github provides constants for using OAuth2 to access Github.
|
|
||||||
package github // import "golang.org/x/oauth2/github"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Endpoint is Github's OAuth 2.0 endpoint.
|
|
||||||
var Endpoint = oauth2.Endpoint{
|
|
||||||
AuthURL: "https://github.com/login/oauth/authorize",
|
|
||||||
TokenURL: "https://github.com/login/oauth/access_token",
|
|
||||||
}
|
|
83
vendor/golang.org/x/oauth2/google/appengine.go
generated
vendored
83
vendor/golang.org/x/oauth2/google/appengine.go
generated
vendored
@ -1,83 +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 (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"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.
|
|
||||||
//
|
|
||||||
// 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: scopes,
|
|
||||||
key: strings.Join(scopes, " "),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
vendor/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
13
vendor/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
154
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
154
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
@ -1,154 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
150
vendor/golang.org/x/oauth2/google/example_test.go
generated
vendored
150
vendor/golang.org/x/oauth2/google/example_test.go
generated
vendored
@ -1,150 +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_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
"golang.org/x/oauth2/google"
|
|
||||||
"golang.org/x/oauth2/jwt"
|
|
||||||
"google.golang.org/appengine"
|
|
||||||
"google.golang.org/appengine/urlfetch"
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
// Developer Console (https://console.developers.google.com).
|
|
||||||
conf := &oauth2.Config{
|
|
||||||
ClientID: "YOUR_CLIENT_ID",
|
|
||||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
|
||||||
RedirectURL: "YOUR_REDIRECT_URL",
|
|
||||||
Scopes: []string{
|
|
||||||
"https://www.googleapis.com/auth/bigquery",
|
|
||||||
"https://www.googleapis.com/auth/blogger",
|
|
||||||
},
|
|
||||||
Endpoint: google.Endpoint,
|
|
||||||
}
|
|
||||||
// Redirect user to Google's consent page to ask for permission
|
|
||||||
// for the scopes specified above.
|
|
||||||
url := conf.AuthCodeURL("state")
|
|
||||||
fmt.Printf("Visit the URL for the auth dialog: %v", url)
|
|
||||||
|
|
||||||
// Handle the exchange code to initiate a transport.
|
|
||||||
tok, err := conf.Exchange(oauth2.NoContext, "authorization-code")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
client := conf.Client(oauth2.NoContext, tok)
|
|
||||||
client.Get("...")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleJWTConfigFromJSON() {
|
|
||||||
// Your credentials should be obtained from the Google
|
|
||||||
// Developer Console (https://console.developers.google.com).
|
|
||||||
// Navigate to your project, then see the "Credentials" page
|
|
||||||
// under "APIs & Auth".
|
|
||||||
// To create a service account client, click "Create new Client ID",
|
|
||||||
// select "Service Account", and click "Create Client ID". A JSON
|
|
||||||
// key file will then be downloaded to your computer.
|
|
||||||
data, err := ioutil.ReadFile("/path/to/your-project-key.json")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
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 := &jwt.Config{
|
|
||||||
Email: "xxx@developer.gserviceaccount.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 -passin pass:notasecret -out key.pem -nodes
|
|
||||||
//
|
|
||||||
// The field only supports PEM containers with no passphrase.
|
|
||||||
// The openssl command will convert p12 keys to passphrase-less PEM containers.
|
|
||||||
PrivateKey: []byte("-----BEGIN RSA PRIVATE KEY-----..."),
|
|
||||||
Scopes: []string{
|
|
||||||
"https://www.googleapis.com/auth/bigquery",
|
|
||||||
"https://www.googleapis.com/auth/blogger",
|
|
||||||
},
|
|
||||||
TokenURL: google.JWTTokenURL,
|
|
||||||
// If you would like to impersonate a user, you can
|
|
||||||
// create a transport with a subject. The following GET
|
|
||||||
// request will be made on the behalf of user@example.com.
|
|
||||||
// Optional.
|
|
||||||
Subject: "user@example.com",
|
|
||||||
}
|
|
||||||
// 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("...")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleAppEngineTokenSource() {
|
|
||||||
var req *http.Request // from the ServeHTTP handler
|
|
||||||
ctx := appengine.NewContext(req)
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &oauth2.Transport{
|
|
||||||
Source: google.AppEngineTokenSource(ctx, "https://www.googleapis.com/auth/bigquery"),
|
|
||||||
Base: &urlfetch.Transport{
|
|
||||||
Context: ctx,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
client.Get("...")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleComputeTokenSource() {
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &oauth2.Transport{
|
|
||||||
// Fetch from Google Compute Engine's metadata server to retrieve
|
|
||||||
// an access token for the provided account.
|
|
||||||
// If no account is specified, "default" is used.
|
|
||||||
Source: google.ComputeTokenSource(""),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
client.Get("...")
|
|
||||||
}
|
|
145
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
145
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
@ -1,145 +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 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
|
|
||||||
// and
|
|
||||||
// https://developers.google.com/accounts/application-default-credentials.
|
|
||||||
package google // import "golang.org/x/oauth2/google"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"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.
|
|
||||||
var Endpoint = oauth2.Endpoint{
|
|
||||||
AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
|
||||||
TokenURL: "https://accounts.google.com/o/oauth2/token",
|
|
||||||
}
|
|
||||||
|
|
||||||
// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
|
|
||||||
const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
|
|
||||||
|
|
||||||
// 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(jsonKey []byte, scope ...string) (*jwt.Config, error) {
|
|
||||||
var key struct {
|
|
||||||
Email string `json:"client_email"`
|
|
||||||
PrivateKey string `json:"private_key"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(jsonKey, &key); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &jwt.Config{
|
|
||||||
Email: key.Email,
|
|
||||||
PrivateKey: []byte(key.PrivateKey),
|
|
||||||
Scopes: scope,
|
|
||||||
TokenURL: JWTTokenURL,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputeTokenSource returns a token source that fetches access tokens
|
|
||||||
// from Google Compute Engine (GCE)'s metadata server. It's only valid to use
|
|
||||||
// this token source if your program is running on a GCE instance.
|
|
||||||
// If no account is specified, "default" is used.
|
|
||||||
// Further information about retrieving access tokens from the GCE metadata
|
|
||||||
// server can be found at https://cloud.google.com/compute/docs/authentication.
|
|
||||||
func ComputeTokenSource(account string) oauth2.TokenSource {
|
|
||||||
return oauth2.ReuseTokenSource(nil, computeSource{account: account})
|
|
||||||
}
|
|
||||||
|
|
||||||
type computeSource struct {
|
|
||||||
account string
|
|
||||||
}
|
|
||||||
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
ExpiresInSec int `json:"expires_in"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
}
|
|
||||||
err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res)
|
|
||||||
if err != nil {
|
|
||||||
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: res.AccessToken,
|
|
||||||
TokenType: res.TokenType,
|
|
||||||
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
|
|
||||||
}, nil
|
|
||||||
}
|
|
67
vendor/golang.org/x/oauth2/google/google_test.go
generated
vendored
67
vendor/golang.org/x/oauth2/google/google_test.go
generated
vendored
@ -1,67 +0,0 @@
|
|||||||
// 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
vendor/golang.org/x/oauth2/google/sdk.go
generated
vendored
168
vendor/golang.org/x/oauth2/google/sdk.go
generated
vendored
@ -1,168 +0,0 @@
|
|||||||
// 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
vendor/golang.org/x/oauth2/google/sdk_test.go
generated
vendored
46
vendor/golang.org/x/oauth2/google/sdk_test.go
generated
vendored
@ -1,46 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
122
vendor/golang.org/x/oauth2/google/testdata/gcloud/credentials
generated
vendored
122
vendor/golang.org/x/oauth2/google/testdata/gcloud/credentials
generated
vendored
@ -1,122 +0,0 @@
|
|||||||
{
|
|
||||||
"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
vendor/golang.org/x/oauth2/google/testdata/gcloud/properties
generated
vendored
2
vendor/golang.org/x/oauth2/google/testdata/gcloud/properties
generated
vendored
@ -1,2 +0,0 @@
|
|||||||
[core]
|
|
||||||
account = bar@example.com
|
|
11
vendor/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
11
vendor/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
|||||||
|
|
||||||
func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
|
func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
|
||||||
result := map[string]map[string]string{
|
result := map[string]map[string]string{
|
||||||
"": map[string]string{}, // root section
|
"": {}, // root section
|
||||||
}
|
}
|
||||||
scanner := bufio.NewScanner(ini)
|
scanner := bufio.NewScanner(ini)
|
||||||
currentSection := ""
|
currentSection := ""
|
||||||
@ -67,3 +67,10 @@ func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CondVal(v string) []string {
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []string{v}
|
||||||
|
}
|
||||||
|
62
vendor/golang.org/x/oauth2/internal/oauth2_test.go
generated
vendored
62
vendor/golang.org/x/oauth2/internal/oauth2_test.go
generated
vendored
@ -1,62 +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 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
249
vendor/golang.org/x/oauth2/internal/token.go
generated
vendored
Normal file
249
vendor/golang.org/x/oauth2/internal/token.go
generated
vendored
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
// Copyright 2014 The Go 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token represents the crendentials used to authorize
|
||||||
|
// the requests to access protected resources on the OAuth 2.0
|
||||||
|
// provider's backend.
|
||||||
|
//
|
||||||
|
// This type is a mirror of oauth2.Token and exists to break
|
||||||
|
// an otherwise-circular dependency. Other internal packages
|
||||||
|
// should convert this Token into an oauth2.Token before use.
|
||||||
|
type Token struct {
|
||||||
|
// AccessToken is the token that authorizes and authenticates
|
||||||
|
// the requests.
|
||||||
|
AccessToken string
|
||||||
|
|
||||||
|
// TokenType is the type of token.
|
||||||
|
// The Type method returns either this or "Bearer", the default.
|
||||||
|
TokenType string
|
||||||
|
|
||||||
|
// RefreshToken is a token that's used by the application
|
||||||
|
// (as opposed to the user) to refresh the access token
|
||||||
|
// if it expires.
|
||||||
|
RefreshToken string
|
||||||
|
|
||||||
|
// Expiry is the optional expiration time of the access token.
|
||||||
|
//
|
||||||
|
// If zero, TokenSource implementations will reuse the same
|
||||||
|
// token forever and RefreshToken or equivalent
|
||||||
|
// mechanisms for that TokenSource will not be used.
|
||||||
|
Expiry time.Time
|
||||||
|
|
||||||
|
// Raw optionally contains extra metadata from the server
|
||||||
|
// when updating a token.
|
||||||
|
Raw interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 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) {
|
||||||
|
if v := e.ExpiresIn; v != 0 {
|
||||||
|
return time.Now().Add(time.Duration(v) * time.Second)
|
||||||
|
}
|
||||||
|
if v := e.Expires; v != 0 {
|
||||||
|
return time.Now().Add(time.Duration(v) * time.Second)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
var brokenAuthHeaderProviders = []string{
|
||||||
|
"https://accounts.google.com/",
|
||||||
|
"https://api.codeswholesale.com/oauth/token",
|
||||||
|
"https://api.dropbox.com/",
|
||||||
|
"https://api.dropboxapi.com/",
|
||||||
|
"https://api.instagram.com/",
|
||||||
|
"https://api.netatmo.net/",
|
||||||
|
"https://api.odnoklassniki.ru/",
|
||||||
|
"https://api.pushbullet.com/",
|
||||||
|
"https://api.soundcloud.com/",
|
||||||
|
"https://api.twitch.tv/",
|
||||||
|
"https://app.box.com/",
|
||||||
|
"https://connect.stripe.com/",
|
||||||
|
"https://graph.facebook.com", // see https://github.com/golang/oauth2/issues/214
|
||||||
|
"https://login.microsoftonline.com/",
|
||||||
|
"https://login.salesforce.com/",
|
||||||
|
"https://oauth.sandbox.trainingpeaks.com/",
|
||||||
|
"https://oauth.trainingpeaks.com/",
|
||||||
|
"https://oauth.vk.com/",
|
||||||
|
"https://openapi.baidu.com/",
|
||||||
|
"https://slack.com/",
|
||||||
|
"https://test-sandbox.auth.corp.google.com",
|
||||||
|
"https://test.salesforce.com/",
|
||||||
|
"https://user.gini.net/",
|
||||||
|
"https://www.douban.com/",
|
||||||
|
"https://www.googleapis.com/",
|
||||||
|
"https://www.linkedin.com/",
|
||||||
|
"https://www.strava.com/oauth/",
|
||||||
|
"https://www.wunderlist.com/oauth/",
|
||||||
|
"https://api.patreon.com/",
|
||||||
|
"https://sandbox.codeswholesale.com/oauth/token",
|
||||||
|
"https://api.sipgate.com/v1/authorization/oauth",
|
||||||
|
}
|
||||||
|
|
||||||
|
// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints.
|
||||||
|
var brokenAuthHeaderDomains = []string{
|
||||||
|
".force.com",
|
||||||
|
".myshopify.com",
|
||||||
|
".okta.com",
|
||||||
|
".oktapreview.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
|
||||||
|
brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// In summary:
|
||||||
|
// - 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 {
|
||||||
|
for _, s := range brokenAuthHeaderProviders {
|
||||||
|
if strings.HasPrefix(tokenURL, s) {
|
||||||
|
// Some sites fail to implement the OAuth2 spec fully.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if u, err := url.Parse(tokenURL); err == nil {
|
||||||
|
for _, s := range brokenAuthHeaderDomains {
|
||||||
|
if strings.HasSuffix(u.Host, s) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the provider implements the spec properly
|
||||||
|
// otherwise. We can add more exceptions as they're
|
||||||
|
// discovered. We will _not_ be adding configurable hooks
|
||||||
|
// to this package to let users select server bugs.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
|
||||||
|
hc, err := ContextClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bustedAuth := !providerAuthHeaderWorks(tokenURL)
|
||||||
|
if bustedAuth {
|
||||||
|
if clientID != "" {
|
||||||
|
v.Set("client_id", clientID)
|
||||||
|
}
|
||||||
|
if clientSecret != "" {
|
||||||
|
v.Set("client_secret", clientSecret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
if !bustedAuth {
|
||||||
|
req.SetBasicAuth(clientID, clientSecret)
|
||||||
|
}
|
||||||
|
r, err := hc.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||||
|
}
|
||||||
|
if code := r.StatusCode; code < 200 || code > 299 {
|
||||||
|
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
var token *Token
|
||||||
|
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||||
|
switch content {
|
||||||
|
case "application/x-www-form-urlencoded", "text/plain":
|
||||||
|
vals, err := url.ParseQuery(string(body))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token = &Token{
|
||||||
|
AccessToken: vals.Get("access_token"),
|
||||||
|
TokenType: vals.Get("token_type"),
|
||||||
|
RefreshToken: vals.Get("refresh_token"),
|
||||||
|
Raw: vals,
|
||||||
|
}
|
||||||
|
e := vals.Get("expires_in")
|
||||||
|
if e == "" {
|
||||||
|
// TODO(jbd): Facebook's OAuth2 implementation is broken and
|
||||||
|
// returns expires_in field in expires. Remove the fallback to expires,
|
||||||
|
// when Facebook fixes their implementation.
|
||||||
|
e = vals.Get("expires")
|
||||||
|
}
|
||||||
|
expires, _ := strconv.Atoi(e)
|
||||||
|
if expires != 0 {
|
||||||
|
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
var tj tokenJSON
|
||||||
|
if err = json.Unmarshal(body, &tj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token = &Token{
|
||||||
|
AccessToken: tj.AccessToken,
|
||||||
|
TokenType: tj.TokenType,
|
||||||
|
RefreshToken: tj.RefreshToken,
|
||||||
|
Expiry: tj.expiry(),
|
||||||
|
Raw: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
json.Unmarshal(body, &token.Raw) // no error checks for optional fields
|
||||||
|
}
|
||||||
|
// Don't overwrite `RefreshToken` with an empty value
|
||||||
|
// if this was a token refreshing request.
|
||||||
|
if token.RefreshToken == "" {
|
||||||
|
token.RefreshToken = v.Get("refresh_token")
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
69
vendor/golang.org/x/oauth2/internal/transport.go
generated
vendored
Normal file
69
vendor/golang.org/x/oauth2/internal/transport.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2014 The Go 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 (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPClient is the context key to use with golang.org/x/net/context's
|
||||||
|
// WithValue function to associate an *http.Client value with a context.
|
||||||
|
var HTTPClient ContextKey
|
||||||
|
|
||||||
|
// ContextKey is just an empty struct. It exists so HTTPClient can be
|
||||||
|
// an immutable public variable with a unique type. It's immutable
|
||||||
|
// because nobody else can create a ContextKey, being unexported.
|
||||||
|
type ContextKey struct{}
|
||||||
|
|
||||||
|
// ContextClientFunc is a func which tries to return an *http.Client
|
||||||
|
// 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.Context) (*http.Client, error)
|
||||||
|
|
||||||
|
var contextClientFuncs []ContextClientFunc
|
||||||
|
|
||||||
|
func RegisterContextClientFunc(fn ContextClientFunc) {
|
||||||
|
contextClientFuncs = append(contextClientFuncs, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextClient(ctx context.Context) (*http.Client, error) {
|
||||||
|
if ctx != nil {
|
||||||
|
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
|
||||||
|
return hc, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, fn := range contextClientFuncs {
|
||||||
|
c, err := fn(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c != nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return http.DefaultClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextTransport(ctx context.Context) http.RoundTripper {
|
||||||
|
hc, err := ContextClient(ctx)
|
||||||
|
// This is a rare error case (somebody using nil on App Engine).
|
||||||
|
if err != nil {
|
||||||
|
return ErrorTransport{err}
|
||||||
|
}
|
||||||
|
return hc.Transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorTransport returns the specified error on RoundTrip.
|
||||||
|
// This RoundTripper should be used in rare error cases where
|
||||||
|
// error handling can be postponed to response handling time.
|
||||||
|
type ErrorTransport struct{ Err error }
|
||||||
|
|
||||||
|
func (t ErrorTransport) RoundTrip(*http.Request) (*http.Response, error) {
|
||||||
|
return nil, t.Err
|
||||||
|
}
|
160
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
160
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
@ -1,160 +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 jws provides encoding and decoding utilities for
|
|
||||||
// signed JWS messages.
|
|
||||||
package jws // import "golang.org/x/oauth2/jws"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ClaimSet contains information about the JWT signature including the
|
|
||||||
// permissions being requested (scopes), the target of the token, the issuer,
|
|
||||||
// the time the token was issued, and the lifetime of the token.
|
|
||||||
type ClaimSet struct {
|
|
||||||
Iss string `json:"iss"` // email address of the client_id of the application making the access token request
|
|
||||||
Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
|
|
||||||
Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional).
|
|
||||||
Exp int64 `json:"exp"` // the expiration time of the assertion
|
|
||||||
Iat int64 `json:"iat"` // the time the assertion was issued.
|
|
||||||
Typ string `json:"typ,omitempty"` // token type (Optional).
|
|
||||||
|
|
||||||
// Email for which the application is requesting delegated access (Optional).
|
|
||||||
Sub string `json:"sub,omitempty"`
|
|
||||||
|
|
||||||
// The old name of Sub. Client keeps setting Prn to be
|
|
||||||
// complaint with legacy OAuth 2.0 providers. (Optional)
|
|
||||||
Prn string `json:"prn,omitempty"`
|
|
||||||
|
|
||||||
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
|
|
||||||
// This array is marshalled using custom code (see (c *ClaimSet) encode()).
|
|
||||||
PrivateClaims map[string]interface{} `json:"-"`
|
|
||||||
|
|
||||||
exp time.Time
|
|
||||||
iat time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ClaimSet) encode() (string, error) {
|
|
||||||
if c.exp.IsZero() || c.iat.IsZero() {
|
|
||||||
// Reverting time back for machines whose time is not perfectly in sync.
|
|
||||||
// If client machine's time is in the future according
|
|
||||||
// to Google servers, an access token will not be issued.
|
|
||||||
now := time.Now().Add(-10 * time.Second)
|
|
||||||
c.iat = now
|
|
||||||
c.exp = now.Add(time.Hour)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Exp = c.exp.Unix()
|
|
||||||
c.Iat = c.iat.Unix()
|
|
||||||
|
|
||||||
b, err := json.Marshal(c)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.PrivateClaims) == 0 {
|
|
||||||
return base64Encode(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal private claim set and then append it to b.
|
|
||||||
prv, err := json.Marshal(c.PrivateClaims)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("jws: invalid map of private claims %v", c.PrivateClaims)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concatenate public and private claim JSON objects.
|
|
||||||
if !bytes.HasSuffix(b, []byte{'}'}) {
|
|
||||||
return "", fmt.Errorf("jws: invalid JSON %s", b)
|
|
||||||
}
|
|
||||||
if !bytes.HasPrefix(prv, []byte{'{'}) {
|
|
||||||
return "", fmt.Errorf("jws: invalid JSON %s", prv)
|
|
||||||
}
|
|
||||||
b[len(b)-1] = ',' // Replace closing curly brace with a comma.
|
|
||||||
b = append(b, prv[1:]...) // Append private claims.
|
|
||||||
return base64Encode(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header represents the header for the signed JWS payloads.
|
|
||||||
type Header struct {
|
|
||||||
// The algorithm used for signature.
|
|
||||||
Algorithm string `json:"alg"`
|
|
||||||
|
|
||||||
// Represents the token type.
|
|
||||||
Typ string `json:"typ"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Header) encode() (string, error) {
|
|
||||||
b, err := json.Marshal(h)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return base64Encode(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode decodes a claim set from a JWS payload.
|
|
||||||
func Decode(payload string) (*ClaimSet, error) {
|
|
||||||
// decode returned id token to get expiry
|
|
||||||
s := strings.Split(payload, ".")
|
|
||||||
if len(s) < 2 {
|
|
||||||
// TODO(jbd): Provide more context about the error.
|
|
||||||
return nil, errors.New("jws: invalid token received")
|
|
||||||
}
|
|
||||||
decoded, err := base64Decode(s[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c := &ClaimSet{}
|
|
||||||
err = json.NewDecoder(bytes.NewBuffer(decoded)).Decode(c)
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode encodes a signed JWS with provided header and claim set.
|
|
||||||
func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, error) {
|
|
||||||
head, err := header.encode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
cs, err := c.encode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
ss := fmt.Sprintf("%s.%s", head, cs)
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write([]byte(ss))
|
|
||||||
b, err := rsa.SignPKCS1v15(rand.Reader, signature, crypto.SHA256, h.Sum(nil))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
sig := base64Encode(b)
|
|
||||||
return fmt.Sprintf("%s.%s", ss, sig), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// base64Encode returns and Base64url encoded version of the input string with any
|
|
||||||
// trailing "=" stripped.
|
|
||||||
func base64Encode(b []byte) string {
|
|
||||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
|
|
||||||
}
|
|
||||||
|
|
||||||
// base64Decode decodes the Base64url encoded string
|
|
||||||
func base64Decode(s string) ([]byte, error) {
|
|
||||||
// add back missing padding
|
|
||||||
switch len(s) % 4 {
|
|
||||||
case 2:
|
|
||||||
s += "=="
|
|
||||||
case 3:
|
|
||||||
s += "="
|
|
||||||
}
|
|
||||||
return base64.URLEncoding.DecodeString(s)
|
|
||||||
}
|
|
31
vendor/golang.org/x/oauth2/jwt/example_test.go
generated
vendored
31
vendor/golang.org/x/oauth2/jwt/example_test.go
generated
vendored
@ -1,31 +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 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("...")
|
|
||||||
}
|
|
147
vendor/golang.org/x/oauth2/jwt/jwt.go
generated
vendored
147
vendor/golang.org/x/oauth2/jwt/jwt.go
generated
vendored
@ -1,147 +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 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"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
"golang.org/x/oauth2/internal"
|
|
||||||
"golang.org/x/oauth2/jws"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
defaultGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
|
||||||
defaultHeader = &jws.Header{Algorithm: "RS256", Typ: "JWT"}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// PrivateKey contains the contents of an RSA private key or the
|
|
||||||
// contents of a PEM file that contains a private key. The provided
|
|
||||||
// private key is used to sign JWT payloads.
|
|
||||||
// PEM containers with a passphrase are not supported.
|
|
||||||
// Use the following command to convert a PKCS 12 file into a PEM.
|
|
||||||
//
|
|
||||||
// $ openssl pkcs12 -in key.p12 -out key.pem -nodes
|
|
||||||
//
|
|
||||||
PrivateKey []byte
|
|
||||||
|
|
||||||
// Subject is the optional user to impersonate.
|
|
||||||
Subject string
|
|
||||||
|
|
||||||
// Scopes optionally specifies a list of requested permission scopes.
|
|
||||||
Scopes []string
|
|
||||||
|
|
||||||
// TokenURL is the endpoint required to complete the 2-legged JWT flow.
|
|
||||||
TokenURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenSource returns a JWT TokenSource using the configuration
|
|
||||||
// in c and the HTTP client from the provided context.
|
|
||||||
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 returned client and its Transport should not be modified.
|
|
||||||
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 reuseTokenSource.
|
|
||||||
type jwtSource struct {
|
|
||||||
ctx context.Context
|
|
||||||
conf *Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (js jwtSource) Token() (*oauth2.Token, error) {
|
|
||||||
pk, err := internal.ParseKey(js.conf.PrivateKey)
|
|
||||||
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, " "),
|
|
||||||
Aud: js.conf.TokenURL,
|
|
||||||
}
|
|
||||||
if subject := js.conf.Subject; subject != "" {
|
|
||||||
claimSet.Sub = subject
|
|
||||||
// prn is the old name of sub. Keep setting it
|
|
||||||
// to be compatible with legacy OAuth 2.0 providers.
|
|
||||||
claimSet.Prn = subject
|
|
||||||
}
|
|
||||||
payload, err := jws.Encode(defaultHeader, claimSet, pk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
v := url.Values{}
|
|
||||||
v.Set("grant_type", defaultGrantType)
|
|
||||||
v.Set("assertion", payload)
|
|
||||||
resp, err := hc.PostForm(js.conf.TokenURL, v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
|
||||||
}
|
|
||||||
if c := resp.StatusCode; c < 200 || c > 299 {
|
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", resp.Status, body)
|
|
||||||
}
|
|
||||||
// tokenRes is the JSON response body.
|
|
||||||
var tokenRes struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
IDToken string `json:"id_token"`
|
|
||||||
ExpiresIn int64 `json:"expires_in"` // relative seconds from now
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(body, &tokenRes); err != nil {
|
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
|
||||||
}
|
|
||||||
token := &oauth2.Token{
|
|
||||||
AccessToken: tokenRes.AccessToken,
|
|
||||||
TokenType: tokenRes.TokenType,
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
if v := tokenRes.IDToken; v != "" {
|
|
||||||
// decode returned id token to get expiry
|
|
||||||
claimSet, err := jws.Decode(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oauth2: error decoding JWT token: %v", err)
|
|
||||||
}
|
|
||||||
token.Expiry = time.Unix(claimSet.Exp, 0)
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
}
|
|
134
vendor/golang.org/x/oauth2/jwt/jwt_test.go
generated
vendored
134
vendor/golang.org/x/oauth2/jwt/jwt_test.go
generated
vendored
@ -1,134 +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 jwt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var dummyPrivateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpAIBAAKCAQEAx4fm7dngEmOULNmAs1IGZ9Apfzh+BkaQ1dzkmbUgpcoghucE
|
|
||||||
DZRnAGd2aPyB6skGMXUytWQvNYav0WTR00wFtX1ohWTfv68HGXJ8QXCpyoSKSSFY
|
|
||||||
fuP9X36wBSkSX9J5DVgiuzD5VBdzUISSmapjKm+DcbRALjz6OUIPEWi1Tjl6p5RK
|
|
||||||
1w41qdbmt7E5/kGhKLDuT7+M83g4VWhgIvaAXtnhklDAggilPPa8ZJ1IFe31lNlr
|
|
||||||
k4DRk38nc6sEutdf3RL7QoH7FBusI7uXV03DC6dwN1kP4GE7bjJhcRb/7jYt7CQ9
|
|
||||||
/E9Exz3c0yAp0yrTg0Fwh+qxfH9dKwN52S7SBwIDAQABAoIBAQCaCs26K07WY5Jt
|
|
||||||
3a2Cw3y2gPrIgTCqX6hJs7O5ByEhXZ8nBwsWANBUe4vrGaajQHdLj5OKfsIDrOvn
|
|
||||||
2NI1MqflqeAbu/kR32q3tq8/Rl+PPiwUsW3E6Pcf1orGMSNCXxeducF2iySySzh3
|
|
||||||
nSIhCG5uwJDWI7a4+9KiieFgK1pt/Iv30q1SQS8IEntTfXYwANQrfKUVMmVF9aIK
|
|
||||||
6/WZE2yd5+q3wVVIJ6jsmTzoDCX6QQkkJICIYwCkglmVy5AeTckOVwcXL0jqw5Kf
|
|
||||||
5/soZJQwLEyBoQq7Kbpa26QHq+CJONetPP8Ssy8MJJXBT+u/bSseMb3Zsr5cr43e
|
|
||||||
DJOhwsThAoGBAPY6rPKl2NT/K7XfRCGm1sbWjUQyDShscwuWJ5+kD0yudnT/ZEJ1
|
|
||||||
M3+KS/iOOAoHDdEDi9crRvMl0UfNa8MAcDKHflzxg2jg/QI+fTBjPP5GOX0lkZ9g
|
|
||||||
z6VePoVoQw2gpPFVNPPTxKfk27tEzbaffvOLGBEih0Kb7HTINkW8rIlzAoGBAM9y
|
|
||||||
1yr+jvfS1cGFtNU+Gotoihw2eMKtIqR03Yn3n0PK1nVCDKqwdUqCypz4+ml6cxRK
|
|
||||||
J8+Pfdh7D+ZJd4LEG6Y4QRDLuv5OA700tUoSHxMSNn3q9As4+T3MUyYxWKvTeu3U
|
|
||||||
f2NWP9ePU0lV8ttk7YlpVRaPQmc1qwooBA/z/8AdAoGAW9x0HWqmRICWTBnpjyxx
|
|
||||||
QGlW9rQ9mHEtUotIaRSJ6K/F3cxSGUEkX1a3FRnp6kPLcckC6NlqdNgNBd6rb2rA
|
|
||||||
cPl/uSkZP42Als+9YMoFPU/xrrDPbUhu72EDrj3Bllnyb168jKLa4VBOccUvggxr
|
|
||||||
Dm08I1hgYgdN5huzs7y6GeUCgYEAj+AZJSOJ6o1aXS6rfV3mMRve9bQ9yt8jcKXw
|
|
||||||
5HhOCEmMtaSKfnOF1Ziih34Sxsb7O2428DiX0mV/YHtBnPsAJidL0SdLWIapBzeg
|
|
||||||
KHArByIRkwE6IvJvwpGMdaex1PIGhx5i/3VZL9qiq/ElT05PhIb+UXgoWMabCp84
|
|
||||||
OgxDK20CgYAeaFo8BdQ7FmVX2+EEejF+8xSge6WVLtkaon8bqcn6P0O8lLypoOhd
|
|
||||||
mJAYH8WU+UAy9pecUnDZj14LAGNVmYcse8HFX71MoshnvCTFEPVo4rZxIAGwMpeJ
|
|
||||||
5jgQ3slYLpqrGlcbLgUXBUgzEO684Wk/UV9DFPlHALVqCfXQ9dpJPg==
|
|
||||||
-----END RSA PRIVATE KEY-----`)
|
|
||||||
|
|
||||||
func TestJWTFetch_JSONResponse(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": "90d64460d14870c08c81352a05dedd3465940a7c",
|
|
||||||
"scope": "user",
|
|
||||||
"token_type": "bearer",
|
|
||||||
"expires_in": 3600
|
|
||||||
}`))
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
conf := &Config{
|
|
||||||
Email: "aaa@xxx.com",
|
|
||||||
PrivateKey: dummyPrivateKey,
|
|
||||||
TokenURL: ts.URL,
|
|
||||||
}
|
|
||||||
tok, err := conf.TokenSource(oauth2.NoContext).Token()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !tok.Valid() {
|
|
||||||
t.Errorf("Token invalid")
|
|
||||||
}
|
|
||||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
|
||||||
t.Errorf("Unexpected access token, %#v", tok.AccessToken)
|
|
||||||
}
|
|
||||||
if tok.TokenType != "bearer" {
|
|
||||||
t.Errorf("Unexpected token type, %#v", tok.TokenType)
|
|
||||||
}
|
|
||||||
if tok.Expiry.IsZero() {
|
|
||||||
t.Errorf("Unexpected token expiry, %#v", tok.Expiry)
|
|
||||||
}
|
|
||||||
scope := tok.Extra("scope")
|
|
||||||
if scope != "user" {
|
|
||||||
t.Errorf("Unexpected value for scope: %v", scope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestJWTFetch_BadResponse(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(`{"scope": "user", "token_type": "bearer"}`))
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
conf := &Config{
|
|
||||||
Email: "aaa@xxx.com",
|
|
||||||
PrivateKey: dummyPrivateKey,
|
|
||||||
TokenURL: ts.URL,
|
|
||||||
}
|
|
||||||
tok, err := conf.TokenSource(oauth2.NoContext).Token()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if tok == nil {
|
|
||||||
t.Fatalf("token is nil")
|
|
||||||
}
|
|
||||||
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 want := "user"; scope != want {
|
|
||||||
t.Errorf("token scope = %q; want %q", scope, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestJWTFetch_BadResponseType(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":123, "scope": "user", "token_type": "bearer"}`))
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
conf := &Config{
|
|
||||||
Email: "aaa@xxx.com",
|
|
||||||
PrivateKey: dummyPrivateKey,
|
|
||||||
TokenURL: ts.URL,
|
|
||||||
}
|
|
||||||
tok, err := conf.TokenSource(oauth2.NoContext).Token()
|
|
||||||
if err == nil {
|
|
||||||
t.Error("got a token; expected error")
|
|
||||||
if tok.AccessToken != "" {
|
|
||||||
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
16
vendor/golang.org/x/oauth2/linkedin/linkedin.go
generated
vendored
16
vendor/golang.org/x/oauth2/linkedin/linkedin.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// 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",
|
|
||||||
}
|
|
267
vendor/golang.org/x/oauth2/oauth2.go
generated
vendored
267
vendor/golang.org/x/oauth2/oauth2.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -9,28 +9,38 @@ package oauth2 // import "golang.org/x/oauth2"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NoContext is the default context you should supply if not using
|
// NoContext is the default context you should supply if not using
|
||||||
// your own context.Context (see https://golang.org/x/net/context).
|
// your own context.Context (see https://golang.org/x/net/context).
|
||||||
|
//
|
||||||
|
// Deprecated: Use context.Background() or context.TODO() instead.
|
||||||
var NoContext = context.TODO()
|
var NoContext = context.TODO()
|
||||||
|
|
||||||
|
// RegisterBrokenAuthHeaderProvider registers an OAuth2 server
|
||||||
|
// identified by the tokenURL prefix as an OAuth2 implementation
|
||||||
|
// which doesn't support the HTTP Basic authentication
|
||||||
|
// scheme to authenticate with the authorization server.
|
||||||
|
// Once a server is registered, credentials (client_id and client_secret)
|
||||||
|
// will be passed as query parameters rather than being present
|
||||||
|
// in the Authorization header.
|
||||||
|
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
|
||||||
|
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
|
||||||
|
internal.RegisterBrokenAuthHeaderProvider(tokenURL)
|
||||||
|
}
|
||||||
|
|
||||||
// Config describes a typical 3-legged OAuth2 flow, with both the
|
// Config describes a typical 3-legged OAuth2 flow, with both the
|
||||||
// client application information and the server's endpoint URLs.
|
// client application information and the server's endpoint URLs.
|
||||||
|
// For the client credentials 2-legged OAuth2 flow, see the clientcredentials
|
||||||
|
// package (https://golang.org/x/oauth2/clientcredentials).
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// ClientID is the application's ID.
|
// ClientID is the application's ID.
|
||||||
ClientID string
|
ClientID string
|
||||||
@ -79,13 +89,13 @@ var (
|
|||||||
// result in your application obtaining a refresh token the
|
// result in your application obtaining a refresh token the
|
||||||
// first time your application exchanges an authorization
|
// first time your application exchanges an authorization
|
||||||
// code for a user.
|
// code for a user.
|
||||||
AccessTypeOnline AuthCodeOption = SetParam("access_type", "online")
|
AccessTypeOnline AuthCodeOption = SetAuthURLParam("access_type", "online")
|
||||||
AccessTypeOffline AuthCodeOption = SetParam("access_type", "offline")
|
AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline")
|
||||||
|
|
||||||
// ApprovalForce forces the users to view the consent dialog
|
// ApprovalForce forces the users to view the consent dialog
|
||||||
// and confirm the permissions request at the URL returned
|
// and confirm the permissions request at the URL returned
|
||||||
// from AuthCodeURL, even if they've already done so.
|
// from AuthCodeURL, even if they've already done so.
|
||||||
ApprovalForce AuthCodeOption = SetParam("approval_prompt", "force")
|
ApprovalForce AuthCodeOption = SetAuthURLParam("approval_prompt", "force")
|
||||||
)
|
)
|
||||||
|
|
||||||
// An AuthCodeOption is passed to Config.AuthCodeURL.
|
// An AuthCodeOption is passed to Config.AuthCodeURL.
|
||||||
@ -97,9 +107,9 @@ type setParam struct{ k, v string }
|
|||||||
|
|
||||||
func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) }
|
func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) }
|
||||||
|
|
||||||
// SetParam builds an AuthCodeOption which passes key/value parameters
|
// SetAuthURLParam builds an AuthCodeOption which passes key/value parameters
|
||||||
// to a provider's authorization endpoint.
|
// to a provider's authorization endpoint.
|
||||||
func SetParam(key, value string) AuthCodeOption {
|
func SetAuthURLParam(key, value string) AuthCodeOption {
|
||||||
return setParam{key, value}
|
return setParam{key, value}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +129,9 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
|
|||||||
v := url.Values{
|
v := url.Values{
|
||||||
"response_type": {"code"},
|
"response_type": {"code"},
|
||||||
"client_id": {c.ClientID},
|
"client_id": {c.ClientID},
|
||||||
"redirect_uri": condVal(c.RedirectURL),
|
"redirect_uri": internal.CondVal(c.RedirectURL),
|
||||||
"scope": condVal(strings.Join(c.Scopes, " ")),
|
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
|
||||||
"state": condVal(state),
|
"state": internal.CondVal(state),
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt.setValue(v)
|
opt.setValue(v)
|
||||||
@ -151,7 +161,7 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
|
|||||||
"grant_type": {"password"},
|
"grant_type": {"password"},
|
||||||
"username": {username},
|
"username": {username},
|
||||||
"password": {password},
|
"password": {password},
|
||||||
"scope": condVal(strings.Join(c.Scopes, " ")),
|
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,51 +179,10 @@ func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) {
|
|||||||
return retrieveToken(ctx, c, url.Values{
|
return retrieveToken(ctx, c, url.Values{
|
||||||
"grant_type": {"authorization_code"},
|
"grant_type": {"authorization_code"},
|
||||||
"code": {code},
|
"code": {code},
|
||||||
"redirect_uri": condVal(c.RedirectURL),
|
"redirect_uri": internal.CondVal(c.RedirectURL),
|
||||||
"scope": condVal(strings.Join(c.Scopes, " ")),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// contextClientFunc is a func which tries to return an *http.Client
|
|
||||||
// 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.Context) (*http.Client, error)
|
|
||||||
|
|
||||||
var contextClientFuncs []contextClientFunc
|
|
||||||
|
|
||||||
func registerContextClientFunc(fn contextClientFunc) {
|
|
||||||
contextClientFuncs = append(contextClientFuncs, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func contextClient(ctx context.Context) (*http.Client, error) {
|
|
||||||
for _, fn := range contextClientFuncs {
|
|
||||||
c, err := fn(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if c != nil {
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
|
|
||||||
return hc, nil
|
|
||||||
}
|
|
||||||
return http.DefaultClient, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
// so I'd rather not everybody do an error check on this Client
|
|
||||||
// method. They can get the error that they're doing it wrong
|
|
||||||
// later, at client.Get/PostForm time.
|
|
||||||
return errorTransport{err}
|
|
||||||
}
|
|
||||||
return hc.Transport
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client returns an HTTP client using the provided token.
|
// Client returns an HTTP client using the provided token.
|
||||||
// The token will auto-refresh as necessary. The underlying
|
// The token will auto-refresh as necessary. The underlying
|
||||||
// HTTP transport will be obtained using the provided context.
|
// HTTP transport will be obtained using the provided context.
|
||||||
@ -299,177 +268,25 @@ func (s *reuseTokenSource) Token() (*Token, error) {
|
|||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
|
// StaticTokenSource returns a TokenSource that always returns the same token.
|
||||||
hc, err := contextClient(ctx)
|
// Because the provided token t is never refreshed, StaticTokenSource is only
|
||||||
if err != nil {
|
// useful for tokens that never expire.
|
||||||
return nil, err
|
func StaticTokenSource(t *Token) TokenSource {
|
||||||
}
|
return staticTokenSource{t}
|
||||||
v.Set("client_id", c.ClientID)
|
|
||||||
bustedAuth := !providerAuthHeaderWorks(c.Endpoint.TokenURL)
|
|
||||||
if bustedAuth && c.ClientSecret != "" {
|
|
||||||
v.Set("client_secret", c.ClientSecret)
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest("POST", c.Endpoint.TokenURL, strings.NewReader(v.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
if !bustedAuth {
|
|
||||||
req.SetBasicAuth(c.ClientID, c.ClientSecret)
|
|
||||||
}
|
|
||||||
r, err := hc.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer r.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
|
||||||
}
|
|
||||||
if code := r.StatusCode; code < 200 || code > 299 {
|
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
var token *Token
|
|
||||||
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
|
||||||
switch content {
|
|
||||||
case "application/x-www-form-urlencoded", "text/plain":
|
|
||||||
vals, err := url.ParseQuery(string(body))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
token = &Token{
|
|
||||||
AccessToken: vals.Get("access_token"),
|
|
||||||
TokenType: vals.Get("token_type"),
|
|
||||||
RefreshToken: vals.Get("refresh_token"),
|
|
||||||
raw: vals,
|
|
||||||
}
|
|
||||||
e := vals.Get("expires_in")
|
|
||||||
if e == "" {
|
|
||||||
// TODO(jbd): Facebook's OAuth2 implementation is broken and
|
|
||||||
// returns expires_in field in expires. Remove the fallback to expires,
|
|
||||||
// when Facebook fixes their implementation.
|
|
||||||
e = vals.Get("expires")
|
|
||||||
}
|
|
||||||
expires, _ := strconv.Atoi(e)
|
|
||||||
if expires != 0 {
|
|
||||||
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
var tj tokenJSON
|
|
||||||
if err = json.Unmarshal(body, &tj); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
token = &Token{
|
|
||||||
AccessToken: tj.AccessToken,
|
|
||||||
TokenType: tj.TokenType,
|
|
||||||
RefreshToken: tj.RefreshToken,
|
|
||||||
Expiry: tj.expiry(),
|
|
||||||
raw: make(map[string]interface{}),
|
|
||||||
}
|
|
||||||
json.Unmarshal(body, &token.raw) // no error checks for optional fields
|
|
||||||
}
|
|
||||||
// Don't overwrite `RefreshToken` with an empty value
|
|
||||||
// if this was a token refreshing request.
|
|
||||||
if token.RefreshToken == "" {
|
|
||||||
token.RefreshToken = v.Get("refresh_token")
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tokenJSON is the struct representing the HTTP response from OAuth2
|
// staticTokenSource is a TokenSource that always returns the same Token.
|
||||||
// providers returning a token in JSON form.
|
type staticTokenSource struct {
|
||||||
type tokenJSON struct {
|
t *Token
|
||||||
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) {
|
func (s staticTokenSource) Token() (*Token, error) {
|
||||||
if v := e.ExpiresIn; v != 0 {
|
return s.t, nil
|
||||||
return time.Now().Add(time.Duration(v) * time.Second)
|
|
||||||
}
|
|
||||||
if v := e.Expires; v != 0 {
|
|
||||||
return time.Now().Add(time.Duration(v) * time.Second)
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
// In summary:
|
|
||||||
// - 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 {
|
|
||||||
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
|
|
||||||
// otherwise. We can add more exceptions as they're
|
|
||||||
// discovered. We will _not_ be adding configurable hooks
|
|
||||||
// to this package to let users select server bugs.
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPClient is the context key to use with golang.org/x/net/context's
|
// HTTPClient is the context key to use with golang.org/x/net/context's
|
||||||
// WithValue function to associate an *http.Client value with a context.
|
// WithValue function to associate an *http.Client value with a context.
|
||||||
var HTTPClient contextKey
|
var HTTPClient internal.ContextKey
|
||||||
|
|
||||||
// contextKey is just an empty struct. It exists so HTTPClient can be
|
|
||||||
// an immutable public variable with a unique type. It's immutable
|
|
||||||
// because nobody else can create a contextKey, being unexported.
|
|
||||||
type contextKey struct{}
|
|
||||||
|
|
||||||
// NewClient creates an *http.Client from a Context and TokenSource.
|
// NewClient creates an *http.Client from a Context and TokenSource.
|
||||||
// The returned client is not valid beyond the lifetime of the context.
|
// The returned client is not valid beyond the lifetime of the context.
|
||||||
@ -479,15 +296,15 @@ type contextKey struct{}
|
|||||||
// packages.
|
// packages.
|
||||||
func NewClient(ctx context.Context, src TokenSource) *http.Client {
|
func NewClient(ctx context.Context, src TokenSource) *http.Client {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
c, err := contextClient(ctx)
|
c, err := internal.ContextClient(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &http.Client{Transport: errorTransport{err}}
|
return &http.Client{Transport: internal.ErrorTransport{Err: err}}
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Transport: &Transport{
|
Transport: &Transport{
|
||||||
Base: contextTransport(ctx),
|
Base: internal.ContextTransport(ctx),
|
||||||
Source: ReuseTokenSource(nil, src),
|
Source: ReuseTokenSource(nil, src),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
439
vendor/golang.org/x/oauth2/oauth2_test.go
generated
vendored
439
vendor/golang.org/x/oauth2/oauth2_test.go
generated
vendored
@ -1,439 +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 oauth2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mockTransport struct {
|
|
||||||
rt func(req *http.Request) (resp *http.Response, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *mockTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
|
||||||
return t.rt(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
type mockCache struct {
|
|
||||||
token *Token
|
|
||||||
readErr error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *mockCache) ReadToken() (*Token, error) {
|
|
||||||
return c.token, c.readErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *mockCache) WriteToken(*Token) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
func newConf(url string) *Config {
|
|
||||||
return &Config{
|
|
||||||
ClientID: "CLIENT_ID",
|
|
||||||
ClientSecret: "CLIENT_SECRET",
|
|
||||||
RedirectURL: "REDIRECT_URL",
|
|
||||||
Scopes: []string{"scope1", "scope2"},
|
|
||||||
Endpoint: Endpoint{
|
|
||||||
AuthURL: url + "/auth",
|
|
||||||
TokenURL: url + "/token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAuthCodeURL(t *testing.T) {
|
|
||||||
conf := newConf("server")
|
|
||||||
url := conf.AuthCodeURL("foo", AccessTypeOffline, ApprovalForce)
|
|
||||||
if url != "server/auth?access_type=offline&approval_prompt=force&client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=foo" {
|
|
||||||
t.Errorf("Auth code URL doesn't match the expected, found: %v", url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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",
|
|
||||||
Endpoint: Endpoint{
|
|
||||||
AuthURL: "/auth-url",
|
|
||||||
TokenURL: "/token-url",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
url := conf.AuthCodeURL("")
|
|
||||||
if url != "/auth-url?client_id=CLIENT_ID&response_type=code" {
|
|
||||||
t.Fatalf("Auth code URL doesn't match the expected, found: %v", url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExchangeRequest(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.URL.String() != "/token" {
|
|
||||||
t.Errorf("Unexpected exchange request URL, %v is found.", r.URL)
|
|
||||||
}
|
|
||||||
headerAuth := r.Header.Get("Authorization")
|
|
||||||
if headerAuth != "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" {
|
|
||||||
t.Errorf("Unexpected authorization header, %v is found.", headerAuth)
|
|
||||||
}
|
|
||||||
headerContentType := r.Header.Get("Content-Type")
|
|
||||||
if headerContentType != "application/x-www-form-urlencoded" {
|
|
||||||
t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType)
|
|
||||||
}
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed reading request body: %s.", err)
|
|
||||||
}
|
|
||||||
if string(body) != "client_id=CLIENT_ID&code=exchange-code&grant_type=authorization_code&redirect_uri=REDIRECT_URL&scope=scope1+scope2" {
|
|
||||||
t.Errorf("Unexpected exchange payload, %v is found.", string(body))
|
|
||||||
}
|
|
||||||
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.Exchange(NoContext, "exchange-code")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
if !tok.Valid() {
|
|
||||||
t.Fatalf("Token invalid. Got: %#v", tok)
|
|
||||||
}
|
|
||||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
|
||||||
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
|
||||||
}
|
|
||||||
if tok.TokenType != "bearer" {
|
|
||||||
t.Errorf("Unexpected token type, %#v.", tok.TokenType)
|
|
||||||
}
|
|
||||||
scope := tok.Extra("scope")
|
|
||||||
if scope != "user" {
|
|
||||||
t.Errorf("Unexpected value for scope: %v", scope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExchangeRequest_JSONResponse(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.URL.String() != "/token" {
|
|
||||||
t.Errorf("Unexpected exchange request URL, %v is found.", r.URL)
|
|
||||||
}
|
|
||||||
headerAuth := r.Header.Get("Authorization")
|
|
||||||
if headerAuth != "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" {
|
|
||||||
t.Errorf("Unexpected authorization header, %v is found.", headerAuth)
|
|
||||||
}
|
|
||||||
headerContentType := r.Header.Get("Content-Type")
|
|
||||||
if headerContentType != "application/x-www-form-urlencoded" {
|
|
||||||
t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType)
|
|
||||||
}
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed reading request body: %s.", err)
|
|
||||||
}
|
|
||||||
if string(body) != "client_id=CLIENT_ID&code=exchange-code&grant_type=authorization_code&redirect_uri=REDIRECT_URL&scope=scope1+scope2" {
|
|
||||||
t.Errorf("Unexpected exchange payload, %v is found.", string(body))
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.Write([]byte(`{"access_token": "90d64460d14870c08c81352a05dedd3465940a7c", "scope": "user", "token_type": "bearer", "expires_in": 86400}`))
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
conf := newConf(ts.URL)
|
|
||||||
tok, err := conf.Exchange(NoContext, "exchange-code")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
if !tok.Valid() {
|
|
||||||
t.Fatalf("Token invalid. Got: %#v", tok)
|
|
||||||
}
|
|
||||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
|
||||||
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
|
||||||
}
|
|
||||||
if tok.TokenType != "bearer" {
|
|
||||||
t.Errorf("Unexpected token type, %#v.", tok.TokenType)
|
|
||||||
}
|
|
||||||
scope := tok.Extra("scope")
|
|
||||||
if scope != "user" {
|
|
||||||
t.Errorf("Unexpected value for scope: %v", scope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
w.Write([]byte(`{"scope": "user", "token_type": "bearer"}`))
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
conf := newConf(ts.URL)
|
|
||||||
tok, err := conf.Exchange(NoContext, "code")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if tok.AccessToken != "" {
|
|
||||||
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExchangeRequest_BadResponseType(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":123, "scope": "user", "token_type": "bearer"}`))
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
conf := newConf(ts.URL)
|
|
||||||
_, err := conf.Exchange(NoContext, "exchange-code")
|
|
||||||
if err == nil {
|
|
||||||
t.Error("expected error from invalid access_token type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExchangeRequest_NonBasicAuth(t *testing.T) {
|
|
||||||
tr := &mockTransport{
|
|
||||||
rt: func(r *http.Request) (w *http.Response, err error) {
|
|
||||||
headerAuth := r.Header.Get("Authorization")
|
|
||||||
if headerAuth != "" {
|
|
||||||
t.Errorf("Unexpected authorization header, %v is found.", headerAuth)
|
|
||||||
}
|
|
||||||
return nil, errors.New("no response")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
c := &http.Client{Transport: tr}
|
|
||||||
conf := &Config{
|
|
||||||
ClientID: "CLIENT_ID",
|
|
||||||
Endpoint: Endpoint{
|
|
||||||
AuthURL: "https://accounts.google.com/auth",
|
|
||||||
TokenURL: "https://accounts.google.com/token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.WithValue(context.Background(), HTTPClient, c)
|
|
||||||
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" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r.URL.String() != "/token" {
|
|
||||||
t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL)
|
|
||||||
}
|
|
||||||
headerContentType := r.Header.Get("Content-Type")
|
|
||||||
if headerContentType != "application/x-www-form-urlencoded" {
|
|
||||||
t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType)
|
|
||||||
}
|
|
||||||
body, _ := ioutil.ReadAll(r.Body)
|
|
||||||
if string(body) != "client_id=CLIENT_ID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN" {
|
|
||||||
t.Errorf("Unexpected refresh token payload, %v is found.", string(body))
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
conf := newConf(ts.URL)
|
|
||||||
c := conf.Client(NoContext, &Token{RefreshToken: "REFRESH_TOKEN"})
|
|
||||||
c.Get(ts.URL + "/somethingelse")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchWithNoRefreshToken(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.URL.String() == "/somethingelse" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r.URL.String() != "/token" {
|
|
||||||
t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL)
|
|
||||||
}
|
|
||||||
headerContentType := r.Header.Get("Content-Type")
|
|
||||||
if headerContentType != "application/x-www-form-urlencoded" {
|
|
||||||
t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType)
|
|
||||||
}
|
|
||||||
body, _ := ioutil.ReadAll(r.Body)
|
|
||||||
if string(body) != "client_id=CLIENT_ID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN" {
|
|
||||||
t.Errorf("Unexpected refresh token payload, %v is found.", string(body))
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
conf := newConf(ts.URL)
|
|
||||||
c := conf.Client(NoContext, nil)
|
|
||||||
_, err := c.Get(ts.URL + "/somethingelse")
|
|
||||||
if err == nil {
|
|
||||||
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
vendor/golang.org/x/oauth2/odnoklassniki/odnoklassniki.go
generated
vendored
16
vendor/golang.org/x/oauth2/odnoklassniki/odnoklassniki.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// 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
vendor/golang.org/x/oauth2/paypal/paypal.go
generated
vendored
22
vendor/golang.org/x/oauth2/paypal/paypal.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// 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",
|
|
||||||
}
|
|
66
vendor/golang.org/x/oauth2/token.go
generated
vendored
66
vendor/golang.org/x/oauth2/token.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -7,7 +7,12 @@ package oauth2
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/oauth2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// expiryDelta determines how earlier a token should be considered
|
// expiryDelta determines how earlier a token should be considered
|
||||||
@ -50,6 +55,15 @@ type Token struct {
|
|||||||
|
|
||||||
// Type returns t.TokenType if non-empty, else "Bearer".
|
// Type returns t.TokenType if non-empty, else "Bearer".
|
||||||
func (t *Token) Type() string {
|
func (t *Token) Type() string {
|
||||||
|
if strings.EqualFold(t.TokenType, "bearer") {
|
||||||
|
return "Bearer"
|
||||||
|
}
|
||||||
|
if strings.EqualFold(t.TokenType, "mac") {
|
||||||
|
return "MAC"
|
||||||
|
}
|
||||||
|
if strings.EqualFold(t.TokenType, "basic") {
|
||||||
|
return "Basic"
|
||||||
|
}
|
||||||
if t.TokenType != "" {
|
if t.TokenType != "" {
|
||||||
return t.TokenType
|
return t.TokenType
|
||||||
}
|
}
|
||||||
@ -79,14 +93,28 @@ func (t *Token) WithExtra(extra interface{}) *Token {
|
|||||||
// Extra fields are key-value pairs returned by the server as a
|
// Extra fields are key-value pairs returned by the server as a
|
||||||
// part of the token retrieval response.
|
// part of the token retrieval response.
|
||||||
func (t *Token) Extra(key string) interface{} {
|
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 raw, ok := t.raw.(map[string]interface{}); ok {
|
||||||
return raw[key]
|
return raw[key]
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
vals, ok := t.raw.(url.Values)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v := vals.Get(key)
|
||||||
|
switch s := strings.TrimSpace(v); strings.Count(s, ".") {
|
||||||
|
case 0: // Contains no "."; try to parse as int
|
||||||
|
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
case 1: // Contains a single "."; try to parse as float
|
||||||
|
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// expired reports whether the token is expired.
|
// expired reports whether the token is expired.
|
||||||
@ -102,3 +130,29 @@ func (t *Token) expired() bool {
|
|||||||
func (t *Token) Valid() bool {
|
func (t *Token) Valid() bool {
|
||||||
return t != nil && t.AccessToken != "" && !t.expired()
|
return t != nil && t.AccessToken != "" && !t.expired()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tokenFromInternal maps an *internal.Token struct into
|
||||||
|
// a *Token struct.
|
||||||
|
func tokenFromInternal(t *internal.Token) *Token {
|
||||||
|
if t == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Token{
|
||||||
|
AccessToken: t.AccessToken,
|
||||||
|
TokenType: t.TokenType,
|
||||||
|
RefreshToken: t.RefreshToken,
|
||||||
|
Expiry: t.Expiry,
|
||||||
|
raw: t.Raw,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieveToken takes a *Config and uses that to retrieve an *internal.Token.
|
||||||
|
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
|
||||||
|
// with an error..
|
||||||
|
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
|
||||||
|
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tokenFromInternal(tk), nil
|
||||||
|
}
|
||||||
|
50
vendor/golang.org/x/oauth2/token_test.go
generated
vendored
50
vendor/golang.org/x/oauth2/token_test.go
generated
vendored
@ -1,50 +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 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
8
vendor/golang.org/x/oauth2/transport.go
generated
vendored
8
vendor/golang.org/x/oauth2/transport.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -130,9 +130,3 @@ func (r *onEOFReader) runFunc() {
|
|||||||
r.fn = nil
|
r.fn = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type errorTransport struct{ err error }
|
|
||||||
|
|
||||||
func (t errorTransport) RoundTrip(*http.Request) (*http.Response, error) {
|
|
||||||
return nil, t.err
|
|
||||||
}
|
|
||||||
|
53
vendor/golang.org/x/oauth2/transport_test.go
generated
vendored
53
vendor/golang.org/x/oauth2/transport_test.go
generated
vendored
@ -1,53 +0,0 @@
|
|||||||
package oauth2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tokenSource struct{ token *Token }
|
|
||||||
|
|
||||||
func (t *tokenSource) Token() (*Token, error) {
|
|
||||||
return t.token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTransportTokenSource(t *testing.T) {
|
|
||||||
ts := &tokenSource{
|
|
||||||
token: &Token{
|
|
||||||
AccessToken: "abc",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
tr := &Transport{
|
|
||||||
Source: ts,
|
|
||||||
}
|
|
||||||
server := newMockServer(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Header.Get("Authorization") != "Bearer abc" {
|
|
||||||
t.Errorf("Transport doesn't set the Authorization header from the fetched token")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
defer server.Close()
|
|
||||||
client := http.Client{Transport: tr}
|
|
||||||
client.Get(server.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTokenValidNoAccessToken(t *testing.T) {
|
|
||||||
token := &Token{}
|
|
||||||
if token.Valid() {
|
|
||||||
t.Errorf("Token should not be valid with no access token")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExpiredWithExpiry(t *testing.T) {
|
|
||||||
token := &Token{
|
|
||||||
Expiry: time.Now().Add(-5 * time.Hour),
|
|
||||||
}
|
|
||||||
if token.Valid() {
|
|
||||||
t.Errorf("Token should not be valid if it expired in the past")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMockServer(handler func(w http.ResponseWriter, r *http.Request)) *httptest.Server {
|
|
||||||
return httptest.NewServer(http.HandlerFunc(handler))
|
|
||||||
}
|
|
16
vendor/golang.org/x/oauth2/vk/vk.go
generated
vendored
16
vendor/golang.org/x/oauth2/vk/vk.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// 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",
|
|
||||||
}
|
|
12
vendor/vendor.json
vendored
12
vendor/vendor.json
vendored
@ -518,6 +518,18 @@
|
|||||||
"revision": "4971afdc2f162e82d185353533d3cf16188a9f4e",
|
"revision": "4971afdc2f162e82d185353533d3cf16188a9f4e",
|
||||||
"revisionTime": "2016-11-15T21:05:04Z"
|
"revisionTime": "2016-11-15T21:05:04Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "SjCoL7KD7qBmgSuqGTCAuUhigDk=",
|
||||||
|
"path": "golang.org/x/oauth2",
|
||||||
|
"revision": "f047394b6d14284165300fd82dad67edb3a4d7f6",
|
||||||
|
"revisionTime": "2017-05-17T17:14:19Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "Umx4Fmn5FyXJyUVzKWhnQdvFNkc=",
|
||||||
|
"path": "golang.org/x/oauth2/internal",
|
||||||
|
"revision": "f047394b6d14284165300fd82dad67edb3a4d7f6",
|
||||||
|
"revisionTime": "2017-05-17T17:14:19Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "S0DP7Pn7sZUmXc55IzZnNvERu6s=",
|
"checksumSHA1": "S0DP7Pn7sZUmXc55IzZnNvERu6s=",
|
||||||
"path": "golang.org/x/sync/errgroup",
|
"path": "golang.org/x/sync/errgroup",
|
||||||
|
Loading…
Reference in New Issue
Block a user