mirror of
https://github.com/golang/oauth2.git
synced 2025-07-21 00:00:09 +08:00
Before AppEngine classic allowed "google.golang.org/appengine" imports, we used to maintain two hook files to choose either from "appengine" or "google.golang.org/appengine" namespaces. Now, both environments allow importing from "google.golang.org/appengine". Therefore, there is no need to set hooks in two separate files. Also note that Flex prefers to use metadata server, so we still need to be able to differentiate between these environments. Change-Id: I7478ebdfa1b062d466aaf2aca938f93d42b4c58a Reviewed-on: https://go-review.googlesource.com/37378 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
90 lines
2.3 KiB
Go
90 lines
2.3 KiB
Go
// 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 google
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"golang.org/x/net/context"
|
|
"golang.org/x/oauth2"
|
|
)
|
|
|
|
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex.
|
|
var appengineFlex bool
|
|
|
|
// 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)
|
|
|
|
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
|
|
var appengineAppIDFunc func(c context.Context) string
|
|
|
|
// 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
|
|
}
|