1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-08-01 17:38:37 +00:00

Update vendor dependencies

This commit is contained in:
Frédéric Guillot 2018-07-06 21:18:14 -07:00
parent 34a3fe426b
commit 459bb4531f
747 changed files with 89857 additions and 39711 deletions

View file

@ -4,16 +4,15 @@ Go is an open source project.
It is the work of hundreds of contributors. We appreciate your help!
## Filing issues
When [filing an issue](https://github.com/golang/oauth2/issues), make sure to answer these five questions:
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
@ -23,9 +22,5 @@ The gophers there will answer or ask you to file an issue if you've tripped over
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
before sending patches.
**We do not accept GitHub pull requests**
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
Unless otherwise noted, the Go source files are distributed under
the BSD-style license found in the LICENSE file.

16
vendor/golang.org/x/oauth2/cern/cern.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 cern provides constants for using OAuth2 to access CERN services.
package cern // import "golang.org/x/oauth2/cern"
import (
"golang.org/x/oauth2"
)
// Endpoint is CERN's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://oauth.web.cern.ch/OAuth/Authorize",
TokenURL: "https://oauth.web.cern.ch/OAuth/Token",
}

View file

@ -1,25 +0,0 @@
// 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.
// +build appengine
// App Engine hooks.
package oauth2
import (
"net/http"
"golang.org/x/net/context"
"golang.org/x/oauth2/internal"
"google.golang.org/appengine/urlfetch"
)
func init() {
internal.RegisterContextClientFunc(contextClientAppEngine)
}
func contextClientAppEngine(ctx context.Context) (*http.Client, error) {
return urlfetch.Client(ctx), nil
}

View file

@ -82,7 +82,9 @@ type tokenSource struct {
func (c *tokenSource) Token() (*oauth2.Token, error) {
v := url.Values{
"grant_type": {"client_credentials"},
"scope": internal.CondVal(strings.Join(c.conf.Scopes, " ")),
}
if len(c.conf.Scopes) > 0 {
v.Set("scope", strings.Join(c.conf.Scopes, " "))
}
for k, p := range c.conf.EndpointParams {
if _, ok := v[k]; ok {
@ -92,6 +94,9 @@ func (c *tokenSource) Token() (*oauth2.Token, error) {
}
tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v)
if err != nil {
if rErr, ok := err.(*internal.RetrieveError); ok {
return nil, (*oauth2.RetrieveError)(rErr)
}
return nil, err
}
t := &oauth2.Token{

16
vendor/golang.org/x/oauth2/gitlab/gitlab.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 gitlab provides constants for using OAuth2 to access GitLab.
package gitlab // import "golang.org/x/oauth2/gitlab"
import (
"golang.org/x/oauth2"
)
// Endpoint is GitLab's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://gitlab.com/oauth/authorize",
TokenURL: "https://gitlab.com/oauth/token",
}

View file

@ -18,20 +18,6 @@ import (
"golang.org/x/oauth2"
)
// DefaultCredentials holds "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type DefaultCredentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// DefaultClient returns an HTTP Client that uses the
// DefaultTokenSource to obtain authentication credentials.
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
@ -53,25 +39,12 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
return creds.TokenSource, nil
}
// FindDefaultCredentials searches for "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 and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scope ...string) (*DefaultCredentials, error) {
// Common implementation for FindDefaultCredentials.
func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCredentials, error) {
// First, try the environment variable.
const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
if filename := os.Getenv(envVar); filename != "" {
creds, err := readCredentialsFile(ctx, filename, scope)
creds, err := readCredentialsFile(ctx, filename, scopes)
if err != nil {
return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
}
@ -80,7 +53,7 @@ func FindDefaultCredentials(ctx context.Context, scope ...string) (*DefaultCrede
// Second, try a well-known file.
filename := wellKnownFile()
if creds, err := readCredentialsFile(ctx, filename, scope); err == nil {
if creds, err := readCredentialsFile(ctx, filename, scopes); err == nil {
return creds, nil
} else if !os.IsNotExist(err) {
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
@ -90,7 +63,7 @@ func FindDefaultCredentials(ctx context.Context, scope ...string) (*DefaultCrede
if appengineTokenFunc != nil && !appengineFlex {
return &DefaultCredentials{
ProjectID: appengineAppIDFunc(ctx),
TokenSource: AppEngineTokenSource(ctx, scope...),
TokenSource: AppEngineTokenSource(ctx, scopes...),
}, nil
}
@ -108,6 +81,23 @@ func FindDefaultCredentials(ctx context.Context, scope ...string) (*DefaultCrede
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
}
// Common implementation for CredentialsFromJSON.
func credentialsFromJSON(ctx context.Context, jsonData []byte, scopes []string) (*DefaultCredentials, error) {
var f credentialsFile
if err := json.Unmarshal(jsonData, &f); err != nil {
return nil, err
}
ts, err := f.tokenSource(ctx, append([]string(nil), scopes...))
if err != nil {
return nil, err
}
return &DefaultCredentials{
ProjectID: f.ProjectID,
TokenSource: ts,
JSON: jsonData,
}, nil
}
func wellKnownFile() string {
const f = "application_default_credentials.json"
if runtime.GOOS == "windows" {
@ -121,17 +111,5 @@ func readCredentialsFile(ctx context.Context, filename string, scopes []string)
if err != nil {
return nil, err
}
var f credentialsFile
if err := json.Unmarshal(b, &f); err != nil {
return nil, err
}
ts, err := f.tokenSource(ctx, append([]string(nil), scopes...))
if err != nil {
return nil, err
}
return &DefaultCredentials{
ProjectID: f.ProjectID,
TokenSource: ts,
JSON: b,
}, nil
return CredentialsFromJSON(ctx, b, scopes...)
}

42
vendor/golang.org/x/oauth2/google/doc_go19.go generated vendored Normal file
View file

@ -0,0 +1,42 @@
// Copyright 2018 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.
// +build go1.9
// 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.
//
// A brief overview of the package follows. For more information, please read
// https://developers.google.com/accounts/docs/OAuth2
// and
// https://developers.google.com/accounts/docs/application-default-credentials.
//
// OAuth2 Configs
//
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
// create an http.Client.
//
//
// Credentials
//
// The Credentials type represents Google credentials, including Application Default
// Credentials.
//
// Use FindDefaultCredentials to obtain Application Default Credentials.
// FindDefaultCredentials looks in some well-known places for a credentials file, and
// will call AppEngineTokenSource or ComputeTokenSource as needed.
//
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
//
// Use CredentialsFromJSON to obtain credentials from either of the two JSON formats
// described in OAuth2 Configs, above. The TokenSource in the returned value is the
// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or
// JWTConfigFromJSON, but the Credentials may contain additional information
// that is useful is some circumstances.
package google // import "golang.org/x/oauth2/google"

43
vendor/golang.org/x/oauth2/google/doc_not_go19.go generated vendored Normal file
View file

@ -0,0 +1,43 @@
// Copyright 2018 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.
// +build !go1.9
// 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.
//
// A brief overview of the package follows. For more information, please read
// https://developers.google.com/accounts/docs/OAuth2
// and
// https://developers.google.com/accounts/docs/application-default-credentials.
//
// OAuth2 Configs
//
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
// create an http.Client.
//
//
// Credentials
//
// The DefaultCredentials type represents Google Application Default Credentials, as
// well as other forms of credential.
//
// Use FindDefaultCredentials to obtain Application Default Credentials.
// FindDefaultCredentials looks in some well-known places for a credentials file, and
// will call AppEngineTokenSource or ComputeTokenSource as needed.
//
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
//
// Use CredentialsFromJSON to obtain credentials from either of the two JSON
// formats described in OAuth2 Configs, above. (The DefaultCredentials returned may
// not be "Application Default Credentials".) The TokenSource in the returned value
// is the same as the one obtained from the oauth2.Config returned from
// ConfigFromJSON or JWTConfigFromJSON, but the DefaultCredentials may contain
// additional information that is useful is some circumstances.
package google // import "golang.org/x/oauth2/google"

View file

@ -2,8 +2,6 @@
// 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 (
@ -12,6 +10,7 @@ import (
"log"
"net/http"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/jwt"
@ -148,3 +147,16 @@ func ExampleComputeTokenSource() {
}
client.Get("...")
}
func ExampleCredentialsFromJSON() {
ctx := context.Background()
data, err := ioutil.ReadFile("/path/to/key-file.json")
if err != nil {
log.Fatal(err)
}
creds, err := google.CredentialsFromJSON(ctx, data, "https://www.googleapis.com/auth/bigquery")
if err != nil {
log.Fatal(err)
}
_ = creds // TODO: Use creds.
}

57
vendor/golang.org/x/oauth2/google/go19.go generated vendored Normal file
View file

@ -0,0 +1,57 @@
// Copyright 2018 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.
// +build go1.9
package google
import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// Credentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type Credentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// DefaultCredentials is the old name of Credentials.
//
// Deprecated: use Credentials instead.
type DefaultCredentials = Credentials
// FindDefaultCredentials searches for "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 and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
return findDefaultCredentials(ctx, scopes)
}
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
return credentialsFromJSON(ctx, jsonData, scopes)
}

View file

@ -2,17 +2,7 @@
// 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/docs/application-default-credentials.
package google // import "golang.org/x/oauth2/google"
package google
import (
"encoding/json"

54
vendor/golang.org/x/oauth2/google/not_go19.go generated vendored Normal file
View file

@ -0,0 +1,54 @@
// Copyright 2018 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.
// +build !go1.9
package google
import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// DefaultCredentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type DefaultCredentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// FindDefaultCredentials searches for "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 and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*DefaultCredentials, error) {
return findDefaultCredentials(ctx, scopes)
}
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
//
// Note: despite the name, the returned credentials may not be Application Default Credentials.
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*DefaultCredentials, error) {
return credentialsFromJSON(ctx, jsonData, scopes)
}

View file

@ -5,9 +5,11 @@
package google
import (
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"os/user"
@ -18,7 +20,6 @@ import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/internal"
)
type sdkCredentials struct {
@ -76,7 +77,7 @@ func NewSDKConfig(account string) (*SDKConfig, error) {
return nil, fmt.Errorf("oauth2/google: failed to load SDK properties: %v", err)
}
defer f.Close()
ini, err := internal.ParseINI(f)
ini, err := parseINI(f)
if err != nil {
return nil, fmt.Errorf("oauth2/google: failed to parse SDK properties %q: %v", propertiesPath, err)
}
@ -146,6 +147,34 @@ func (c *SDKConfig) Scopes() []string {
return c.conf.Scopes
}
func parseINI(ini io.Reader) (map[string]map[string]string, error) {
result := map[string]map[string]string{
"": {}, // root section
}
scanner := bufio.NewScanner(ini)
currentSection := ""
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, ";") {
// comment.
continue
}
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
currentSection = strings.TrimSpace(line[1 : len(line)-1])
result[currentSection] = map[string]string{}
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 && parts[0] != "" {
result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error scanning ini: %v", err)
}
return result, nil
}
// sdkConfigPath tries to guess where the gcloud config is located.
// It can be overridden during tests.
var sdkConfigPath = func() (string, error) {

View file

@ -4,7 +4,11 @@
package google
import "testing"
import (
"reflect"
"strings"
"testing"
)
func TestSDKConfig(t *testing.T) {
sdkConfigPath = func() (string, error) {
@ -44,3 +48,60 @@ func TestSDKConfig(t *testing.T) {
}
}
}
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{
"": {"root": "toor"},
"foo": {"bar": "hop", "ini": "nin"},
},
},
{
"\t extra \t = whitespace \t\r\n \t [everywhere] \t \r\n here \t = \t there \t \r\n",
map[string]map[string]string{
"": {"extra": "whitespace"},
"everywhere": {"here": "there"},
},
},
{
`[empty]
[section]
empty=
`,
map[string]map[string]string{
"": {},
"empty": {},
"section": {"empty": ""},
},
},
{
`ignore
[invalid
=stuff
;comment=true
`,
map[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)
}
}
}

View file

@ -0,0 +1,13 @@
// Copyright 2018 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.
// +build appengine
package internal
import "google.golang.org/appengine/urlfetch"
func init() {
appengineClientHook = urlfetch.Client
}

View file

@ -5,14 +5,11 @@
package internal
import (
"bufio"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io"
"strings"
)
// ParseKey converts the binary contents of a private key file
@ -38,38 +35,3 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
}
return parsed, nil
}
func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
result := map[string]map[string]string{
"": {}, // root section
}
scanner := bufio.NewScanner(ini)
currentSection := ""
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, ";") {
// comment.
continue
}
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
currentSection = strings.TrimSpace(line[1 : len(line)-1])
result[currentSection] = map[string]string{}
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 && parts[0] != "" {
result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error scanning ini: %v", err)
}
return result, nil
}
func CondVal(v string) []string {
if v == "" {
return nil
}
return []string{v}
}

View file

@ -1,61 +0,0 @@
// 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
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{
"": {"root": "toor"},
"foo": {"bar": "hop", "ini": "nin"},
},
},
{
`[empty]
[section]
empty=
`,
map[string]map[string]string{
"": {},
"empty": {},
"section": {"empty": ""},
},
},
{
`ignore
[invalid
=stuff
;comment=true
`,
map[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)
}
}
}

View file

@ -6,6 +6,7 @@ package internal
import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -100,9 +101,10 @@ var brokenAuthHeaderProviders = []string{
"https://api.pushbullet.com/",
"https://api.soundcloud.com/",
"https://api.twitch.tv/",
"https://id.twitch.tv/",
"https://app.box.com/",
"https://connect.stripe.com/",
"https://graph.facebook.com", // see https://github.com/golang/oauth2/issues/214
"https://login.mailchimp.com/",
"https://login.microsoftonline.com/",
"https://login.salesforce.com/",
"https://login.windows.net",
@ -123,10 +125,16 @@ var brokenAuthHeaderProviders = []string{
"https://api.patreon.com/",
"https://sandbox.codeswholesale.com/oauth/token",
"https://api.sipgate.com/v1/authorization/oauth",
"https://api.medium.com/v1/tokens",
"https://log.finalsurge.com/oauth/token",
"https://multisport.todaysplan.com.au/rest/oauth/access_token",
"https://whats.todaysplan.com.au/rest/oauth/access_token",
"https://stackoverflow.com/oauth/access_token",
}
// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints.
var brokenAuthHeaderDomains = []string{
".auth0.com",
".force.com",
".myshopify.com",
".okta.com",
@ -169,10 +177,6 @@ func providerAuthHeaderWorks(tokenURL string) bool {
}
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 != "" {
@ -190,7 +194,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
if !bustedAuth {
req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
}
r, err := ctxhttp.Do(ctx, hc, req)
r, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
if err != nil {
return nil, err
}
@ -200,7 +204,10 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
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)
return nil, &RetrieveError{
Response: r,
Body: body,
}
}
var token *Token
@ -247,5 +254,17 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
if token.RefreshToken == "" {
token.RefreshToken = v.Get("refresh_token")
}
if token.AccessToken == "" {
return token, errors.New("oauth2: server response missing access_token")
}
return token, nil
}
type RetrieveError struct {
Response *http.Response
Body []byte
}
func (r *RetrieveError) Error() string {
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
}

View file

@ -33,7 +33,8 @@ func TestRetrieveTokenBustedNoSecret(t *testing.T) {
if got, want := r.FormValue("client_secret"), ""; got != want {
t.Errorf("client_secret = %q; want empty", got)
}
io.WriteString(w, "{}") // something non-empty, required to set a Content-Type in Go 1.10
w.Header().Set("Content-Type", "application/json")
io.WriteString(w, `{"access_token": "ACCESS_TOKEN", "token_type": "bearer"}`)
}))
defer ts.Close()
@ -85,7 +86,8 @@ func TestRetrieveTokenWithContexts(t *testing.T) {
const clientID = "client-id"
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "{}") // something non-empty, required to set a Content-Type in Go 1.10
w.Header().Set("Content-Type", "application/json")
io.WriteString(w, `{"access_token": "ACCESS_TOKEN", "token_type": "bearer"}`)
}))
defer ts.Close()
@ -94,14 +96,16 @@ func TestRetrieveTokenWithContexts(t *testing.T) {
t.Errorf("RetrieveToken (with background context) = %v; want no error", err)
}
ctx, cancelfunc := context.WithCancel(context.Background())
retrieved := make(chan struct{})
cancellingts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cancelfunc()
<-retrieved
}))
defer cancellingts.Close()
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err = RetrieveToken(ctx, clientID, "", cancellingts.URL, url.Values{})
close(retrieved)
if err == nil {
t.Errorf("RetrieveToken (with cancelled context) = nil; want error")
}

View file

@ -19,50 +19,16 @@ var HTTPClient ContextKey
// 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 appengineClientHook func(context.Context) *http.Client
var contextClientFuncs []ContextClientFunc
func RegisterContextClientFunc(fn ContextClientFunc) {
contextClientFuncs = append(contextClientFuncs, fn)
}
func ContextClient(ctx context.Context) (*http.Client, error) {
func ContextClient(ctx context.Context) *http.Client {
if ctx != nil {
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
return hc, nil
return hc
}
}
for _, fn := range contextClientFuncs {
c, err := fn(ctx)
if err != nil {
return nil, err
}
if c != nil {
return c, nil
}
if appengineClientHook != nil {
return appengineClientHook(ctx)
}
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
return http.DefaultClient
}

View file

@ -1,38 +0,0 @@
// Copyright 2015 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
import (
"net/http"
"testing"
"golang.org/x/net/context"
)
func TestContextClient(t *testing.T) {
rc := &http.Client{}
RegisterContextClientFunc(func(context.Context) (*http.Client, error) {
return rc, nil
})
c := &http.Client{}
ctx := context.WithValue(context.Background(), HTTPClient, c)
hc, err := ContextClient(ctx)
if err != nil {
t.Fatalf("want valid client; got err = %v", err)
}
if hc != c {
t.Fatalf("want context client = %p; got = %p", c, hc)
}
hc, err = ContextClient(context.TODO())
if err != nil {
t.Fatalf("want valid client; got err = %v", err)
}
if hc != rc {
t.Fatalf("want registered client = %p; got = %p", c, hc)
}
}

167
vendor/golang.org/x/oauth2/jira/jira.go generated vendored Normal file
View file

@ -0,0 +1,167 @@
// Copyright 2018 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 jira provides claims and JWT signing for OAuth2 to access JIRA/Confluence.
package jira
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"golang.org/x/oauth2"
)
// ClaimSet contains information about the JWT signature according
// to Atlassian's documentation
// https://developer.atlassian.com/cloud/jira/software/oauth-2-jwt-bearer-token-authorization-grant-type/
type ClaimSet struct {
Issuer string `json:"iss"`
Subject string `json:"sub"`
InstalledURL string `json:"tnt"` // URL of installed app
AuthURL string `json:"aud"` // URL of auth server
ExpiresIn int64 `json:"exp"` // Must be no later that 60 seconds in the future
IssuedAt int64 `json:"iat"`
}
var (
defaultGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
defaultHeader = map[string]string{
"typ": "JWT",
"alg": "HS256",
}
)
// Config is the configuration for using JWT to fetch tokens,
// commonly known as "two-legged OAuth 2.0".
type Config struct {
// BaseURL for your app
BaseURL string
// Subject is the userkey as defined by Atlassian
// Different than username (ex: /rest/api/2/user?username=alex)
Subject string
oauth2.Config
}
// 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) {
exp := time.Duration(59) * time.Second
claimSet := &ClaimSet{
Issuer: fmt.Sprintf("urn:atlassian:connect:clientid:%s", js.conf.ClientID),
Subject: fmt.Sprintf("urn:atlassian:connect:userkey:%s", js.conf.Subject),
InstalledURL: js.conf.BaseURL,
AuthURL: js.conf.Endpoint.AuthURL,
IssuedAt: time.Now().Unix(),
ExpiresIn: time.Now().Add(exp).Unix(),
}
v := url.Values{}
v.Set("grant_type", defaultGrantType)
// Add scopes if they exist; If not, it defaults to app scopes
if scopes := js.conf.Scopes; scopes != nil {
upperScopes := make([]string, len(scopes))
for i, k := range scopes {
upperScopes[i] = strings.ToUpper(k)
}
v.Set("scope", strings.Join(upperScopes, "+"))
}
// Sign claims for assertion
assertion, err := sign(js.conf.ClientSecret, claimSet)
if err != nil {
return nil, err
}
v.Set("assertion", string(assertion))
// Fetch access token from auth server
hc := oauth2.NewClient(js.ctx, nil)
resp, err := hc.PostForm(js.conf.Endpoint.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"`
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,
}
if secs := tokenRes.ExpiresIn; secs > 0 {
token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
}
return token, nil
}
// Sign the claim set with the shared secret
// Result to be sent as assertion
func sign(key string, claims *ClaimSet) (string, error) {
b, err := json.Marshal(defaultHeader)
if err != nil {
return "", err
}
header := base64.RawURLEncoding.EncodeToString(b)
jsonClaims, err := json.Marshal(claims)
if err != nil {
return "", err
}
encodedClaims := strings.TrimRight(base64.URLEncoding.EncodeToString(jsonClaims), "=")
ss := fmt.Sprintf("%s.%s", header, encodedClaims)
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(ss))
signature := mac.Sum(nil)
return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(signature)), nil
}

185
vendor/golang.org/x/oauth2/jira/jira_test.go generated vendored Normal file
View file

@ -0,0 +1,185 @@
// Copyright 2018 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 jira
import (
"context"
"encoding/base64"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"golang.org/x/oauth2"
"golang.org/x/oauth2/jws"
)
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",
"token_type": "Bearer",
"expires_in": 3600
}`))
}))
defer ts.Close()
conf := &Config{
BaseURL: "https://my.app.com",
Subject: "userkey",
Config: oauth2.Config{
ClientID: "super_secret_client_id",
ClientSecret: "super_shared_secret",
Scopes: []string{"read", "write"},
Endpoint: oauth2.Endpoint{
AuthURL: "https://example.com",
TokenURL: ts.URL,
},
},
}
tok, err := conf.TokenSource(context.Background()).Token()
if err != nil {
t.Fatal(err)
}
if !tok.Valid() {
t.Errorf("got invalid token: %v", tok)
}
if got, want := tok.AccessToken, "90d64460d14870c08c81352a05dedd3465940a7c"; got != want {
t.Errorf("access token = %q; want %q", got, want)
}
if got, want := tok.TokenType, "Bearer"; got != want {
t.Errorf("token type = %q; want %q", got, want)
}
if got := tok.Expiry.IsZero(); got {
t.Errorf("token expiry = %v, want none", got)
}
}
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(`{"token_type": "Bearer"}`))
}))
defer ts.Close()
conf := &Config{
BaseURL: "https://my.app.com",
Subject: "userkey",
Config: oauth2.Config{
ClientID: "super_secret_client_id",
ClientSecret: "super_shared_secret",
Scopes: []string{"read", "write"},
Endpoint: oauth2.Endpoint{
AuthURL: "https://example.com",
TokenURL: ts.URL,
},
},
}
tok, err := conf.TokenSource(context.Background()).Token()
if err != nil {
t.Fatal(err)
}
if tok == nil {
t.Fatalf("got nil token; want token")
}
if tok.Valid() {
t.Errorf("got invalid token: %v", tok)
}
if got, want := tok.AccessToken, ""; got != want {
t.Errorf("access token = %q; want %q", got, want)
}
if got, want := tok.TokenType, "Bearer"; got != want {
t.Errorf("token type = %q; want %q", got, 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, "token_type": "Bearer"}`))
}))
defer ts.Close()
conf := &Config{
BaseURL: "https://my.app.com",
Subject: "userkey",
Config: oauth2.Config{
ClientID: "super_secret_client_id",
ClientSecret: "super_shared_secret",
Endpoint: oauth2.Endpoint{
AuthURL: "https://example.com",
TokenURL: ts.URL,
},
},
}
tok, err := conf.TokenSource(context.Background()).Token()
if err == nil {
t.Error("got a token; expected error")
if got, want := tok.AccessToken, ""; got != want {
t.Errorf("access token = %q; want %q", got, want)
}
}
}
func TestJWTFetch_Assertion(t *testing.T) {
var assertion string
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
assertion = r.Form.Get("assertion")
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{
"access_token": "90d64460d14870c08c81352a05dedd3465940a7c",
"token_type": "Bearer",
"expires_in": 3600
}`))
}))
defer ts.Close()
conf := &Config{
BaseURL: "https://my.app.com",
Subject: "userkey",
Config: oauth2.Config{
ClientID: "super_secret_client_id",
ClientSecret: "super_shared_secret",
Endpoint: oauth2.Endpoint{
AuthURL: "https://example.com",
TokenURL: ts.URL,
},
},
}
_, err := conf.TokenSource(context.Background()).Token()
if err != nil {
t.Fatalf("Failed to fetch token: %v", err)
}
parts := strings.Split(assertion, ".")
if len(parts) != 3 {
t.Fatalf("assertion = %q; want 3 parts", assertion)
}
gotjson, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil {
t.Fatalf("invalid token header; err = %v", err)
}
got := jws.Header{}
if err := json.Unmarshal(gotjson, &got); err != nil {
t.Errorf("failed to unmarshal json token header = %q; err = %v", gotjson, err)
}
want := jws.Header{
Algorithm: "HS256",
Typ: "JWT",
}
if got != want {
t.Errorf("access token header = %q; want %q", got, want)
}
}

View file

@ -124,7 +124,10 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
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)
return nil, &oauth2.RetrieveError{
Response: resp,
Body: body,
}
}
// tokenRes is the JSON response body.
var tokenRes struct {

View file

@ -8,11 +8,13 @@ import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
"golang.org/x/oauth2"
"golang.org/x/oauth2/jws"
)
@ -188,3 +190,32 @@ func TestJWTFetch_Assertion(t *testing.T) {
t.Errorf("access token header = %q; want %q", got, want)
}
}
func TestTokenRetrieveError(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-type", "application/json")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{"error": "invalid_grant"}`))
}))
defer ts.Close()
conf := &Config{
Email: "aaa@xxx.com",
PrivateKey: dummyPrivateKey,
TokenURL: ts.URL,
}
_, err := conf.TokenSource(context.Background()).Token()
if err == nil {
t.Fatalf("got no error, expected one")
}
_, ok := err.(*oauth2.RetrieveError)
if !ok {
t.Fatalf("got %T error, expected *RetrieveError", err)
}
// Test error string for backwards compatibility
expected := fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", "400 Bad Request", `{"error": "invalid_grant"}`)
if errStr := err.Error(); errStr != expected {
t.Fatalf("got %#v, expected %#v", errStr, expected)
}
}

16
vendor/golang.org/x/oauth2/kakao/kakao.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 kakao provides constants for using OAuth2 to access Kakao.
package kakao // import "golang.org/x/oauth2/kakao"
import (
"golang.org/x/oauth2"
)
// Endpoint is Kakao's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://kauth.kakao.com/oauth/authorize",
TokenURL: "https://kauth.kakao.com/oauth/token",
}

View file

@ -11,6 +11,6 @@ import (
// 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",
AuthURL: "https://www.linkedin.com/oauth/v2/authorization",
TokenURL: "https://www.linkedin.com/oauth/v2/accessToken",
}

17
vendor/golang.org/x/oauth2/mailchimp/mailchimp.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2018 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 mailchimp provides constants for using OAuth2 to access MailChimp.
package mailchimp // import "golang.org/x/oauth2/mailchimp"
import (
"golang.org/x/oauth2"
)
// Endpoint is MailChimp's OAuth 2.0 endpoint.
// See http://developer.mailchimp.com/documentation/mailchimp/guides/how-to-use-oauth2/
var Endpoint = oauth2.Endpoint{
AuthURL: "https://login.mailchimp.com/oauth2/authorize",
TokenURL: "https://login.mailchimp.com/oauth2/token",
}

58
vendor/golang.org/x/oauth2/oauth2.go generated vendored
View file

@ -3,7 +3,8 @@
// license that can be found in the LICENSE file.
// Package oauth2 provides support for making
// OAuth2 authorized and authenticated HTTP requests.
// OAuth2 authorized and authenticated HTTP requests,
// as specified in RFC 6749.
// It can additionally grant authorization with Bearer JWT.
package oauth2 // import "golang.org/x/oauth2"
@ -117,21 +118,30 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
// that asks for permissions for the required scopes explicitly.
//
// State is a token to protect the user from CSRF attacks. You must
// always provide a non-zero string and validate that it matches the
// always provide a non-empty string and validate that it matches the
// the state query parameter on your redirect callback.
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
//
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
// as ApprovalForce.
// It can also be used to pass the PKCE challange.
// See https://www.oauth.com/oauth2-servers/pkce/ for more info.
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
var buf bytes.Buffer
buf.WriteString(c.Endpoint.AuthURL)
v := url.Values{
"response_type": {"code"},
"client_id": {c.ClientID},
"redirect_uri": internal.CondVal(c.RedirectURL),
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
"state": internal.CondVal(state),
}
if c.RedirectURL != "" {
v.Set("redirect_uri", c.RedirectURL)
}
if len(c.Scopes) > 0 {
v.Set("scope", strings.Join(c.Scopes, " "))
}
if state != "" {
// TODO(light): Docs say never to omit state; don't allow empty.
v.Set("state", state)
}
for _, opt := range opts {
opt.setValue(v)
@ -157,12 +167,15 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
// The HTTP client to use is derived from the context.
// If nil, http.DefaultClient is used.
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
return retrieveToken(ctx, c, url.Values{
v := url.Values{
"grant_type": {"password"},
"username": {username},
"password": {password},
"scope": internal.CondVal(strings.Join(c.Scopes, " ")),
})
}
if len(c.Scopes) > 0 {
v.Set("scope", strings.Join(c.Scopes, " "))
}
return retrieveToken(ctx, c, v)
}
// Exchange converts an authorization code into a token.
@ -175,12 +188,21 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
//
// The code will be in the *http.Request.FormValue("code"). Before
// calling Exchange, be sure to validate FormValue("state").
func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) {
return retrieveToken(ctx, c, url.Values{
"grant_type": {"authorization_code"},
"code": {code},
"redirect_uri": internal.CondVal(c.RedirectURL),
})
//
// Opts may include the PKCE verifier code if previously used in AuthCodeURL.
// See https://www.oauth.com/oauth2-servers/pkce/ for more info.
func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error) {
v := url.Values{
"grant_type": {"authorization_code"},
"code": {code},
}
if c.RedirectURL != "" {
v.Set("redirect_uri", c.RedirectURL)
}
for _, opt := range opts {
opt.setValue(v)
}
return retrieveToken(ctx, c, v)
}
// Client returns an HTTP client using the provided token.
@ -300,15 +322,11 @@ var HTTPClient internal.ContextKey
// packages.
func NewClient(ctx context.Context, src TokenSource) *http.Client {
if src == nil {
c, err := internal.ContextClient(ctx)
if err != nil {
return &http.Client{Transport: internal.ErrorTransport{Err: err}}
}
return c
return internal.ContextClient(ctx)
}
return &http.Client{
Transport: &Transport{
Base: internal.ContextTransport(ctx),
Base: internal.ContextClient(ctx).Transport,
Source: ReuseTokenSource(nil, src),
},
}

View file

@ -135,6 +135,52 @@ func TestExchangeRequest(t *testing.T) {
}
}
func TestExchangeRequest_CustomParam(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) != "code=exchange-code&foo=bar&grant_type=authorization_code&redirect_uri=REDIRECT_URL" {
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)
param := SetAuthURLParam("foo", "bar")
tok, err := conf.Exchange(context.Background(), "exchange-code", param)
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" {
@ -278,12 +324,9 @@ func TestExchangeRequest_BadResponse(t *testing.T) {
}))
defer ts.Close()
conf := newConf(ts.URL)
tok, err := conf.Exchange(context.Background(), "code")
if err != nil {
t.Fatal(err)
}
if tok.AccessToken != "" {
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
_, err := conf.Exchange(context.Background(), "code")
if err == nil {
t.Error("expected error from missing access_token")
}
}
@ -296,7 +339,7 @@ func TestExchangeRequest_BadResponseType(t *testing.T) {
conf := newConf(ts.URL)
_, err := conf.Exchange(context.Background(), "exchange-code")
if err == nil {
t.Error("expected error from invalid access_token type")
t.Error("expected error from non-string access_token")
}
}
@ -419,6 +462,32 @@ func TestFetchWithNoRefreshToken(t *testing.T) {
}
}
func TestTokenRetrieveError(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.String() != "/token" {
t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL)
}
w.Header().Set("Content-type", "application/json")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{"error": "invalid_grant"}`))
}))
defer ts.Close()
conf := newConf(ts.URL)
_, err := conf.Exchange(context.Background(), "exchange-code")
if err == nil {
t.Fatalf("got no error, expected one")
}
_, ok := err.(*RetrieveError)
if !ok {
t.Fatalf("got %T error, expected *RetrieveError", err)
}
// Test error string for backwards compatibility
expected := fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", "400 Bad Request", `{"error": "invalid_grant"}`)
if errStr := err.Error(); errStr != expected {
t.Fatalf("got %#v, expected %#v", errStr, expected)
}
}
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")
@ -427,18 +496,14 @@ func TestRefreshToken_RefreshTokenReplacement(t *testing.T) {
}))
defer ts.Close()
conf := newConf(ts.URL)
tkr := &tokenRefresher{
conf: conf,
ctx: context.Background(),
refreshToken: "OLD_REFRESH_TOKEN",
}
tkr := conf.TokenSource(context.Background(), &Token{RefreshToken: "OLD_REFRESH_TOKEN"})
tk, err := tkr.Token()
if err != nil {
t.Errorf("got err = %v; want none", err)
return
}
if tk.RefreshToken != tkr.refreshToken {
t.Errorf("tokenRefresher.refresh_token = %q; want %q", tkr.refreshToken, tk.RefreshToken)
if want := "NEW_REFRESH_TOKEN"; tk.RefreshToken != want {
t.Errorf("RefreshToken = %q; want %q", tk.RefreshToken, want)
}
}
@ -451,17 +516,13 @@ func TestRefreshToken_RefreshTokenPreservation(t *testing.T) {
defer ts.Close()
conf := newConf(ts.URL)
const oldRefreshToken = "OLD_REFRESH_TOKEN"
tkr := &tokenRefresher{
conf: conf,
ctx: context.Background(),
refreshToken: oldRefreshToken,
}
_, err := tkr.Token()
tkr := conf.TokenSource(context.Background(), &Token{RefreshToken: oldRefreshToken})
tk, err := tkr.Token()
if err != nil {
t.Fatalf("got err = %v; want none", err)
}
if tkr.refreshToken != oldRefreshToken {
t.Errorf("tokenRefresher.refreshToken = %q; want %q", tkr.refreshToken, oldRefreshToken)
if tk.RefreshToken != oldRefreshToken {
t.Errorf("RefreshToken = %q; want %q", tk.RefreshToken, oldRefreshToken)
}
}

16
vendor/golang.org/x/oauth2/spotify/spotify.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 spotify provides constants for using OAuth2 to access Spotify.
package spotify // import "golang.org/x/oauth2/spotify"
import (
"golang.org/x/oauth2"
)
// Endpoint is Spotify's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://accounts.spotify.com/authorize",
TokenURL: "https://accounts.spotify.com/api/token",
}

View file

@ -0,0 +1,16 @@
// Copyright 2018 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 stackoverflow provides constants for using OAuth2 to access Stack Overflow.
package stackoverflow // import "golang.org/x/oauth2/stackoverflow"
import (
"golang.org/x/oauth2"
)
// Endpoint is Stack Overflow's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://stackoverflow.com/oauth",
TokenURL: "https://stackoverflow.com/oauth/access_token",
}

17
vendor/golang.org/x/oauth2/token.go generated vendored
View file

@ -5,6 +5,7 @@
package oauth2
import (
"fmt"
"net/http"
"net/url"
"strconv"
@ -152,7 +153,23 @@ func tokenFromInternal(t *internal.Token) *Token {
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 {
if rErr, ok := err.(*internal.RetrieveError); ok {
return nil, (*RetrieveError)(rErr)
}
return nil, err
}
return tokenFromInternal(tk), nil
}
// RetrieveError is the error returned when the token endpoint returns a
// non-2XX HTTP status code.
type RetrieveError struct {
Response *http.Response
// Body is the body that was consumed by reading Response.Body.
// It may be truncated.
Body []byte
}
func (r *RetrieveError) Error() string {
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
}

View file

@ -31,9 +31,17 @@ type Transport struct {
}
// RoundTrip authorizes and authenticates the request with an
// access token. If no token exists or token is expired,
// tries to refresh/fetch a new token.
// access token from Transport's Source.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
reqBodyClosed := false
if req.Body != nil {
defer func() {
if !reqBodyClosed {
req.Body.Close()
}
}()
}
if t.Source == nil {
return nil, errors.New("oauth2: Transport's Source is nil")
}
@ -46,6 +54,10 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
token.SetAuthHeader(req2)
t.setModReq(req, req2)
res, err := t.base().RoundTrip(req2)
// req.Body is assumed to have been closed by the base RoundTripper.
reqBodyClosed = true
if err != nil {
t.setModReq(req, nil)
return nil, err

View file

@ -1,6 +1,8 @@
package oauth2
import (
"errors"
"io"
"net/http"
"net/http/httptest"
"testing"
@ -27,6 +29,64 @@ func TestTransportNilTokenSource(t *testing.T) {
}
}
type readCloseCounter struct {
CloseCount int
ReadErr error
}
func (r *readCloseCounter) Read(b []byte) (int, error) {
return 0, r.ReadErr
}
func (r *readCloseCounter) Close() error {
r.CloseCount++
return nil
}
func TestTransportCloseRequestBody(t *testing.T) {
tr := &Transport{}
server := newMockServer(func(w http.ResponseWriter, r *http.Request) {})
defer server.Close()
client := &http.Client{Transport: tr}
body := &readCloseCounter{
ReadErr: errors.New("readCloseCounter.Read not implemented"),
}
resp, err := client.Post(server.URL, "application/json", body)
if err == nil {
t.Errorf("got no errors, want an error with nil token source")
}
if resp != nil {
t.Errorf("Response = %v; want nil", resp)
}
if expected := 1; body.CloseCount != expected {
t.Errorf("Body was closed %d times, expected %d", body.CloseCount, expected)
}
}
func TestTransportCloseRequestBodySuccess(t *testing.T) {
tr := &Transport{
Source: StaticTokenSource(&Token{
AccessToken: "abc",
}),
}
server := newMockServer(func(w http.ResponseWriter, r *http.Request) {})
defer server.Close()
client := &http.Client{Transport: tr}
body := &readCloseCounter{
ReadErr: io.EOF,
}
resp, err := client.Post(server.URL, "application/json", body)
if err != nil {
t.Errorf("got error %v; expected none", err)
}
if resp == nil {
t.Errorf("Response is nil; expected non-nil")
}
if expected := 1; body.CloseCount != expected {
t.Errorf("Body was closed %d times, expected %d", body.CloseCount, expected)
}
}
func TestTransportTokenSource(t *testing.T) {
ts := &tokenSource{
token: &Token{

View file

@ -14,6 +14,6 @@ import (
// For more information see:
// https://dev.twitch.tv/docs/authentication
var Endpoint = oauth2.Endpoint{
AuthURL: "https://api.twitch.tv/kraken/oauth2/authorize",
TokenURL: "https://api.twitch.tv/kraken/oauth2/token",
AuthURL: "https://id.twitch.tv/oauth2/authorize",
TokenURL: "https://id.twitch.tv/oauth2/token",
}