Skip to content

Commit 429a0e6

Browse files
committed
Syncing a fork
2 parents 8ddd60c + e64efc7 commit 429a0e6

32 files changed

+594
-545
lines changed

README.md

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,54 +19,12 @@ See godoc for further documentation and examples.
1919
* [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2)
2020
* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google)
2121

22+
## Policy for new packages
2223

23-
## App Engine
24-
25-
In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor
26-
of the [`context.Context`](https://golang.org/x/net/context#Context) type from
27-
the `golang.org/x/net/context` package
28-
29-
This means it's no longer possible to use the "Classic App Engine"
30-
`appengine.Context` type with the `oauth2` package. (You're using
31-
Classic App Engine if you import the package `"appengine"`.)
32-
33-
To work around this, you may use the new `"google.golang.org/appengine"`
34-
package. This package has almost the same API as the `"appengine"` package,
35-
but it can be fetched with `go get` and used on "Managed VMs" and well as
36-
Classic App Engine.
37-
38-
See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app)
39-
for information on updating your app.
40-
41-
If you don't want to update your entire app to use the new App Engine packages,
42-
you may use both sets of packages in parallel, using only the new packages
43-
with the `oauth2` package.
44-
45-
```go
46-
import (
47-
"golang.org/x/net/context"
48-
"golang.org/x/oauth2"
49-
"golang.org/x/oauth2/google"
50-
newappengine "google.golang.org/appengine"
51-
newurlfetch "google.golang.org/appengine/urlfetch"
52-
53-
"appengine"
54-
)
55-
56-
func handler(w http.ResponseWriter, r *http.Request) {
57-
var c appengine.Context = appengine.NewContext(r)
58-
c.Infof("Logging a message with the old package")
59-
60-
var ctx context.Context = newappengine.NewContext(r)
61-
client := &http.Client{
62-
Transport: &oauth2.Transport{
63-
Source: google.AppEngineTokenSource(ctx, "scope"),
64-
Base: &newurlfetch.Transport{Context: ctx},
65-
},
66-
}
67-
client.Get("...")
68-
}
69-
```
24+
We no longer accept new provider-specific packages in this repo. For
25+
defining provider endpoints and provider-specific OAuth2 behavior, we
26+
encourage you to create packages elsewhere. We'll keep the existing
27+
packages for compatibility.
7028

7129
## Report Issues / Send Patches
7230

clientcredentials/clientcredentials.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
package clientcredentials // import "golang.org/x/oauth2/clientcredentials"
1515

1616
import (
17+
"context"
1718
"fmt"
1819
"net/http"
1920
"net/url"
2021
"strings"
2122

22-
"golang.org/x/net/context"
2323
"golang.org/x/oauth2"
2424
"golang.org/x/oauth2/internal"
2525
)
@@ -42,19 +42,27 @@ type Config struct {
4242

4343
// EndpointParams specifies additional parameters for requests to the token endpoint.
4444
EndpointParams url.Values
45+
46+
// AuthStyle optionally specifies how the endpoint wants the
47+
// client ID & client secret sent. The zero value means to
48+
// auto-detect.
49+
AuthStyle oauth2.AuthStyle
4550
}
4651

4752
// Token uses client credentials to retrieve a token.
48-
// The HTTP client to use is derived from the context.
49-
// If nil, http.DefaultClient is used.
53+
//
54+
// The provided context optionally controls which HTTP client is used. See the oauth2.HTTPClient variable.
5055
func (c *Config) Token(ctx context.Context) (*oauth2.Token, error) {
5156
return c.TokenSource(ctx).Token()
5257
}
5358

5459
// Client returns an HTTP client using the provided token.
55-
// The token will auto-refresh as necessary. The underlying
56-
// HTTP transport will be obtained using the provided context.
57-
// The returned client and its Transport should not be modified.
60+
// The token will auto-refresh as necessary.
61+
//
62+
// The provided context optionally controls which HTTP client
63+
// is returned. See the oauth2.HTTPClient variable.
64+
//
65+
// The returned Client and its Transport should not be modified.
5866
func (c *Config) Client(ctx context.Context) *http.Client {
5967
return oauth2.NewClient(ctx, c.TokenSource(ctx))
6068
}
@@ -87,12 +95,15 @@ func (c *tokenSource) Token() (*oauth2.Token, error) {
8795
v.Set("scope", strings.Join(c.conf.Scopes, " "))
8896
}
8997
for k, p := range c.conf.EndpointParams {
90-
if _, ok := v[k]; ok {
98+
// Allow grant_type to be overridden to allow interoperability with
99+
// non-compliant implementations.
100+
if _, ok := v[k]; ok && k != "grant_type" {
91101
return nil, fmt.Errorf("oauth2: cannot overwrite parameter %q", k)
92102
}
93103
v[k] = p
94104
}
95-
tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v)
105+
106+
tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v, internal.AuthStyle(c.conf.AuthStyle))
96107
if err != nil {
97108
if rErr, ok := err.(*internal.RetrieveError); ok {
98109
return nil, (*oauth2.RetrieveError)(rErr)

clientcredentials/clientcredentials_test.go

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ package clientcredentials
66

77
import (
88
"context"
9+
"io"
910
"io/ioutil"
1011
"net/http"
1112
"net/http/httptest"
1213
"net/url"
1314
"testing"
15+
16+
"golang.org/x/oauth2/internal"
1417
)
1518

1619
func newConf(serverURL string) *Config {
@@ -31,6 +34,43 @@ func (t *mockTransport) RoundTrip(req *http.Request) (resp *http.Response, err e
3134
return t.rt(req)
3235
}
3336

37+
func TestTokenSourceGrantTypeOverride(t *testing.T) {
38+
wantGrantType := "password"
39+
var gotGrantType string
40+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
41+
body, err := ioutil.ReadAll(r.Body)
42+
if err != nil {
43+
t.Errorf("ioutil.ReadAll(r.Body) == %v, %v, want _, <nil>", body, err)
44+
}
45+
if err := r.Body.Close(); err != nil {
46+
t.Errorf("r.Body.Close() == %v, want <nil>", err)
47+
}
48+
values, err := url.ParseQuery(string(body))
49+
if err != nil {
50+
t.Errorf("url.ParseQuery(%q) == %v, %v, want _, <nil>", body, values, err)
51+
}
52+
gotGrantType = values.Get("grant_type")
53+
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
54+
w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&token_type=bearer"))
55+
}))
56+
config := &Config{
57+
ClientID: "CLIENT_ID",
58+
ClientSecret: "CLIENT_SECRET",
59+
Scopes: []string{"scope"},
60+
TokenURL: ts.URL + "/token",
61+
EndpointParams: url.Values{
62+
"grant_type": {wantGrantType},
63+
},
64+
}
65+
token, err := config.TokenSource(context.Background()).Token()
66+
if err != nil {
67+
t.Errorf("config.TokenSource(_).Token() == %v, %v, want !<nil>, <nil>", token, err)
68+
}
69+
if gotGrantType != wantGrantType {
70+
t.Errorf("grant_type == %q, want %q", gotGrantType, wantGrantType)
71+
}
72+
}
73+
3474
func TestTokenRequest(t *testing.T) {
3575
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3676
if r.URL.String() != "/token" {
@@ -74,21 +114,25 @@ func TestTokenRequest(t *testing.T) {
74114
}
75115

76116
func TestTokenRefreshRequest(t *testing.T) {
117+
internal.ResetAuthCache()
77118
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
78119
if r.URL.String() == "/somethingelse" {
79120
return
80121
}
81122
if r.URL.String() != "/token" {
82-
t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL)
123+
t.Errorf("Unexpected token refresh request URL: %q", r.URL)
83124
}
84125
headerContentType := r.Header.Get("Content-Type")
85-
if headerContentType != "application/x-www-form-urlencoded" {
86-
t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType)
126+
if got, want := headerContentType, "application/x-www-form-urlencoded"; got != want {
127+
t.Errorf("Content-Type = %q; want %q", got, want)
87128
}
88129
body, _ := ioutil.ReadAll(r.Body)
89-
if string(body) != "audience=audience1&grant_type=client_credentials&scope=scope1+scope2" {
90-
t.Errorf("Unexpected refresh token payload, %v is found.", string(body))
130+
const want = "audience=audience1&grant_type=client_credentials&scope=scope1+scope2"
131+
if string(body) != want {
132+
t.Errorf("Unexpected refresh token payload.\n got: %s\nwant: %s\n", body, want)
91133
}
134+
w.Header().Set("Content-Type", "application/json")
135+
io.WriteString(w, `{"access_token": "foo", "refresh_token": "bar"}`)
92136
}))
93137
defer ts.Close()
94138
conf := newConf(ts.URL)

facebook/facebook.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ import (
1111

1212
// Endpoint is Facebook's OAuth 2.0 endpoint.
1313
var Endpoint = oauth2.Endpoint{
14-
AuthURL: "https://www.facebook.com/dialog/oauth",
15-
TokenURL: "https://graph.facebook.com/oauth/access_token",
14+
AuthURL: "https://www.facebook.com/v3.1/dialog/oauth",
15+
TokenURL: "https://graph.facebook.com/v3.1/oauth/access_token",
1616
}

go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module golang.org/x/oauth2
2+
3+
go 1.11
4+
5+
require (
6+
cloud.google.com/go v0.34.0
7+
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e
8+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
9+
google.golang.org/appengine v1.4.0
10+
)

go.sum

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
2+
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3+
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
4+
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
5+
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
6+
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
7+
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
8+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
9+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
10+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
11+
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
12+
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

google/appengine.go

Lines changed: 19 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,85 +5,34 @@
55
package google
66

77
import (
8-
"sort"
9-
"strings"
10-
"sync"
8+
"context"
119
"time"
1210

13-
"golang.org/x/net/context"
1411
"golang.org/x/oauth2"
1512
)
1613

17-
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex.
18-
var appengineFlex bool
19-
20-
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
14+
// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
2115
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
2216

23-
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
17+
// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
2418
var appengineAppIDFunc func(c context.Context) string
2519

26-
// AppEngineTokenSource returns a token source that fetches tokens
27-
// issued to the current App Engine application's service account.
28-
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine
29-
// that involves user accounts, see oauth2.Config instead.
20+
// AppEngineTokenSource returns a token source that fetches tokens from either
21+
// the current application's service account or from the metadata server,
22+
// depending on the App Engine environment. See below for environment-specific
23+
// details. If you are implementing a 3-legged OAuth 2.0 flow on App Engine that
24+
// involves user accounts, see oauth2.Config instead.
25+
//
26+
// First generation App Engine runtimes (<= Go 1.9):
27+
// AppEngineTokenSource returns a token source that fetches tokens issued to the
28+
// current App Engine application's service account. The provided context must have
29+
// come from appengine.NewContext.
3030
//
31-
// The provided context must have come from appengine.NewContext.
31+
// Second generation App Engine runtimes (>= Go 1.11) and App Engine flexible:
32+
// AppEngineTokenSource is DEPRECATED on second generation runtimes and on the
33+
// flexible environment. It delegates to ComputeTokenSource, and the provided
34+
// context and scopes are not used. Please use DefaultTokenSource (or ComputeTokenSource,
35+
// which DefaultTokenSource will use in this case) instead.
3236
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
33-
if appengineTokenFunc == nil {
34-
panic("google: AppEngineTokenSource can only be used on App Engine.")
35-
}
36-
scopes := append([]string{}, scope...)
37-
sort.Strings(scopes)
38-
return &appEngineTokenSource{
39-
ctx: ctx,
40-
scopes: scopes,
41-
key: strings.Join(scopes, " "),
42-
}
43-
}
44-
45-
// aeTokens helps the fetched tokens to be reused until their expiration.
46-
var (
47-
aeTokensMu sync.Mutex
48-
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
49-
)
50-
51-
type tokenLock struct {
52-
mu sync.Mutex // guards t; held while fetching or updating t
53-
t *oauth2.Token
54-
}
55-
56-
type appEngineTokenSource struct {
57-
ctx context.Context
58-
scopes []string
59-
key string // to aeTokens map; space-separated scopes
60-
}
61-
62-
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) {
63-
if appengineTokenFunc == nil {
64-
panic("google: AppEngineTokenSource can only be used on App Engine.")
65-
}
66-
67-
aeTokensMu.Lock()
68-
tok, ok := aeTokens[ts.key]
69-
if !ok {
70-
tok = &tokenLock{}
71-
aeTokens[ts.key] = tok
72-
}
73-
aeTokensMu.Unlock()
74-
75-
tok.mu.Lock()
76-
defer tok.mu.Unlock()
77-
if tok.t.Valid() {
78-
return tok.t, nil
79-
}
80-
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
81-
if err != nil {
82-
return nil, err
83-
}
84-
tok.t = &oauth2.Token{
85-
AccessToken: access,
86-
Expiry: exp,
87-
}
88-
return tok.t, nil
37+
return appEngineTokenSource(ctx, scope...)
8938
}

0 commit comments

Comments
 (0)