aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/oauth2
diff options
context:
space:
mode:
authoruzhas <uzhas@ydb.tech>2023-11-16 16:04:50 +0300
committeruzhas <uzhas@ydb.tech>2023-11-16 17:46:46 +0300
commit46f0c0079bb50609d2eeb6586642bcf114fc5239 (patch)
tree84e4e4978d57fe5de321ba69bf9d0c290de60a66 /vendor/golang.org/x/oauth2
parent73045e389397816cc2bdd6cd7818b4bce427b265 (diff)
downloadydb-46f0c0079bb50609d2eeb6586642bcf114fc5239.tar.gz
enable ya make for go projects
Diffstat (limited to 'vendor/golang.org/x/oauth2')
-rw-r--r--vendor/golang.org/x/oauth2/authhandler/authhandler.go94
-rw-r--r--vendor/golang.org/x/oauth2/authhandler/ya.make15
-rw-r--r--vendor/golang.org/x/oauth2/deviceauth.go198
-rw-r--r--vendor/golang.org/x/oauth2/google/appengine.go38
-rw-r--r--vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go27
-rw-r--r--vendor/golang.org/x/oauth2/google/default.go259
-rw-r--r--vendor/golang.org/x/oauth2/google/doc.go133
-rw-r--r--vendor/golang.org/x/oauth2/google/error.go64
-rw-r--r--vendor/golang.org/x/oauth2/google/google.go308
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go556
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go254
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go18
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go313
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go61
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/header.go64
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go105
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go79
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccount/ya.make38
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/externalaccountauthorizeduser.go114
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/ya.make15
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/stsexchange/clientauth.go45
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/stsexchange/sts_exchange.go125
-rw-r--r--vendor/golang.org/x/oauth2/google/internal/stsexchange/ya.make19
-rw-r--r--vendor/golang.org/x/oauth2/google/jwt.go102
-rw-r--r--vendor/golang.org/x/oauth2/google/sdk.go201
-rw-r--r--vendor/golang.org/x/oauth2/google/ya.make32
-rw-r--r--vendor/golang.org/x/oauth2/internal/doc.go6
-rw-r--r--vendor/golang.org/x/oauth2/internal/oauth2.go37
-rw-r--r--vendor/golang.org/x/oauth2/internal/token.go352
-rw-r--r--vendor/golang.org/x/oauth2/internal/transport.go33
-rw-r--r--vendor/golang.org/x/oauth2/internal/ya.make18
-rw-r--r--vendor/golang.org/x/oauth2/jws/jws.go182
-rw-r--r--vendor/golang.org/x/oauth2/jws/ya.make15
-rw-r--r--vendor/golang.org/x/oauth2/jwt/jwt.go185
-rw-r--r--vendor/golang.org/x/oauth2/jwt/ya.make17
-rw-r--r--vendor/golang.org/x/oauth2/oauth2.go421
-rw-r--r--vendor/golang.org/x/oauth2/pkce.go68
-rw-r--r--vendor/golang.org/x/oauth2/token.go205
-rw-r--r--vendor/golang.org/x/oauth2/transport.go89
-rw-r--r--vendor/golang.org/x/oauth2/ya.make62
40 files changed, 4967 insertions, 0 deletions
diff --git a/vendor/golang.org/x/oauth2/authhandler/authhandler.go b/vendor/golang.org/x/oauth2/authhandler/authhandler.go
new file mode 100644
index 0000000000..9bc6cd7bc5
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/authhandler/authhandler.go
@@ -0,0 +1,94 @@
+// Copyright 2021 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 authhandler implements a TokenSource to support
+// "three-legged OAuth 2.0" via a custom AuthorizationHandler.
+package authhandler
+
+import (
+ "context"
+ "errors"
+
+ "golang.org/x/oauth2"
+)
+
+const (
+ // Parameter keys for AuthCodeURL method to support PKCE.
+ codeChallengeKey = "code_challenge"
+ codeChallengeMethodKey = "code_challenge_method"
+
+ // Parameter key for Exchange method to support PKCE.
+ codeVerifierKey = "code_verifier"
+)
+
+// PKCEParams holds parameters to support PKCE.
+type PKCEParams struct {
+ Challenge string // The unpadded, base64-url-encoded string of the encrypted code verifier.
+ ChallengeMethod string // The encryption method (ex. S256).
+ Verifier string // The original, non-encrypted secret.
+}
+
+// AuthorizationHandler is a 3-legged-OAuth helper that prompts
+// the user for OAuth consent at the specified auth code URL
+// and returns an auth code and state upon approval.
+type AuthorizationHandler func(authCodeURL string) (code string, state string, err error)
+
+// TokenSourceWithPKCE is an enhanced version of TokenSource with PKCE support.
+//
+// The pkce parameter supports PKCE flow, which uses code challenge and code verifier
+// to prevent CSRF attacks. A unique code challenge and code verifier should be generated
+// by the caller at runtime. See https://www.oauth.com/oauth2-servers/pkce/ for more info.
+func TokenSourceWithPKCE(ctx context.Context, config *oauth2.Config, state string, authHandler AuthorizationHandler, pkce *PKCEParams) oauth2.TokenSource {
+ return oauth2.ReuseTokenSource(nil, authHandlerSource{config: config, ctx: ctx, authHandler: authHandler, state: state, pkce: pkce})
+}
+
+// TokenSource returns an oauth2.TokenSource that fetches access tokens
+// using 3-legged-OAuth flow.
+//
+// The provided context.Context is used for oauth2 Exchange operation.
+//
+// The provided oauth2.Config should be a full configuration containing AuthURL,
+// TokenURL, and Scope.
+//
+// An environment-specific AuthorizationHandler is used to obtain user consent.
+//
+// Per the OAuth protocol, a unique "state" string should be specified here.
+// This token source will verify that the "state" is identical in the request
+// and response before exchanging the auth code for OAuth token to prevent CSRF
+// attacks.
+func TokenSource(ctx context.Context, config *oauth2.Config, state string, authHandler AuthorizationHandler) oauth2.TokenSource {
+ return TokenSourceWithPKCE(ctx, config, state, authHandler, nil)
+}
+
+type authHandlerSource struct {
+ ctx context.Context
+ config *oauth2.Config
+ authHandler AuthorizationHandler
+ state string
+ pkce *PKCEParams
+}
+
+func (source authHandlerSource) Token() (*oauth2.Token, error) {
+ // Step 1: Obtain auth code.
+ var authCodeUrlOptions []oauth2.AuthCodeOption
+ if source.pkce != nil && source.pkce.Challenge != "" && source.pkce.ChallengeMethod != "" {
+ authCodeUrlOptions = []oauth2.AuthCodeOption{oauth2.SetAuthURLParam(codeChallengeKey, source.pkce.Challenge),
+ oauth2.SetAuthURLParam(codeChallengeMethodKey, source.pkce.ChallengeMethod)}
+ }
+ url := source.config.AuthCodeURL(source.state, authCodeUrlOptions...)
+ code, state, err := source.authHandler(url)
+ if err != nil {
+ return nil, err
+ }
+ if state != source.state {
+ return nil, errors.New("state mismatch in 3-legged-OAuth flow")
+ }
+
+ // Step 2: Exchange auth code for access token.
+ var exchangeOptions []oauth2.AuthCodeOption
+ if source.pkce != nil && source.pkce.Verifier != "" {
+ exchangeOptions = []oauth2.AuthCodeOption{oauth2.SetAuthURLParam(codeVerifierKey, source.pkce.Verifier)}
+ }
+ return source.config.Exchange(source.ctx, code, exchangeOptions...)
+}
diff --git a/vendor/golang.org/x/oauth2/authhandler/ya.make b/vendor/golang.org/x/oauth2/authhandler/ya.make
new file mode 100644
index 0000000000..666ad8a98b
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/authhandler/ya.make
@@ -0,0 +1,15 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ authhandler.go
+)
+
+GO_TEST_SRCS(authhandler_test.go)
+
+END()
+
+RECURSE(
+ gotest
+)
diff --git a/vendor/golang.org/x/oauth2/deviceauth.go b/vendor/golang.org/x/oauth2/deviceauth.go
new file mode 100644
index 0000000000..e99c92f39c
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/deviceauth.go
@@ -0,0 +1,198 @@
+package oauth2
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "golang.org/x/oauth2/internal"
+)
+
+// https://datatracker.ietf.org/doc/html/rfc8628#section-3.5
+const (
+ errAuthorizationPending = "authorization_pending"
+ errSlowDown = "slow_down"
+ errAccessDenied = "access_denied"
+ errExpiredToken = "expired_token"
+)
+
+// DeviceAuthResponse describes a successful RFC 8628 Device Authorization Response
+// https://datatracker.ietf.org/doc/html/rfc8628#section-3.2
+type DeviceAuthResponse struct {
+ // DeviceCode
+ DeviceCode string `json:"device_code"`
+ // UserCode is the code the user should enter at the verification uri
+ UserCode string `json:"user_code"`
+ // VerificationURI is where user should enter the user code
+ VerificationURI string `json:"verification_uri"`
+ // VerificationURIComplete (if populated) includes the user code in the verification URI. This is typically shown to the user in non-textual form, such as a QR code.
+ VerificationURIComplete string `json:"verification_uri_complete,omitempty"`
+ // Expiry is when the device code and user code expire
+ Expiry time.Time `json:"expires_in,omitempty"`
+ // Interval is the duration in seconds that Poll should wait between requests
+ Interval int64 `json:"interval,omitempty"`
+}
+
+func (d DeviceAuthResponse) MarshalJSON() ([]byte, error) {
+ type Alias DeviceAuthResponse
+ var expiresIn int64
+ if !d.Expiry.IsZero() {
+ expiresIn = int64(time.Until(d.Expiry).Seconds())
+ }
+ return json.Marshal(&struct {
+ ExpiresIn int64 `json:"expires_in,omitempty"`
+ *Alias
+ }{
+ ExpiresIn: expiresIn,
+ Alias: (*Alias)(&d),
+ })
+
+}
+
+func (c *DeviceAuthResponse) UnmarshalJSON(data []byte) error {
+ type Alias DeviceAuthResponse
+ aux := &struct {
+ ExpiresIn int64 `json:"expires_in"`
+ // workaround misspelling of verification_uri
+ VerificationURL string `json:"verification_url"`
+ *Alias
+ }{
+ Alias: (*Alias)(c),
+ }
+ if err := json.Unmarshal(data, &aux); err != nil {
+ return err
+ }
+ if aux.ExpiresIn != 0 {
+ c.Expiry = time.Now().UTC().Add(time.Second * time.Duration(aux.ExpiresIn))
+ }
+ if c.VerificationURI == "" {
+ c.VerificationURI = aux.VerificationURL
+ }
+ return nil
+}
+
+// DeviceAuth returns a device auth struct which contains a device code
+// and authorization information provided for users to enter on another device.
+func (c *Config) DeviceAuth(ctx context.Context, opts ...AuthCodeOption) (*DeviceAuthResponse, error) {
+ // https://datatracker.ietf.org/doc/html/rfc8628#section-3.1
+ v := url.Values{
+ "client_id": {c.ClientID},
+ }
+ if len(c.Scopes) > 0 {
+ v.Set("scope", strings.Join(c.Scopes, " "))
+ }
+ for _, opt := range opts {
+ opt.setValue(v)
+ }
+ return retrieveDeviceAuth(ctx, c, v)
+}
+
+func retrieveDeviceAuth(ctx context.Context, c *Config, v url.Values) (*DeviceAuthResponse, error) {
+ if c.Endpoint.DeviceAuthURL == "" {
+ return nil, errors.New("endpoint missing DeviceAuthURL")
+ }
+
+ req, err := http.NewRequest("POST", c.Endpoint.DeviceAuthURL, strings.NewReader(v.Encode()))
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ req.Header.Set("Accept", "application/json")
+
+ t := time.Now()
+ r, err := internal.ContextClient(ctx).Do(req)
+ if err != nil {
+ return nil, err
+ }
+
+ body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20))
+ if err != nil {
+ return nil, fmt.Errorf("oauth2: cannot auth device: %v", err)
+ }
+ if code := r.StatusCode; code < 200 || code > 299 {
+ return nil, &RetrieveError{
+ Response: r,
+ Body: body,
+ }
+ }
+
+ da := &DeviceAuthResponse{}
+ err = json.Unmarshal(body, &da)
+ if err != nil {
+ return nil, fmt.Errorf("unmarshal %s", err)
+ }
+
+ if !da.Expiry.IsZero() {
+ // Make a small adjustment to account for time taken by the request
+ da.Expiry = da.Expiry.Add(-time.Since(t))
+ }
+
+ return da, nil
+}
+
+// DeviceAccessToken polls the server to exchange a device code for a token.
+func (c *Config) DeviceAccessToken(ctx context.Context, da *DeviceAuthResponse, opts ...AuthCodeOption) (*Token, error) {
+ if !da.Expiry.IsZero() {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithDeadline(ctx, da.Expiry)
+ defer cancel()
+ }
+
+ // https://datatracker.ietf.org/doc/html/rfc8628#section-3.4
+ v := url.Values{
+ "client_id": {c.ClientID},
+ "grant_type": {"urn:ietf:params:oauth:grant-type:device_code"},
+ "device_code": {da.DeviceCode},
+ }
+ if len(c.Scopes) > 0 {
+ v.Set("scope", strings.Join(c.Scopes, " "))
+ }
+ for _, opt := range opts {
+ opt.setValue(v)
+ }
+
+ // "If no value is provided, clients MUST use 5 as the default."
+ // https://datatracker.ietf.org/doc/html/rfc8628#section-3.2
+ interval := da.Interval
+ if interval == 0 {
+ interval = 5
+ }
+
+ ticker := time.NewTicker(time.Duration(interval) * time.Second)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ case <-ticker.C:
+ tok, err := retrieveToken(ctx, c, v)
+ if err == nil {
+ return tok, nil
+ }
+
+ e, ok := err.(*RetrieveError)
+ if !ok {
+ return nil, err
+ }
+ switch e.ErrorCode {
+ case errSlowDown:
+ // https://datatracker.ietf.org/doc/html/rfc8628#section-3.5
+ // "the interval MUST be increased by 5 seconds for this and all subsequent requests"
+ interval += 5
+ ticker.Reset(time.Duration(interval) * time.Second)
+ case errAuthorizationPending:
+ // Do nothing.
+ case errAccessDenied, errExpiredToken:
+ fallthrough
+ default:
+ return tok, err
+ }
+ }
+ }
+}
diff --git a/vendor/golang.org/x/oauth2/google/appengine.go b/vendor/golang.org/x/oauth2/google/appengine.go
new file mode 100644
index 0000000000..feb1157b15
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/appengine.go
@@ -0,0 +1,38 @@
+// 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 (
+ "context"
+ "time"
+
+ "golang.org/x/oauth2"
+)
+
+// 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.
+var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
+
+// 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.
+var appengineAppIDFunc func(c context.Context) string
+
+// AppEngineTokenSource returns a token source that fetches tokens from either
+// the current application's service account or from the metadata server,
+// depending on the App Engine environment. See below for environment-specific
+// details. If you are implementing a 3-legged OAuth 2.0 flow on App Engine that
+// involves user accounts, see oauth2.Config instead.
+//
+// First generation App Engine runtimes (<= Go 1.9):
+// AppEngineTokenSource returns a token source that fetches tokens issued to the
+// current App Engine application's service account. The provided context must have
+// come from appengine.NewContext.
+//
+// Second generation App Engine runtimes (>= Go 1.11) and App Engine flexible:
+// AppEngineTokenSource is DEPRECATED on second generation runtimes and on the
+// flexible environment. It delegates to ComputeTokenSource, and the provided
+// context and scopes are not used. Please use DefaultTokenSource (or ComputeTokenSource,
+// which DefaultTokenSource will use in this case) instead.
+func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
+ return appEngineTokenSource(ctx, scope...)
+}
diff --git a/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go b/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go
new file mode 100644
index 0000000000..9c79aa0a0c
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go
@@ -0,0 +1,27 @@
+// 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.
+
+//go:build !appengine
+
+// This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible.
+
+package google
+
+import (
+ "context"
+ "log"
+ "sync"
+
+ "golang.org/x/oauth2"
+)
+
+var logOnce sync.Once // only spam about deprecation once
+
+// See comment on AppEngineTokenSource in appengine.go.
+func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
+ logOnce.Do(func() {
+ log.Print("google: AppEngineTokenSource is deprecated on App Engine standard second generation runtimes (>= Go 1.11) and App Engine flexible. Please use DefaultTokenSource or ComputeTokenSource.")
+ })
+ return ComputeTokenSource("")
+}
diff --git a/vendor/golang.org/x/oauth2/google/default.go b/vendor/golang.org/x/oauth2/google/default.go
new file mode 100644
index 0000000000..12b12a30c5
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/default.go
@@ -0,0 +1,259 @@
+// 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 google
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime"
+ "time"
+
+ "cloud.google.com/go/compute/metadata"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/authhandler"
+)
+
+const (
+ adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc"
+ universeDomainDefault = "googleapis.com"
+)
+
+// Credentials holds Google credentials, including "Application Default Credentials".
+// For more details, see:
+// https://developers.google.com/accounts/docs/application-default-credentials
+// Credentials from external accounts (workload identity federation) are used to
+// identify a particular application from an on-prem or non-Google Cloud platform
+// including Amazon Web Services (AWS), Microsoft Azure or any identity provider
+// that supports OpenID Connect (OIDC).
+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
+
+ // universeDomain is the default service domain for a given Cloud universe.
+ universeDomain string
+}
+
+// UniverseDomain returns the default service domain for a given Cloud universe.
+// The default value is "googleapis.com".
+func (c *Credentials) UniverseDomain() string {
+ if c.universeDomain == "" {
+ return universeDomainDefault
+ }
+ return c.universeDomain
+}
+
+// DefaultCredentials is the old name of Credentials.
+//
+// Deprecated: use Credentials instead.
+type DefaultCredentials = Credentials
+
+// CredentialsParams holds user supplied parameters that are used together
+// with a credentials file for building a Credentials object.
+type CredentialsParams struct {
+ // Scopes is the list OAuth scopes. Required.
+ // Example: https://www.googleapis.com/auth/cloud-platform
+ Scopes []string
+
+ // Subject is the user email used for domain wide delegation (see
+ // https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority).
+ // Optional.
+ Subject string
+
+ // AuthHandler is the AuthorizationHandler used for 3-legged OAuth flow. Required for 3LO flow.
+ AuthHandler authhandler.AuthorizationHandler
+
+ // State is a unique string used with AuthHandler. Required for 3LO flow.
+ State string
+
+ // PKCE is used to support PKCE flow. Optional for 3LO flow.
+ PKCE *authhandler.PKCEParams
+
+ // The OAuth2 TokenURL default override. This value overrides the default TokenURL,
+ // unless explicitly specified by the credentials config file. Optional.
+ TokenURL string
+
+ // EarlyTokenRefresh is the amount of time before a token expires that a new
+ // token will be preemptively fetched. If unset the default value is 10
+ // seconds.
+ //
+ // Note: This option is currently only respected when using credentials
+ // fetched from the GCE metadata server.
+ EarlyTokenRefresh time.Duration
+}
+
+func (params CredentialsParams) deepCopy() CredentialsParams {
+ paramsCopy := params
+ paramsCopy.Scopes = make([]string, len(params.Scopes))
+ copy(paramsCopy.Scopes, params.Scopes)
+ return paramsCopy
+}
+
+// DefaultClient returns an HTTP Client that uses the
+// DefaultTokenSource to obtain authentication 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 returns the token source for
+// "Application Default Credentials".
+// It is a shortcut for FindDefaultCredentials(ctx, scope).TokenSource.
+func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
+ creds, err := FindDefaultCredentials(ctx, scope...)
+ if err != nil {
+ return nil, err
+ }
+ return creds.TokenSource, nil
+}
+
+// FindDefaultCredentialsWithParams 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.
+// For workload identity federation, refer to
+// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation on
+// how to generate the JSON configuration file for on-prem/non-Google cloud
+// platforms.
+// 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 standard first generation runtimes (<= Go 1.9) it uses
+// the appengine.AccessToken function.
+// 4. On Google Compute Engine, Google App Engine standard second generation runtimes
+// (>= Go 1.11), and Google App Engine flexible environment, it fetches
+// credentials from the metadata server.
+func FindDefaultCredentialsWithParams(ctx context.Context, params CredentialsParams) (*Credentials, error) {
+ // Make defensive copy of the slices in params.
+ params = params.deepCopy()
+
+ // First, try the environment variable.
+ const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
+ if filename := os.Getenv(envVar); filename != "" {
+ creds, err := readCredentialsFile(ctx, filename, params)
+ if err != nil {
+ return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
+ }
+ return creds, nil
+ }
+
+ // Second, try a well-known file.
+ filename := wellKnownFile()
+ if b, err := os.ReadFile(filename); err == nil {
+ return CredentialsFromJSONWithParams(ctx, b, params)
+ }
+
+ // Third, if we're on a Google App Engine standard first generation runtime (<= Go 1.9)
+ // use those credentials. App Engine standard second generation runtimes (>= Go 1.11)
+ // and App Engine flexible use ComputeTokenSource and the metadata server.
+ if appengineTokenFunc != nil {
+ return &Credentials{
+ ProjectID: appengineAppIDFunc(ctx),
+ TokenSource: AppEngineTokenSource(ctx, params.Scopes...),
+ }, nil
+ }
+
+ // Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime,
+ // or App Engine flexible, use the metadata server.
+ if metadata.OnGCE() {
+ id, _ := metadata.ProjectID()
+ return &Credentials{
+ ProjectID: id,
+ TokenSource: computeTokenSource("", params.EarlyTokenRefresh, params.Scopes...),
+ }, nil
+ }
+
+ // None are found; return helpful error.
+ return nil, fmt.Errorf("google: could not find default credentials. See %v for more information", adcSetupURL)
+}
+
+// FindDefaultCredentials invokes FindDefaultCredentialsWithParams with the specified scopes.
+func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
+ var params CredentialsParams
+ params.Scopes = scopes
+ return FindDefaultCredentialsWithParams(ctx, params)
+}
+
+// CredentialsFromJSONWithParams obtains Google credentials from a JSON value. The JSON can
+// represent either a Google Developers Console client_credentials.json file (as in ConfigFromJSON),
+// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh
+// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud
+// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
+func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params CredentialsParams) (*Credentials, error) {
+ // Make defensive copy of the slices in params.
+ params = params.deepCopy()
+
+ // First, attempt to parse jsonData as a Google Developers Console client_credentials.json.
+ config, _ := ConfigFromJSON(jsonData, params.Scopes...)
+ if config != nil {
+ return &Credentials{
+ ProjectID: "",
+ TokenSource: authhandler.TokenSourceWithPKCE(ctx, config, params.State, params.AuthHandler, params.PKCE),
+ JSON: jsonData,
+ }, nil
+ }
+
+ // Otherwise, parse jsonData as one of the other supported credentials files.
+ var f credentialsFile
+ if err := json.Unmarshal(jsonData, &f); err != nil {
+ return nil, err
+ }
+
+ universeDomain := f.UniverseDomain
+ // Authorized user credentials are only supported in the googleapis.com universe.
+ if f.Type == userCredentialsKey {
+ universeDomain = universeDomainDefault
+ }
+
+ ts, err := f.tokenSource(ctx, params)
+ if err != nil {
+ return nil, err
+ }
+ ts = newErrWrappingTokenSource(ts)
+ return &Credentials{
+ ProjectID: f.ProjectID,
+ TokenSource: ts,
+ JSON: jsonData,
+ universeDomain: universeDomain,
+ }, nil
+}
+
+// CredentialsFromJSON invokes CredentialsFromJSONWithParams with the specified scopes.
+func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
+ var params CredentialsParams
+ params.Scopes = scopes
+ return CredentialsFromJSONWithParams(ctx, jsonData, params)
+}
+
+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 readCredentialsFile(ctx context.Context, filename string, params CredentialsParams) (*Credentials, error) {
+ b, err := os.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return CredentialsFromJSONWithParams(ctx, b, params)
+}
diff --git a/vendor/golang.org/x/oauth2/google/doc.go b/vendor/golang.org/x/oauth2/google/doc.go
new file mode 100644
index 0000000000..ca717634a3
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/doc.go
@@ -0,0 +1,133 @@
+// 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 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,
+// Google App Engine service accounts and workload identity federation
+// from non-Google cloud platforms.
+//
+// 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.
+// For more information on using workload identity federation, refer to
+// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation.
+//
+// # 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.
+//
+// # Workload Identity Federation
+//
+// Using workload identity federation, your application can access Google Cloud
+// resources from Amazon Web Services (AWS), Microsoft Azure or any identity
+// provider that supports OpenID Connect (OIDC) or SAML 2.0.
+// Traditionally, applications running outside Google Cloud have used service
+// account keys to access Google Cloud resources. Using identity federation,
+// you can allow your workload to impersonate a service account.
+// This lets you access Google Cloud resources directly, eliminating the
+// maintenance and security burden associated with service account keys.
+//
+// Follow the detailed instructions on how to configure Workload Identity Federation
+// in various platforms:
+//
+// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#aws
+// Microsoft Azure: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#azure
+// OIDC identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#oidc
+// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#saml
+//
+// For OIDC and SAML providers, the library can retrieve tokens in three ways:
+// from a local file location (file-sourced credentials), from a server
+// (URL-sourced credentials), or from a local executable (executable-sourced
+// credentials).
+// For file-sourced credentials, a background process needs to be continuously
+// refreshing the file location with a new OIDC/SAML token prior to expiration.
+// For tokens with one hour lifetimes, the token needs to be updated in the file
+// every hour. The token can be stored directly as plain text or in JSON format.
+// For URL-sourced credentials, a local server needs to host a GET endpoint to
+// return the OIDC/SAML token. The response can be in plain text or JSON.
+// Additional required request headers can also be specified.
+// For executable-sourced credentials, an application needs to be available to
+// output the OIDC/SAML token and other information in a JSON format.
+// For more information on how these work (and how to implement
+// executable-sourced credentials), please check out:
+// https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#create_a_credential_configuration
+//
+// Note that this library does not perform any validation on the token_url, token_info_url,
+// or service_account_impersonation_url fields of the credential configuration.
+// It is not recommended to use a credential configuration that you did not generate with
+// the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain.
+//
+// # Workforce Identity Federation
+//
+// Workforce identity federation lets you use an external identity provider (IdP) to
+// authenticate and authorize a workforce—a group of users, such as employees, partners,
+// and contractors—using IAM, so that the users can access Google Cloud services.
+// Workforce identity federation extends Google Cloud's identity capabilities to support
+// syncless, attribute-based single sign on.
+//
+// With workforce identity federation, your workforce can access Google Cloud resources
+// using an external identity provider (IdP) that supports OpenID Connect (OIDC) or
+// SAML 2.0 such as Azure Active Directory (Azure AD), Active Directory Federation
+// Services (AD FS), Okta, and others.
+//
+// Follow the detailed instructions on how to configure Workload Identity Federation
+// in various platforms:
+//
+// Azure AD: https://cloud.google.com/iam/docs/workforce-sign-in-azure-ad
+// Okta: https://cloud.google.com/iam/docs/workforce-sign-in-okta
+// OIDC identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#oidc
+// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#saml
+//
+// For workforce identity federation, the library can retrieve tokens in three ways:
+// from a local file location (file-sourced credentials), from a server
+// (URL-sourced credentials), or from a local executable (executable-sourced
+// credentials).
+// For file-sourced credentials, a background process needs to be continuously
+// refreshing the file location with a new OIDC/SAML token prior to expiration.
+// For tokens with one hour lifetimes, the token needs to be updated in the file
+// every hour. The token can be stored directly as plain text or in JSON format.
+// For URL-sourced credentials, a local server needs to host a GET endpoint to
+// return the OIDC/SAML token. The response can be in plain text or JSON.
+// Additional required request headers can also be specified.
+// For executable-sourced credentials, an application needs to be available to
+// output the OIDC/SAML token and other information in a JSON format.
+// For more information on how these work (and how to implement
+// executable-sourced credentials), please check out:
+// https://cloud.google.com/iam/docs/workforce-obtaining-short-lived-credentials#generate_a_configuration_file_for_non-interactive_sign-in
+//
+// Note that this library does not perform any validation on the token_url, token_info_url,
+// or service_account_impersonation_url fields of the credential configuration.
+// It is not recommended to use a credential configuration that you did not generate with
+// the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain.
+//
+// # 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.
+//
+// Application Default Credentials also support workload identity federation to
+// access Google Cloud resources from non-Google Cloud platforms including Amazon
+// Web Services (AWS), Microsoft Azure or any identity provider that supports
+// OpenID Connect (OIDC). Workload identity federation is recommended for
+// non-Google Cloud environments as it avoids the need to download, manage and
+// store service account private keys locally.
+//
+// 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"
diff --git a/vendor/golang.org/x/oauth2/google/error.go b/vendor/golang.org/x/oauth2/google/error.go
new file mode 100644
index 0000000000..d84dd00473
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/error.go
@@ -0,0 +1,64 @@
+// Copyright 2022 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 (
+ "errors"
+
+ "golang.org/x/oauth2"
+)
+
+// AuthenticationError indicates there was an error in the authentication flow.
+//
+// Use (*AuthenticationError).Temporary to check if the error can be retried.
+type AuthenticationError struct {
+ err *oauth2.RetrieveError
+}
+
+func newAuthenticationError(err error) error {
+ re := &oauth2.RetrieveError{}
+ if !errors.As(err, &re) {
+ return err
+ }
+ return &AuthenticationError{
+ err: re,
+ }
+}
+
+// Temporary indicates that the network error has one of the following status codes and may be retried: 500, 503, 408, or 429.
+func (e *AuthenticationError) Temporary() bool {
+ if e.err.Response == nil {
+ return false
+ }
+ sc := e.err.Response.StatusCode
+ return sc == 500 || sc == 503 || sc == 408 || sc == 429
+}
+
+func (e *AuthenticationError) Error() string {
+ return e.err.Error()
+}
+
+func (e *AuthenticationError) Unwrap() error {
+ return e.err
+}
+
+type errWrappingTokenSource struct {
+ src oauth2.TokenSource
+}
+
+func newErrWrappingTokenSource(ts oauth2.TokenSource) oauth2.TokenSource {
+ return &errWrappingTokenSource{src: ts}
+}
+
+// Token returns the current token if it's still valid, else will
+// refresh the current token (using r.Context for HTTP client
+// information) and return the new one.
+func (s *errWrappingTokenSource) Token() (*oauth2.Token, error) {
+ t, err := s.src.Token()
+ if err != nil {
+ return nil, newAuthenticationError(err)
+ }
+ return t, nil
+}
diff --git a/vendor/golang.org/x/oauth2/google/google.go b/vendor/golang.org/x/oauth2/google/google.go
new file mode 100644
index 0000000000..c66c53527d
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/google.go
@@ -0,0 +1,308 @@
+// 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 (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/url"
+ "strings"
+ "time"
+
+ "cloud.google.com/go/compute/metadata"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google/internal/externalaccount"
+ "golang.org/x/oauth2/google/internal/externalaccountauthorizeduser"
+ "golang.org/x/oauth2/jwt"
+)
+
+// Endpoint is Google's OAuth 2.0 default endpoint.
+var Endpoint = oauth2.Endpoint{
+ AuthURL: "https://accounts.google.com/o/oauth2/auth",
+ TokenURL: "https://oauth2.googleapis.com/token",
+ DeviceAuthURL: "https://oauth2.googleapis.com/device/code",
+ AuthStyle: oauth2.AuthStyleInParams,
+}
+
+// MTLSTokenURL is Google's OAuth 2.0 default mTLS endpoint.
+const MTLSTokenURL = "https://oauth2.mtls.googleapis.com/token"
+
+// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
+const JWTTokenURL = "https://oauth2.googleapis.com/token"
+
+// ConfigFromJSON uses a Google Developers Console client_credentials.json
+// file to construct a config.
+// client_credentials.json can be downloaded from
+// https://console.developers.google.com, under "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" 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 f credentialsFile
+ if err := json.Unmarshal(jsonKey, &f); err != nil {
+ return nil, err
+ }
+ if f.Type != serviceAccountKey {
+ return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
+ }
+ scope = append([]string(nil), scope...) // copy
+ return f.jwtConfig(scope, ""), nil
+}
+
+// JSON key file types.
+const (
+ serviceAccountKey = "service_account"
+ userCredentialsKey = "authorized_user"
+ externalAccountKey = "external_account"
+ externalAccountAuthorizedUserKey = "external_account_authorized_user"
+ impersonatedServiceAccount = "impersonated_service_account"
+)
+
+// credentialsFile is the unmarshalled representation of a credentials file.
+type credentialsFile struct {
+ Type string `json:"type"`
+
+ // Service Account fields
+ ClientEmail string `json:"client_email"`
+ PrivateKeyID string `json:"private_key_id"`
+ PrivateKey string `json:"private_key"`
+ AuthURL string `json:"auth_uri"`
+ TokenURL string `json:"token_uri"`
+ ProjectID string `json:"project_id"`
+ UniverseDomain string `json:"universe_domain"`
+
+ // User Credential fields
+ // (These typically come from gcloud auth.)
+ ClientSecret string `json:"client_secret"`
+ ClientID string `json:"client_id"`
+ RefreshToken string `json:"refresh_token"`
+
+ // External Account fields
+ Audience string `json:"audience"`
+ SubjectTokenType string `json:"subject_token_type"`
+ TokenURLExternal string `json:"token_url"`
+ TokenInfoURL string `json:"token_info_url"`
+ ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
+ ServiceAccountImpersonation serviceAccountImpersonationInfo `json:"service_account_impersonation"`
+ Delegates []string `json:"delegates"`
+ CredentialSource externalaccount.CredentialSource `json:"credential_source"`
+ QuotaProjectID string `json:"quota_project_id"`
+ WorkforcePoolUserProject string `json:"workforce_pool_user_project"`
+
+ // External Account Authorized User fields
+ RevokeURL string `json:"revoke_url"`
+
+ // Service account impersonation
+ SourceCredentials *credentialsFile `json:"source_credentials"`
+}
+
+type serviceAccountImpersonationInfo struct {
+ TokenLifetimeSeconds int `json:"token_lifetime_seconds"`
+}
+
+func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config {
+ cfg := &jwt.Config{
+ Email: f.ClientEmail,
+ PrivateKey: []byte(f.PrivateKey),
+ PrivateKeyID: f.PrivateKeyID,
+ Scopes: scopes,
+ TokenURL: f.TokenURL,
+ Subject: subject, // This is the user email to impersonate
+ Audience: f.Audience,
+ }
+ if cfg.TokenURL == "" {
+ cfg.TokenURL = JWTTokenURL
+ }
+ return cfg
+}
+
+func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsParams) (oauth2.TokenSource, error) {
+ switch f.Type {
+ case serviceAccountKey:
+ cfg := f.jwtConfig(params.Scopes, params.Subject)
+ return cfg.TokenSource(ctx), nil
+ case userCredentialsKey:
+ cfg := &oauth2.Config{
+ ClientID: f.ClientID,
+ ClientSecret: f.ClientSecret,
+ Scopes: params.Scopes,
+ Endpoint: oauth2.Endpoint{
+ AuthURL: f.AuthURL,
+ TokenURL: f.TokenURL,
+ AuthStyle: oauth2.AuthStyleInParams,
+ },
+ }
+ if cfg.Endpoint.AuthURL == "" {
+ cfg.Endpoint.AuthURL = Endpoint.AuthURL
+ }
+ if cfg.Endpoint.TokenURL == "" {
+ if params.TokenURL != "" {
+ cfg.Endpoint.TokenURL = params.TokenURL
+ } else {
+ cfg.Endpoint.TokenURL = Endpoint.TokenURL
+ }
+ }
+ tok := &oauth2.Token{RefreshToken: f.RefreshToken}
+ return cfg.TokenSource(ctx, tok), nil
+ case externalAccountKey:
+ cfg := &externalaccount.Config{
+ Audience: f.Audience,
+ SubjectTokenType: f.SubjectTokenType,
+ TokenURL: f.TokenURLExternal,
+ TokenInfoURL: f.TokenInfoURL,
+ ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
+ ServiceAccountImpersonationLifetimeSeconds: f.ServiceAccountImpersonation.TokenLifetimeSeconds,
+ ClientSecret: f.ClientSecret,
+ ClientID: f.ClientID,
+ CredentialSource: f.CredentialSource,
+ QuotaProjectID: f.QuotaProjectID,
+ Scopes: params.Scopes,
+ WorkforcePoolUserProject: f.WorkforcePoolUserProject,
+ }
+ return cfg.TokenSource(ctx)
+ case externalAccountAuthorizedUserKey:
+ cfg := &externalaccountauthorizeduser.Config{
+ Audience: f.Audience,
+ RefreshToken: f.RefreshToken,
+ TokenURL: f.TokenURLExternal,
+ TokenInfoURL: f.TokenInfoURL,
+ ClientID: f.ClientID,
+ ClientSecret: f.ClientSecret,
+ RevokeURL: f.RevokeURL,
+ QuotaProjectID: f.QuotaProjectID,
+ Scopes: params.Scopes,
+ }
+ return cfg.TokenSource(ctx)
+ case impersonatedServiceAccount:
+ if f.ServiceAccountImpersonationURL == "" || f.SourceCredentials == nil {
+ return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials")
+ }
+
+ ts, err := f.SourceCredentials.tokenSource(ctx, params)
+ if err != nil {
+ return nil, err
+ }
+ imp := externalaccount.ImpersonateTokenSource{
+ Ctx: ctx,
+ URL: f.ServiceAccountImpersonationURL,
+ Scopes: params.Scopes,
+ Ts: ts,
+ Delegates: f.Delegates,
+ }
+ return oauth2.ReuseTokenSource(nil, imp), nil
+ case "":
+ return nil, errors.New("missing 'type' field in credentials")
+ default:
+ return nil, fmt.Errorf("unknown credential type: %q", f.Type)
+ }
+}
+
+// ComputeTokenSource returns a token source that fetches access tokens
+// from Google Compute Engine (GCE)'s metadata server. It's only valid to use
+// this token source if your program is running on a GCE instance.
+// If no account is specified, "default" is used.
+// If no scopes are specified, a set of default scopes are automatically granted.
+// 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, scope ...string) oauth2.TokenSource {
+ return computeTokenSource(account, 0, scope...)
+}
+
+func computeTokenSource(account string, earlyExpiry time.Duration, scope ...string) oauth2.TokenSource {
+ return oauth2.ReuseTokenSourceWithExpiry(nil, computeSource{account: account, scopes: scope}, earlyExpiry)
+}
+
+type computeSource struct {
+ account string
+ scopes []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"
+ }
+ tokenURI := "instance/service-accounts/" + acct + "/token"
+ if len(cs.scopes) > 0 {
+ v := url.Values{}
+ v.Set("scopes", strings.Join(cs.scopes, ","))
+ tokenURI = tokenURI + "?" + v.Encode()
+ }
+ tokenJSON, err := metadata.Get(tokenURI)
+ 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")
+ }
+ tok := &oauth2.Token{
+ AccessToken: res.AccessToken,
+ TokenType: res.TokenType,
+ Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
+ }
+ // NOTE(cbro): add hidden metadata about where the token is from.
+ // This is needed for detection by client libraries to know that credentials come from the metadata server.
+ // This may be removed in a future version of this library.
+ return tok.WithExtra(map[string]interface{}{
+ "oauth2.google.tokenSource": "compute-metadata",
+ "oauth2.google.serviceAccount": acct,
+ }), nil
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go
new file mode 100644
index 0000000000..bd4efd19ba
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go
@@ -0,0 +1,556 @@
+// Copyright 2021 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 externalaccount
+
+import (
+ "bytes"
+ "context"
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
+ "path"
+ "sort"
+ "strings"
+ "time"
+
+ "golang.org/x/oauth2"
+)
+
+type awsSecurityCredentials struct {
+ AccessKeyID string `json:"AccessKeyID"`
+ SecretAccessKey string `json:"SecretAccessKey"`
+ SecurityToken string `json:"Token"`
+}
+
+// awsRequestSigner is a utility class to sign http requests using a AWS V4 signature.
+type awsRequestSigner struct {
+ RegionName string
+ AwsSecurityCredentials awsSecurityCredentials
+}
+
+// getenv aliases os.Getenv for testing
+var getenv = os.Getenv
+
+const (
+ // AWS Signature Version 4 signing algorithm identifier.
+ awsAlgorithm = "AWS4-HMAC-SHA256"
+
+ // The termination string for the AWS credential scope value as defined in
+ // https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
+ awsRequestType = "aws4_request"
+
+ // The AWS authorization header name for the security session token if available.
+ awsSecurityTokenHeader = "x-amz-security-token"
+
+ // The name of the header containing the session token for metadata endpoint calls
+ awsIMDSv2SessionTokenHeader = "X-aws-ec2-metadata-token"
+
+ awsIMDSv2SessionTtlHeader = "X-aws-ec2-metadata-token-ttl-seconds"
+
+ awsIMDSv2SessionTtl = "300"
+
+ // The AWS authorization header name for the auto-generated date.
+ awsDateHeader = "x-amz-date"
+
+ // Supported AWS configuration environment variables.
+ awsAccessKeyId = "AWS_ACCESS_KEY_ID"
+ awsDefaultRegion = "AWS_DEFAULT_REGION"
+ awsRegion = "AWS_REGION"
+ awsSecretAccessKey = "AWS_SECRET_ACCESS_KEY"
+ awsSessionToken = "AWS_SESSION_TOKEN"
+
+ awsTimeFormatLong = "20060102T150405Z"
+ awsTimeFormatShort = "20060102"
+)
+
+func getSha256(input []byte) (string, error) {
+ hash := sha256.New()
+ if _, err := hash.Write(input); err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(hash.Sum(nil)), nil
+}
+
+func getHmacSha256(key, input []byte) ([]byte, error) {
+ hash := hmac.New(sha256.New, key)
+ if _, err := hash.Write(input); err != nil {
+ return nil, err
+ }
+ return hash.Sum(nil), nil
+}
+
+func cloneRequest(r *http.Request) *http.Request {
+ r2 := new(http.Request)
+ *r2 = *r
+ if r.Header != nil {
+ r2.Header = make(http.Header, len(r.Header))
+
+ // Find total number of values.
+ headerCount := 0
+ for _, headerValues := range r.Header {
+ headerCount += len(headerValues)
+ }
+ copiedHeaders := make([]string, headerCount) // shared backing array for headers' values
+
+ for headerKey, headerValues := range r.Header {
+ headerCount = copy(copiedHeaders, headerValues)
+ r2.Header[headerKey] = copiedHeaders[:headerCount:headerCount]
+ copiedHeaders = copiedHeaders[headerCount:]
+ }
+ }
+ return r2
+}
+
+func canonicalPath(req *http.Request) string {
+ result := req.URL.EscapedPath()
+ if result == "" {
+ return "/"
+ }
+ return path.Clean(result)
+}
+
+func canonicalQuery(req *http.Request) string {
+ queryValues := req.URL.Query()
+ for queryKey := range queryValues {
+ sort.Strings(queryValues[queryKey])
+ }
+ return queryValues.Encode()
+}
+
+func canonicalHeaders(req *http.Request) (string, string) {
+ // Header keys need to be sorted alphabetically.
+ var headers []string
+ lowerCaseHeaders := make(http.Header)
+ for k, v := range req.Header {
+ k := strings.ToLower(k)
+ if _, ok := lowerCaseHeaders[k]; ok {
+ // include additional values
+ lowerCaseHeaders[k] = append(lowerCaseHeaders[k], v...)
+ } else {
+ headers = append(headers, k)
+ lowerCaseHeaders[k] = v
+ }
+ }
+ sort.Strings(headers)
+
+ var fullHeaders bytes.Buffer
+ for _, header := range headers {
+ headerValue := strings.Join(lowerCaseHeaders[header], ",")
+ fullHeaders.WriteString(header)
+ fullHeaders.WriteRune(':')
+ fullHeaders.WriteString(headerValue)
+ fullHeaders.WriteRune('\n')
+ }
+
+ return strings.Join(headers, ";"), fullHeaders.String()
+}
+
+func requestDataHash(req *http.Request) (string, error) {
+ var requestData []byte
+ if req.Body != nil {
+ requestBody, err := req.GetBody()
+ if err != nil {
+ return "", err
+ }
+ defer requestBody.Close()
+
+ requestData, err = ioutil.ReadAll(io.LimitReader(requestBody, 1<<20))
+ if err != nil {
+ return "", err
+ }
+ }
+
+ return getSha256(requestData)
+}
+
+func requestHost(req *http.Request) string {
+ if req.Host != "" {
+ return req.Host
+ }
+ return req.URL.Host
+}
+
+func canonicalRequest(req *http.Request, canonicalHeaderColumns, canonicalHeaderData string) (string, error) {
+ dataHash, err := requestDataHash(req)
+ if err != nil {
+ return "", err
+ }
+
+ return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", req.Method, canonicalPath(req), canonicalQuery(req), canonicalHeaderData, canonicalHeaderColumns, dataHash), nil
+}
+
+// SignRequest adds the appropriate headers to an http.Request
+// or returns an error if something prevented this.
+func (rs *awsRequestSigner) SignRequest(req *http.Request) error {
+ signedRequest := cloneRequest(req)
+ timestamp := now()
+
+ signedRequest.Header.Add("host", requestHost(req))
+
+ if rs.AwsSecurityCredentials.SecurityToken != "" {
+ signedRequest.Header.Add(awsSecurityTokenHeader, rs.AwsSecurityCredentials.SecurityToken)
+ }
+
+ if signedRequest.Header.Get("date") == "" {
+ signedRequest.Header.Add(awsDateHeader, timestamp.Format(awsTimeFormatLong))
+ }
+
+ authorizationCode, err := rs.generateAuthentication(signedRequest, timestamp)
+ if err != nil {
+ return err
+ }
+ signedRequest.Header.Set("Authorization", authorizationCode)
+
+ req.Header = signedRequest.Header
+ return nil
+}
+
+func (rs *awsRequestSigner) generateAuthentication(req *http.Request, timestamp time.Time) (string, error) {
+ canonicalHeaderColumns, canonicalHeaderData := canonicalHeaders(req)
+
+ dateStamp := timestamp.Format(awsTimeFormatShort)
+ serviceName := ""
+ if splitHost := strings.Split(requestHost(req), "."); len(splitHost) > 0 {
+ serviceName = splitHost[0]
+ }
+
+ credentialScope := fmt.Sprintf("%s/%s/%s/%s", dateStamp, rs.RegionName, serviceName, awsRequestType)
+
+ requestString, err := canonicalRequest(req, canonicalHeaderColumns, canonicalHeaderData)
+ if err != nil {
+ return "", err
+ }
+ requestHash, err := getSha256([]byte(requestString))
+ if err != nil {
+ return "", err
+ }
+
+ stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s", awsAlgorithm, timestamp.Format(awsTimeFormatLong), credentialScope, requestHash)
+
+ signingKey := []byte("AWS4" + rs.AwsSecurityCredentials.SecretAccessKey)
+ for _, signingInput := range []string{
+ dateStamp, rs.RegionName, serviceName, awsRequestType, stringToSign,
+ } {
+ signingKey, err = getHmacSha256(signingKey, []byte(signingInput))
+ if err != nil {
+ return "", err
+ }
+ }
+
+ return fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", awsAlgorithm, rs.AwsSecurityCredentials.AccessKeyID, credentialScope, canonicalHeaderColumns, hex.EncodeToString(signingKey)), nil
+}
+
+type awsCredentialSource struct {
+ EnvironmentID string
+ RegionURL string
+ RegionalCredVerificationURL string
+ CredVerificationURL string
+ IMDSv2SessionTokenURL string
+ TargetResource string
+ requestSigner *awsRequestSigner
+ region string
+ ctx context.Context
+ client *http.Client
+}
+
+type awsRequestHeader struct {
+ Key string `json:"key"`
+ Value string `json:"value"`
+}
+
+type awsRequest struct {
+ URL string `json:"url"`
+ Method string `json:"method"`
+ Headers []awsRequestHeader `json:"headers"`
+}
+
+func (cs awsCredentialSource) doRequest(req *http.Request) (*http.Response, error) {
+ if cs.client == nil {
+ cs.client = oauth2.NewClient(cs.ctx, nil)
+ }
+ return cs.client.Do(req.WithContext(cs.ctx))
+}
+
+func canRetrieveRegionFromEnvironment() bool {
+ // The AWS region can be provided through AWS_REGION or AWS_DEFAULT_REGION. Only one is
+ // required.
+ return getenv(awsRegion) != "" || getenv(awsDefaultRegion) != ""
+}
+
+func canRetrieveSecurityCredentialFromEnvironment() bool {
+ // Check if both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are available.
+ return getenv(awsAccessKeyId) != "" && getenv(awsSecretAccessKey) != ""
+}
+
+func shouldUseMetadataServer() bool {
+ return !canRetrieveRegionFromEnvironment() || !canRetrieveSecurityCredentialFromEnvironment()
+}
+
+func (cs awsCredentialSource) credentialSourceType() string {
+ return "aws"
+}
+
+func (cs awsCredentialSource) subjectToken() (string, error) {
+ if cs.requestSigner == nil {
+ headers := make(map[string]string)
+ if shouldUseMetadataServer() {
+ awsSessionToken, err := cs.getAWSSessionToken()
+ if err != nil {
+ return "", err
+ }
+
+ if awsSessionToken != "" {
+ headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
+ }
+ }
+
+ awsSecurityCredentials, err := cs.getSecurityCredentials(headers)
+ if err != nil {
+ return "", err
+ }
+
+ if cs.region, err = cs.getRegion(headers); err != nil {
+ return "", err
+ }
+
+ cs.requestSigner = &awsRequestSigner{
+ RegionName: cs.region,
+ AwsSecurityCredentials: awsSecurityCredentials,
+ }
+ }
+
+ // Generate the signed request to AWS STS GetCallerIdentity API.
+ // Use the required regional endpoint. Otherwise, the request will fail.
+ req, err := http.NewRequest("POST", strings.Replace(cs.RegionalCredVerificationURL, "{region}", cs.region, 1), nil)
+ if err != nil {
+ return "", err
+ }
+ // The full, canonical resource name of the workload identity pool
+ // provider, with or without the HTTPS prefix.
+ // Including this header as part of the signature is recommended to
+ // ensure data integrity.
+ if cs.TargetResource != "" {
+ req.Header.Add("x-goog-cloud-target-resource", cs.TargetResource)
+ }
+ cs.requestSigner.SignRequest(req)
+
+ /*
+ The GCP STS endpoint expects the headers to be formatted as:
+ # [
+ # {key: 'x-amz-date', value: '...'},
+ # {key: 'Authorization', value: '...'},
+ # ...
+ # ]
+ # And then serialized as:
+ # quote(json.dumps({
+ # url: '...',
+ # method: 'POST',
+ # headers: [{key: 'x-amz-date', value: '...'}, ...]
+ # }))
+ */
+
+ awsSignedReq := awsRequest{
+ URL: req.URL.String(),
+ Method: "POST",
+ }
+ for headerKey, headerList := range req.Header {
+ for _, headerValue := range headerList {
+ awsSignedReq.Headers = append(awsSignedReq.Headers, awsRequestHeader{
+ Key: headerKey,
+ Value: headerValue,
+ })
+ }
+ }
+ sort.Slice(awsSignedReq.Headers, func(i, j int) bool {
+ headerCompare := strings.Compare(awsSignedReq.Headers[i].Key, awsSignedReq.Headers[j].Key)
+ if headerCompare == 0 {
+ return strings.Compare(awsSignedReq.Headers[i].Value, awsSignedReq.Headers[j].Value) < 0
+ }
+ return headerCompare < 0
+ })
+
+ result, err := json.Marshal(awsSignedReq)
+ if err != nil {
+ return "", err
+ }
+ return url.QueryEscape(string(result)), nil
+}
+
+func (cs *awsCredentialSource) getAWSSessionToken() (string, error) {
+ if cs.IMDSv2SessionTokenURL == "" {
+ return "", nil
+ }
+
+ req, err := http.NewRequest("PUT", cs.IMDSv2SessionTokenURL, nil)
+ if err != nil {
+ return "", err
+ }
+
+ req.Header.Add(awsIMDSv2SessionTtlHeader, awsIMDSv2SessionTtl)
+
+ resp, err := cs.doRequest(req)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return "", err
+ }
+
+ if resp.StatusCode != 200 {
+ return "", fmt.Errorf("oauth2/google: unable to retrieve AWS session token - %s", string(respBody))
+ }
+
+ return string(respBody), nil
+}
+
+func (cs *awsCredentialSource) getRegion(headers map[string]string) (string, error) {
+ if canRetrieveRegionFromEnvironment() {
+ if envAwsRegion := getenv(awsRegion); envAwsRegion != "" {
+ return envAwsRegion, nil
+ }
+ return getenv("AWS_DEFAULT_REGION"), nil
+ }
+
+ if cs.RegionURL == "" {
+ return "", errors.New("oauth2/google: unable to determine AWS region")
+ }
+
+ req, err := http.NewRequest("GET", cs.RegionURL, nil)
+ if err != nil {
+ return "", err
+ }
+
+ for name, value := range headers {
+ req.Header.Add(name, value)
+ }
+
+ resp, err := cs.doRequest(req)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return "", err
+ }
+
+ if resp.StatusCode != 200 {
+ return "", fmt.Errorf("oauth2/google: unable to retrieve AWS region - %s", string(respBody))
+ }
+
+ // This endpoint will return the region in format: us-east-2b.
+ // Only the us-east-2 part should be used.
+ respBodyEnd := 0
+ if len(respBody) > 1 {
+ respBodyEnd = len(respBody) - 1
+ }
+ return string(respBody[:respBodyEnd]), nil
+}
+
+func (cs *awsCredentialSource) getSecurityCredentials(headers map[string]string) (result awsSecurityCredentials, err error) {
+ if canRetrieveSecurityCredentialFromEnvironment() {
+ return awsSecurityCredentials{
+ AccessKeyID: getenv(awsAccessKeyId),
+ SecretAccessKey: getenv(awsSecretAccessKey),
+ SecurityToken: getenv(awsSessionToken),
+ }, nil
+ }
+
+ roleName, err := cs.getMetadataRoleName(headers)
+ if err != nil {
+ return
+ }
+
+ credentials, err := cs.getMetadataSecurityCredentials(roleName, headers)
+ if err != nil {
+ return
+ }
+
+ if credentials.AccessKeyID == "" {
+ return result, errors.New("oauth2/google: missing AccessKeyId credential")
+ }
+
+ if credentials.SecretAccessKey == "" {
+ return result, errors.New("oauth2/google: missing SecretAccessKey credential")
+ }
+
+ return credentials, nil
+}
+
+func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string, headers map[string]string) (awsSecurityCredentials, error) {
+ var result awsSecurityCredentials
+
+ req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", cs.CredVerificationURL, roleName), nil)
+ if err != nil {
+ return result, err
+ }
+ req.Header.Add("Content-Type", "application/json")
+
+ for name, value := range headers {
+ req.Header.Add(name, value)
+ }
+
+ resp, err := cs.doRequest(req)
+ if err != nil {
+ return result, err
+ }
+ defer resp.Body.Close()
+
+ respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return result, err
+ }
+
+ if resp.StatusCode != 200 {
+ return result, fmt.Errorf("oauth2/google: unable to retrieve AWS security credentials - %s", string(respBody))
+ }
+
+ err = json.Unmarshal(respBody, &result)
+ return result, err
+}
+
+func (cs *awsCredentialSource) getMetadataRoleName(headers map[string]string) (string, error) {
+ if cs.CredVerificationURL == "" {
+ return "", errors.New("oauth2/google: unable to determine the AWS metadata server security credentials endpoint")
+ }
+
+ req, err := http.NewRequest("GET", cs.CredVerificationURL, nil)
+ if err != nil {
+ return "", err
+ }
+
+ for name, value := range headers {
+ req.Header.Add(name, value)
+ }
+
+ resp, err := cs.doRequest(req)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return "", err
+ }
+
+ if resp.StatusCode != 200 {
+ return "", fmt.Errorf("oauth2/google: unable to retrieve AWS role name - %s", string(respBody))
+ }
+
+ return string(respBody), nil
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go
new file mode 100644
index 0000000000..33288d3677
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go
@@ -0,0 +1,254 @@
+// Copyright 2020 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 externalaccount
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "regexp"
+ "strconv"
+ "time"
+
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google/internal/stsexchange"
+)
+
+// now aliases time.Now for testing
+var now = func() time.Time {
+ return time.Now().UTC()
+}
+
+// Config stores the configuration for fetching tokens with external credentials.
+type Config struct {
+ // Audience is the Secure Token Service (STS) audience which contains the resource name for the workload
+ // identity pool or the workforce pool and the provider identifier in that pool.
+ Audience string
+ // SubjectTokenType is the STS token type based on the Oauth2.0 token exchange spec
+ // e.g. `urn:ietf:params:oauth:token-type:jwt`.
+ SubjectTokenType string
+ // TokenURL is the STS token exchange endpoint.
+ TokenURL string
+ // TokenInfoURL is the token_info endpoint used to retrieve the account related information (
+ // user attributes like account identifier, eg. email, username, uid, etc). This is
+ // needed for gCloud session account identification.
+ TokenInfoURL string
+ // ServiceAccountImpersonationURL is the URL for the service account impersonation request. This is only
+ // required for workload identity pools when APIs to be accessed have not integrated with UberMint.
+ ServiceAccountImpersonationURL string
+ // ServiceAccountImpersonationLifetimeSeconds is the number of seconds the service account impersonation
+ // token will be valid for.
+ ServiceAccountImpersonationLifetimeSeconds int
+ // ClientSecret is currently only required if token_info endpoint also
+ // needs to be called with the generated GCP access token. When provided, STS will be
+ // called with additional basic authentication using client_id as username and client_secret as password.
+ ClientSecret string
+ // ClientID is only required in conjunction with ClientSecret, as described above.
+ ClientID string
+ // CredentialSource contains the necessary information to retrieve the token itself, as well
+ // as some environmental information.
+ CredentialSource CredentialSource
+ // QuotaProjectID is injected by gCloud. If the value is non-empty, the Auth libraries
+ // will set the x-goog-user-project which overrides the project associated with the credentials.
+ QuotaProjectID string
+ // Scopes contains the desired scopes for the returned access token.
+ Scopes []string
+ // The optional workforce pool user project number when the credential
+ // corresponds to a workforce pool and not a workload identity pool.
+ // The underlying principal must still have serviceusage.services.use IAM
+ // permission to use the project for billing/quota.
+ WorkforcePoolUserProject string
+}
+
+var (
+ validWorkforceAudiencePattern *regexp.Regexp = regexp.MustCompile(`//iam\.googleapis\.com/locations/[^/]+/workforcePools/`)
+)
+
+func validateWorkforceAudience(input string) bool {
+ return validWorkforceAudiencePattern.MatchString(input)
+}
+
+// TokenSource Returns an external account TokenSource struct. This is to be called by package google to construct a google.Credentials.
+func (c *Config) TokenSource(ctx context.Context) (oauth2.TokenSource, error) {
+ return c.tokenSource(ctx, "https")
+}
+
+// tokenSource is a private function that's directly called by some of the tests,
+// because the unit test URLs are mocked, and would otherwise fail the
+// validity check.
+func (c *Config) tokenSource(ctx context.Context, scheme string) (oauth2.TokenSource, error) {
+ if c.WorkforcePoolUserProject != "" {
+ valid := validateWorkforceAudience(c.Audience)
+ if !valid {
+ return nil, fmt.Errorf("oauth2/google: workforce_pool_user_project should not be set for non-workforce pool credentials")
+ }
+ }
+
+ ts := tokenSource{
+ ctx: ctx,
+ conf: c,
+ }
+ if c.ServiceAccountImpersonationURL == "" {
+ return oauth2.ReuseTokenSource(nil, ts), nil
+ }
+ scopes := c.Scopes
+ ts.conf.Scopes = []string{"https://www.googleapis.com/auth/cloud-platform"}
+ imp := ImpersonateTokenSource{
+ Ctx: ctx,
+ URL: c.ServiceAccountImpersonationURL,
+ Scopes: scopes,
+ Ts: oauth2.ReuseTokenSource(nil, ts),
+ TokenLifetimeSeconds: c.ServiceAccountImpersonationLifetimeSeconds,
+ }
+ return oauth2.ReuseTokenSource(nil, imp), nil
+}
+
+// Subject token file types.
+const (
+ fileTypeText = "text"
+ fileTypeJSON = "json"
+)
+
+type format struct {
+ // Type is either "text" or "json". When not provided "text" type is assumed.
+ Type string `json:"type"`
+ // SubjectTokenFieldName is only required for JSON format. This would be "access_token" for azure.
+ SubjectTokenFieldName string `json:"subject_token_field_name"`
+}
+
+// CredentialSource stores the information necessary to retrieve the credentials for the STS exchange.
+// One field amongst File, URL, and Executable should be filled, depending on the kind of credential in question.
+// The EnvironmentID should start with AWS if being used for an AWS credential.
+type CredentialSource struct {
+ File string `json:"file"`
+
+ URL string `json:"url"`
+ Headers map[string]string `json:"headers"`
+
+ Executable *ExecutableConfig `json:"executable"`
+
+ EnvironmentID string `json:"environment_id"`
+ RegionURL string `json:"region_url"`
+ RegionalCredVerificationURL string `json:"regional_cred_verification_url"`
+ CredVerificationURL string `json:"cred_verification_url"`
+ IMDSv2SessionTokenURL string `json:"imdsv2_session_token_url"`
+ Format format `json:"format"`
+}
+
+type ExecutableConfig struct {
+ Command string `json:"command"`
+ TimeoutMillis *int `json:"timeout_millis"`
+ OutputFile string `json:"output_file"`
+}
+
+// parse determines the type of CredentialSource needed.
+func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) {
+ if len(c.CredentialSource.EnvironmentID) > 3 && c.CredentialSource.EnvironmentID[:3] == "aws" {
+ if awsVersion, err := strconv.Atoi(c.CredentialSource.EnvironmentID[3:]); err == nil {
+ if awsVersion != 1 {
+ return nil, fmt.Errorf("oauth2/google: aws version '%d' is not supported in the current build", awsVersion)
+ }
+
+ awsCredSource := awsCredentialSource{
+ EnvironmentID: c.CredentialSource.EnvironmentID,
+ RegionURL: c.CredentialSource.RegionURL,
+ RegionalCredVerificationURL: c.CredentialSource.RegionalCredVerificationURL,
+ CredVerificationURL: c.CredentialSource.URL,
+ TargetResource: c.Audience,
+ ctx: ctx,
+ }
+ if c.CredentialSource.IMDSv2SessionTokenURL != "" {
+ awsCredSource.IMDSv2SessionTokenURL = c.CredentialSource.IMDSv2SessionTokenURL
+ }
+
+ return awsCredSource, nil
+ }
+ } else if c.CredentialSource.File != "" {
+ return fileCredentialSource{File: c.CredentialSource.File, Format: c.CredentialSource.Format}, nil
+ } else if c.CredentialSource.URL != "" {
+ return urlCredentialSource{URL: c.CredentialSource.URL, Headers: c.CredentialSource.Headers, Format: c.CredentialSource.Format, ctx: ctx}, nil
+ } else if c.CredentialSource.Executable != nil {
+ return CreateExecutableCredential(ctx, c.CredentialSource.Executable, c)
+ }
+ return nil, fmt.Errorf("oauth2/google: unable to parse credential source")
+}
+
+type baseCredentialSource interface {
+ credentialSourceType() string
+ subjectToken() (string, error)
+}
+
+// tokenSource is the source that handles external credentials. It is used to retrieve Tokens.
+type tokenSource struct {
+ ctx context.Context
+ conf *Config
+}
+
+func getMetricsHeaderValue(conf *Config, credSource baseCredentialSource) string {
+ return fmt.Sprintf("gl-go/%s auth/%s google-byoid-sdk source/%s sa-impersonation/%t config-lifetime/%t",
+ goVersion(),
+ "unknown",
+ credSource.credentialSourceType(),
+ conf.ServiceAccountImpersonationURL != "",
+ conf.ServiceAccountImpersonationLifetimeSeconds != 0)
+}
+
+// Token allows tokenSource to conform to the oauth2.TokenSource interface.
+func (ts tokenSource) Token() (*oauth2.Token, error) {
+ conf := ts.conf
+
+ credSource, err := conf.parse(ts.ctx)
+ if err != nil {
+ return nil, err
+ }
+ subjectToken, err := credSource.subjectToken()
+
+ if err != nil {
+ return nil, err
+ }
+ stsRequest := stsexchange.TokenExchangeRequest{
+ GrantType: "urn:ietf:params:oauth:grant-type:token-exchange",
+ Audience: conf.Audience,
+ Scope: conf.Scopes,
+ RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token",
+ SubjectToken: subjectToken,
+ SubjectTokenType: conf.SubjectTokenType,
+ }
+ header := make(http.Header)
+ header.Add("Content-Type", "application/x-www-form-urlencoded")
+ header.Add("x-goog-api-client", getMetricsHeaderValue(conf, credSource))
+ clientAuth := stsexchange.ClientAuthentication{
+ AuthStyle: oauth2.AuthStyleInHeader,
+ ClientID: conf.ClientID,
+ ClientSecret: conf.ClientSecret,
+ }
+ var options map[string]interface{}
+ // Do not pass workforce_pool_user_project when client authentication is used.
+ // The client ID is sufficient for determining the user project.
+ if conf.WorkforcePoolUserProject != "" && conf.ClientID == "" {
+ options = map[string]interface{}{
+ "userProject": conf.WorkforcePoolUserProject,
+ }
+ }
+ stsResp, err := stsexchange.ExchangeToken(ts.ctx, conf.TokenURL, &stsRequest, clientAuth, header, options)
+ if err != nil {
+ return nil, err
+ }
+
+ accessToken := &oauth2.Token{
+ AccessToken: stsResp.AccessToken,
+ TokenType: stsResp.TokenType,
+ }
+ if stsResp.ExpiresIn < 0 {
+ return nil, fmt.Errorf("oauth2/google: got invalid expiry from security token service")
+ } else if stsResp.ExpiresIn >= 0 {
+ accessToken.Expiry = now().Add(time.Duration(stsResp.ExpiresIn) * time.Second)
+ }
+
+ if stsResp.RefreshToken != "" {
+ accessToken.RefreshToken = stsResp.RefreshToken
+ }
+ return accessToken, nil
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go
new file mode 100644
index 0000000000..233a78cef2
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go
@@ -0,0 +1,18 @@
+// Copyright 2020 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 externalaccount
+
+import "fmt"
+
+// Error for handling OAuth related error responses as stated in rfc6749#5.2.
+type Error struct {
+ Code string
+ URI string
+ Description string
+}
+
+func (err *Error) Error() string {
+ return fmt.Sprintf("got error code %s from %s: %s", err.Code, err.URI, err.Description)
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go
new file mode 100644
index 0000000000..6497dc022e
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go
@@ -0,0 +1,313 @@
+// Copyright 2022 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 externalaccount
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "regexp"
+ "strings"
+ "time"
+)
+
+var serviceAccountImpersonationRE = regexp.MustCompile("https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/(.*@.*):generateAccessToken")
+
+const (
+ executableSupportedMaxVersion = 1
+ defaultTimeout = 30 * time.Second
+ timeoutMinimum = 5 * time.Second
+ timeoutMaximum = 120 * time.Second
+ executableSource = "response"
+ outputFileSource = "output file"
+)
+
+type nonCacheableError struct {
+ message string
+}
+
+func (nce nonCacheableError) Error() string {
+ return nce.message
+}
+
+func missingFieldError(source, field string) error {
+ return fmt.Errorf("oauth2/google: %v missing `%q` field", source, field)
+}
+
+func jsonParsingError(source, data string) error {
+ return fmt.Errorf("oauth2/google: unable to parse %v\nResponse: %v", source, data)
+}
+
+func malformedFailureError() error {
+ return nonCacheableError{"oauth2/google: response must include `error` and `message` fields when unsuccessful"}
+}
+
+func userDefinedError(code, message string) error {
+ return nonCacheableError{fmt.Sprintf("oauth2/google: response contains unsuccessful response: (%v) %v", code, message)}
+}
+
+func unsupportedVersionError(source string, version int) error {
+ return fmt.Errorf("oauth2/google: %v contains unsupported version: %v", source, version)
+}
+
+func tokenExpiredError() error {
+ return nonCacheableError{"oauth2/google: the token returned by the executable is expired"}
+}
+
+func tokenTypeError(source string) error {
+ return fmt.Errorf("oauth2/google: %v contains unsupported token type", source)
+}
+
+func exitCodeError(exitCode int) error {
+ return fmt.Errorf("oauth2/google: executable command failed with exit code %v", exitCode)
+}
+
+func executableError(err error) error {
+ return fmt.Errorf("oauth2/google: executable command failed: %v", err)
+}
+
+func executablesDisallowedError() error {
+ return errors.New("oauth2/google: executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run")
+}
+
+func timeoutRangeError() error {
+ return errors.New("oauth2/google: invalid `timeout_millis` field — executable timeout must be between 5 and 120 seconds")
+}
+
+func commandMissingError() error {
+ return errors.New("oauth2/google: missing `command` field — executable command must be provided")
+}
+
+type environment interface {
+ existingEnv() []string
+ getenv(string) string
+ run(ctx context.Context, command string, env []string) ([]byte, error)
+ now() time.Time
+}
+
+type runtimeEnvironment struct{}
+
+func (r runtimeEnvironment) existingEnv() []string {
+ return os.Environ()
+}
+
+func (r runtimeEnvironment) getenv(key string) string {
+ return os.Getenv(key)
+}
+
+func (r runtimeEnvironment) now() time.Time {
+ return time.Now().UTC()
+}
+
+func (r runtimeEnvironment) run(ctx context.Context, command string, env []string) ([]byte, error) {
+ splitCommand := strings.Fields(command)
+ cmd := exec.CommandContext(ctx, splitCommand[0], splitCommand[1:]...)
+ cmd.Env = env
+
+ var stdout, stderr bytes.Buffer
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+
+ if err := cmd.Run(); err != nil {
+ if ctx.Err() == context.DeadlineExceeded {
+ return nil, context.DeadlineExceeded
+ }
+
+ if exitError, ok := err.(*exec.ExitError); ok {
+ return nil, exitCodeError(exitError.ExitCode())
+ }
+
+ return nil, executableError(err)
+ }
+
+ bytesStdout := bytes.TrimSpace(stdout.Bytes())
+ if len(bytesStdout) > 0 {
+ return bytesStdout, nil
+ }
+ return bytes.TrimSpace(stderr.Bytes()), nil
+}
+
+type executableCredentialSource struct {
+ Command string
+ Timeout time.Duration
+ OutputFile string
+ ctx context.Context
+ config *Config
+ env environment
+}
+
+// CreateExecutableCredential creates an executableCredentialSource given an ExecutableConfig.
+// It also performs defaulting and type conversions.
+func CreateExecutableCredential(ctx context.Context, ec *ExecutableConfig, config *Config) (executableCredentialSource, error) {
+ if ec.Command == "" {
+ return executableCredentialSource{}, commandMissingError()
+ }
+
+ result := executableCredentialSource{}
+ result.Command = ec.Command
+ if ec.TimeoutMillis == nil {
+ result.Timeout = defaultTimeout
+ } else {
+ result.Timeout = time.Duration(*ec.TimeoutMillis) * time.Millisecond
+ if result.Timeout < timeoutMinimum || result.Timeout > timeoutMaximum {
+ return executableCredentialSource{}, timeoutRangeError()
+ }
+ }
+ result.OutputFile = ec.OutputFile
+ result.ctx = ctx
+ result.config = config
+ result.env = runtimeEnvironment{}
+ return result, nil
+}
+
+type executableResponse struct {
+ Version int `json:"version,omitempty"`
+ Success *bool `json:"success,omitempty"`
+ TokenType string `json:"token_type,omitempty"`
+ ExpirationTime int64 `json:"expiration_time,omitempty"`
+ IdToken string `json:"id_token,omitempty"`
+ SamlResponse string `json:"saml_response,omitempty"`
+ Code string `json:"code,omitempty"`
+ Message string `json:"message,omitempty"`
+}
+
+func (cs executableCredentialSource) parseSubjectTokenFromSource(response []byte, source string, now int64) (string, error) {
+ var result executableResponse
+ if err := json.Unmarshal(response, &result); err != nil {
+ return "", jsonParsingError(source, string(response))
+ }
+
+ if result.Version == 0 {
+ return "", missingFieldError(source, "version")
+ }
+
+ if result.Success == nil {
+ return "", missingFieldError(source, "success")
+ }
+
+ if !*result.Success {
+ if result.Code == "" || result.Message == "" {
+ return "", malformedFailureError()
+ }
+ return "", userDefinedError(result.Code, result.Message)
+ }
+
+ if result.Version > executableSupportedMaxVersion || result.Version < 0 {
+ return "", unsupportedVersionError(source, result.Version)
+ }
+
+ if result.ExpirationTime == 0 && cs.OutputFile != "" {
+ return "", missingFieldError(source, "expiration_time")
+ }
+
+ if result.TokenType == "" {
+ return "", missingFieldError(source, "token_type")
+ }
+
+ if result.ExpirationTime != 0 && result.ExpirationTime < now {
+ return "", tokenExpiredError()
+ }
+
+ if result.TokenType == "urn:ietf:params:oauth:token-type:jwt" || result.TokenType == "urn:ietf:params:oauth:token-type:id_token" {
+ if result.IdToken == "" {
+ return "", missingFieldError(source, "id_token")
+ }
+ return result.IdToken, nil
+ }
+
+ if result.TokenType == "urn:ietf:params:oauth:token-type:saml2" {
+ if result.SamlResponse == "" {
+ return "", missingFieldError(source, "saml_response")
+ }
+ return result.SamlResponse, nil
+ }
+
+ return "", tokenTypeError(source)
+}
+
+func (cs executableCredentialSource) credentialSourceType() string {
+ return "executable"
+}
+
+func (cs executableCredentialSource) subjectToken() (string, error) {
+ if token, err := cs.getTokenFromOutputFile(); token != "" || err != nil {
+ return token, err
+ }
+
+ return cs.getTokenFromExecutableCommand()
+}
+
+func (cs executableCredentialSource) getTokenFromOutputFile() (token string, err error) {
+ if cs.OutputFile == "" {
+ // This ExecutableCredentialSource doesn't use an OutputFile.
+ return "", nil
+ }
+
+ file, err := os.Open(cs.OutputFile)
+ if err != nil {
+ // No OutputFile found. Hasn't been created yet, so skip it.
+ return "", nil
+ }
+ defer file.Close()
+
+ data, err := ioutil.ReadAll(io.LimitReader(file, 1<<20))
+ if err != nil || len(data) == 0 {
+ // Cachefile exists, but no data found. Get new credential.
+ return "", nil
+ }
+
+ token, err = cs.parseSubjectTokenFromSource(data, outputFileSource, cs.env.now().Unix())
+ if err != nil {
+ if _, ok := err.(nonCacheableError); ok {
+ // If the cached token is expired we need a new token,
+ // and if the cache contains a failure, we need to try again.
+ return "", nil
+ }
+
+ // There was an error in the cached token, and the developer should be aware of it.
+ return "", err
+ }
+ // Token parsing succeeded. Use found token.
+ return token, nil
+}
+
+func (cs executableCredentialSource) executableEnvironment() []string {
+ result := cs.env.existingEnv()
+ result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE=%v", cs.config.Audience))
+ result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE=%v", cs.config.SubjectTokenType))
+ result = append(result, "GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE=0")
+ if cs.config.ServiceAccountImpersonationURL != "" {
+ matches := serviceAccountImpersonationRE.FindStringSubmatch(cs.config.ServiceAccountImpersonationURL)
+ if matches != nil {
+ result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL=%v", matches[1]))
+ }
+ }
+ if cs.OutputFile != "" {
+ result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE=%v", cs.OutputFile))
+ }
+ return result
+}
+
+func (cs executableCredentialSource) getTokenFromExecutableCommand() (string, error) {
+ // For security reasons, we need our consumers to set this environment variable to allow executables to be run.
+ if cs.env.getenv("GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES") != "1" {
+ return "", executablesDisallowedError()
+ }
+
+ ctx, cancel := context.WithDeadline(cs.ctx, cs.env.now().Add(cs.Timeout))
+ defer cancel()
+
+ output, err := cs.env.run(ctx, cs.Command, cs.executableEnvironment())
+ if err != nil {
+ return "", err
+ }
+ return cs.parseSubjectTokenFromSource(output, executableSource, cs.env.now().Unix())
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go
new file mode 100644
index 0000000000..f35f73c5cb
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go
@@ -0,0 +1,61 @@
+// Copyright 2020 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 externalaccount
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+type fileCredentialSource struct {
+ File string
+ Format format
+}
+
+func (cs fileCredentialSource) credentialSourceType() string {
+ return "file"
+}
+
+func (cs fileCredentialSource) subjectToken() (string, error) {
+ tokenFile, err := os.Open(cs.File)
+ if err != nil {
+ return "", fmt.Errorf("oauth2/google: failed to open credential file %q", cs.File)
+ }
+ defer tokenFile.Close()
+ tokenBytes, err := ioutil.ReadAll(io.LimitReader(tokenFile, 1<<20))
+ if err != nil {
+ return "", fmt.Errorf("oauth2/google: failed to read credential file: %v", err)
+ }
+ tokenBytes = bytes.TrimSpace(tokenBytes)
+ switch cs.Format.Type {
+ case "json":
+ jsonData := make(map[string]interface{})
+ err = json.Unmarshal(tokenBytes, &jsonData)
+ if err != nil {
+ return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token file: %v", err)
+ }
+ val, ok := jsonData[cs.Format.SubjectTokenFieldName]
+ if !ok {
+ return "", errors.New("oauth2/google: provided subject_token_field_name not found in credentials")
+ }
+ token, ok := val.(string)
+ if !ok {
+ return "", errors.New("oauth2/google: improperly formatted subject token")
+ }
+ return token, nil
+ case "text":
+ return string(tokenBytes), nil
+ case "":
+ return string(tokenBytes), nil
+ default:
+ return "", errors.New("oauth2/google: invalid credential_source file format type")
+ }
+
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/header.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/header.go
new file mode 100644
index 0000000000..1d5aad2e2d
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/header.go
@@ -0,0 +1,64 @@
+// Copyright 2023 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 externalaccount
+
+import (
+ "runtime"
+ "strings"
+ "unicode"
+)
+
+var (
+ // version is a package internal global variable for testing purposes.
+ version = runtime.Version
+)
+
+// versionUnknown is only used when the runtime version cannot be determined.
+const versionUnknown = "UNKNOWN"
+
+// goVersion returns a Go runtime version derived from the runtime environment
+// that is modified to be suitable for reporting in a header, meaning it has no
+// whitespace. If it is unable to determine the Go runtime version, it returns
+// versionUnknown.
+func goVersion() string {
+ const develPrefix = "devel +"
+
+ s := version()
+ if strings.HasPrefix(s, develPrefix) {
+ s = s[len(develPrefix):]
+ if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
+ s = s[:p]
+ }
+ return s
+ } else if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
+ s = s[:p]
+ }
+
+ notSemverRune := func(r rune) bool {
+ return !strings.ContainsRune("0123456789.", r)
+ }
+
+ if strings.HasPrefix(s, "go1") {
+ s = s[2:]
+ var prerelease string
+ if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
+ s, prerelease = s[:p], s[p:]
+ }
+ if strings.HasSuffix(s, ".") {
+ s += "0"
+ } else if strings.Count(s, ".") < 2 {
+ s += ".0"
+ }
+ if prerelease != "" {
+ // Some release candidates already have a dash in them.
+ if !strings.HasPrefix(prerelease, "-") {
+ prerelease = "-" + prerelease
+ }
+ s += prerelease
+ }
+ return s
+ }
+ return "UNKNOWN"
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go
new file mode 100644
index 0000000000..54c8f209f3
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go
@@ -0,0 +1,105 @@
+// Copyright 2021 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 externalaccount
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "time"
+
+ "golang.org/x/oauth2"
+)
+
+// generateAccesstokenReq is used for service account impersonation
+type generateAccessTokenReq struct {
+ Delegates []string `json:"delegates,omitempty"`
+ Lifetime string `json:"lifetime,omitempty"`
+ Scope []string `json:"scope,omitempty"`
+}
+
+type impersonateTokenResponse struct {
+ AccessToken string `json:"accessToken"`
+ ExpireTime string `json:"expireTime"`
+}
+
+// ImpersonateTokenSource uses a source credential, stored in Ts, to request an access token to the provided URL.
+// Scopes can be defined when the access token is requested.
+type ImpersonateTokenSource struct {
+ // Ctx is the execution context of the impersonation process
+ // used to perform http call to the URL. Required
+ Ctx context.Context
+ // Ts is the source credential used to generate a token on the
+ // impersonated service account. Required.
+ Ts oauth2.TokenSource
+
+ // URL is the endpoint to call to generate a token
+ // on behalf the service account. Required.
+ URL string
+ // Scopes that the impersonated credential should have. Required.
+ Scopes []string
+ // Delegates are the service account email addresses in a delegation chain.
+ // Each service account must be granted roles/iam.serviceAccountTokenCreator
+ // on the next service account in the chain. Optional.
+ Delegates []string
+ // TokenLifetimeSeconds is the number of seconds the impersonation token will
+ // be valid for.
+ TokenLifetimeSeconds int
+}
+
+// Token performs the exchange to get a temporary service account token to allow access to GCP.
+func (its ImpersonateTokenSource) Token() (*oauth2.Token, error) {
+ lifetimeString := "3600s"
+ if its.TokenLifetimeSeconds != 0 {
+ lifetimeString = fmt.Sprintf("%ds", its.TokenLifetimeSeconds)
+ }
+ reqBody := generateAccessTokenReq{
+ Lifetime: lifetimeString,
+ Scope: its.Scopes,
+ Delegates: its.Delegates,
+ }
+ b, err := json.Marshal(reqBody)
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: unable to marshal request: %v", err)
+ }
+ client := oauth2.NewClient(its.Ctx, its.Ts)
+ req, err := http.NewRequest("POST", its.URL, bytes.NewReader(b))
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: unable to create impersonation request: %v", err)
+ }
+ req = req.WithContext(its.Ctx)
+ req.Header.Set("Content-Type", "application/json")
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: unable to generate access 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/google: unable to read body: %v", err)
+ }
+ if c := resp.StatusCode; c < 200 || c > 299 {
+ return nil, fmt.Errorf("oauth2/google: status code %d: %s", c, body)
+ }
+
+ var accessTokenResp impersonateTokenResponse
+ if err := json.Unmarshal(body, &accessTokenResp); err != nil {
+ return nil, fmt.Errorf("oauth2/google: unable to parse response: %v", err)
+ }
+ expiry, err := time.Parse(time.RFC3339, accessTokenResp.ExpireTime)
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: unable to parse expiry: %v", err)
+ }
+ return &oauth2.Token{
+ AccessToken: accessTokenResp.AccessToken,
+ Expiry: expiry,
+ TokenType: "Bearer",
+ }, nil
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go
new file mode 100644
index 0000000000..606bb4e800
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go
@@ -0,0 +1,79 @@
+// Copyright 2020 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 externalaccount
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+
+ "golang.org/x/oauth2"
+)
+
+type urlCredentialSource struct {
+ URL string
+ Headers map[string]string
+ Format format
+ ctx context.Context
+}
+
+func (cs urlCredentialSource) credentialSourceType() string {
+ return "url"
+}
+
+func (cs urlCredentialSource) subjectToken() (string, error) {
+ client := oauth2.NewClient(cs.ctx, nil)
+ req, err := http.NewRequest("GET", cs.URL, nil)
+ if err != nil {
+ return "", fmt.Errorf("oauth2/google: HTTP request for URL-sourced credential failed: %v", err)
+ }
+ req = req.WithContext(cs.ctx)
+
+ for key, val := range cs.Headers {
+ req.Header.Add(key, val)
+ }
+ resp, err := client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("oauth2/google: invalid response when retrieving subject token: %v", err)
+ }
+ defer resp.Body.Close()
+
+ respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return "", fmt.Errorf("oauth2/google: invalid body in subject token URL query: %v", err)
+ }
+ if c := resp.StatusCode; c < 200 || c > 299 {
+ return "", fmt.Errorf("oauth2/google: status code %d: %s", c, respBody)
+ }
+
+ switch cs.Format.Type {
+ case "json":
+ jsonData := make(map[string]interface{})
+ err = json.Unmarshal(respBody, &jsonData)
+ if err != nil {
+ return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token file: %v", err)
+ }
+ val, ok := jsonData[cs.Format.SubjectTokenFieldName]
+ if !ok {
+ return "", errors.New("oauth2/google: provided subject_token_field_name not found in credentials")
+ }
+ token, ok := val.(string)
+ if !ok {
+ return "", errors.New("oauth2/google: improperly formatted subject token")
+ }
+ return token, nil
+ case "text":
+ return string(respBody), nil
+ case "":
+ return string(respBody), nil
+ default:
+ return "", errors.New("oauth2/google: invalid credential_source file format type")
+ }
+
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/ya.make b/vendor/golang.org/x/oauth2/google/internal/externalaccount/ya.make
new file mode 100644
index 0000000000..91bc37a76a
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/ya.make
@@ -0,0 +1,38 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+GO_SKIP_TESTS(
+ TestRetrieveOutputFileSubjectTokenNotJSON
+ TestRetrieveOutputFileSubjectTokenFailureTests
+ TestRetrieveOutputFileSubjectTokenInvalidCache
+ TestRetrieveOutputFileSubjectTokenJwt
+)
+
+SRCS(
+ aws.go
+ basecredentials.go
+ err.go
+ executablecredsource.go
+ filecredsource.go
+ header.go
+ impersonate.go
+ urlcredsource.go
+)
+
+GO_TEST_SRCS(
+ aws_test.go
+ basecredentials_test.go
+ err_test.go
+ executablecredsource_test.go
+ filecredsource_test.go
+ header_test.go
+ impersonate_test.go
+ urlcredsource_test.go
+)
+
+END()
+
+RECURSE(
+ gotest
+)
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/externalaccountauthorizeduser.go b/vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/externalaccountauthorizeduser.go
new file mode 100644
index 0000000000..cb58207074
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/externalaccountauthorizeduser.go
@@ -0,0 +1,114 @@
+// Copyright 2023 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 externalaccountauthorizeduser
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google/internal/stsexchange"
+)
+
+// now aliases time.Now for testing.
+var now = func() time.Time {
+ return time.Now().UTC()
+}
+
+var tokenValid = func(token oauth2.Token) bool {
+ return token.Valid()
+}
+
+type Config struct {
+ // Audience is the Secure Token Service (STS) audience which contains the resource name for the workforce pool and
+ // the provider identifier in that pool.
+ Audience string
+ // RefreshToken is the optional OAuth 2.0 refresh token. If specified, credentials can be refreshed.
+ RefreshToken string
+ // TokenURL is the optional STS token exchange endpoint for refresh. Must be specified for refresh, can be left as
+ // None if the token can not be refreshed.
+ TokenURL string
+ // TokenInfoURL is the optional STS endpoint URL for token introspection.
+ TokenInfoURL string
+ // ClientID is only required in conjunction with ClientSecret, as described above.
+ ClientID string
+ // ClientSecret is currently only required if token_info endpoint also needs to be called with the generated GCP
+ // access token. When provided, STS will be called with additional basic authentication using client_id as username
+ // and client_secret as password.
+ ClientSecret string
+ // Token is the OAuth2.0 access token. Can be nil if refresh information is provided.
+ Token string
+ // Expiry is the optional expiration datetime of the OAuth 2.0 access token.
+ Expiry time.Time
+ // RevokeURL is the optional STS endpoint URL for revoking tokens.
+ RevokeURL string
+ // QuotaProjectID is the optional project ID used for quota and billing. This project may be different from the
+ // project used to create the credentials.
+ QuotaProjectID string
+ Scopes []string
+}
+
+func (c *Config) canRefresh() bool {
+ return c.ClientID != "" && c.ClientSecret != "" && c.RefreshToken != "" && c.TokenURL != ""
+}
+
+func (c *Config) TokenSource(ctx context.Context) (oauth2.TokenSource, error) {
+ var token oauth2.Token
+ if c.Token != "" && !c.Expiry.IsZero() {
+ token = oauth2.Token{
+ AccessToken: c.Token,
+ Expiry: c.Expiry,
+ TokenType: "Bearer",
+ }
+ }
+ if !tokenValid(token) && !c.canRefresh() {
+ return nil, errors.New("oauth2/google: Token should be created with fields to make it valid (`token` and `expiry`), or fields to allow it to refresh (`refresh_token`, `token_url`, `client_id`, `client_secret`).")
+ }
+
+ ts := tokenSource{
+ ctx: ctx,
+ conf: c,
+ }
+
+ return oauth2.ReuseTokenSource(&token, ts), nil
+}
+
+type tokenSource struct {
+ ctx context.Context
+ conf *Config
+}
+
+func (ts tokenSource) Token() (*oauth2.Token, error) {
+ conf := ts.conf
+ if !conf.canRefresh() {
+ return nil, errors.New("oauth2/google: The credentials do not contain the necessary fields need to refresh the access token. You must specify refresh_token, token_url, client_id, and client_secret.")
+ }
+
+ clientAuth := stsexchange.ClientAuthentication{
+ AuthStyle: oauth2.AuthStyleInHeader,
+ ClientID: conf.ClientID,
+ ClientSecret: conf.ClientSecret,
+ }
+
+ stsResponse, err := stsexchange.RefreshAccessToken(ts.ctx, conf.TokenURL, conf.RefreshToken, clientAuth, nil)
+ if err != nil {
+ return nil, err
+ }
+ if stsResponse.ExpiresIn < 0 {
+ return nil, errors.New("oauth2/google: got invalid expiry from security token service")
+ }
+
+ if stsResponse.RefreshToken != "" {
+ conf.RefreshToken = stsResponse.RefreshToken
+ }
+
+ token := &oauth2.Token{
+ AccessToken: stsResponse.AccessToken,
+ Expiry: now().Add(time.Duration(stsResponse.ExpiresIn) * time.Second),
+ TokenType: "Bearer",
+ }
+ return token, nil
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/ya.make b/vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/ya.make
new file mode 100644
index 0000000000..f71d6d0c55
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/externalaccountauthorizeduser/ya.make
@@ -0,0 +1,15 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ externalaccountauthorizeduser.go
+)
+
+GO_TEST_SRCS(externalaccountauthorizeduser_test.go)
+
+END()
+
+RECURSE(
+ gotest
+)
diff --git a/vendor/golang.org/x/oauth2/google/internal/stsexchange/clientauth.go b/vendor/golang.org/x/oauth2/google/internal/stsexchange/clientauth.go
new file mode 100644
index 0000000000..ebd520eace
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/stsexchange/clientauth.go
@@ -0,0 +1,45 @@
+// Copyright 2020 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 stsexchange
+
+import (
+ "encoding/base64"
+ "net/http"
+ "net/url"
+
+ "golang.org/x/oauth2"
+)
+
+// ClientAuthentication represents an OAuth client ID and secret and the mechanism for passing these credentials as stated in rfc6749#2.3.1.
+type ClientAuthentication struct {
+ // AuthStyle can be either basic or request-body
+ AuthStyle oauth2.AuthStyle
+ ClientID string
+ ClientSecret string
+}
+
+// InjectAuthentication is used to add authentication to a Secure Token Service exchange
+// request. It modifies either the passed url.Values or http.Header depending on the desired
+// authentication format.
+func (c *ClientAuthentication) InjectAuthentication(values url.Values, headers http.Header) {
+ if c.ClientID == "" || c.ClientSecret == "" || values == nil || headers == nil {
+ return
+ }
+
+ switch c.AuthStyle {
+ case oauth2.AuthStyleInHeader: // AuthStyleInHeader corresponds to basic authentication as defined in rfc7617#2
+ plainHeader := c.ClientID + ":" + c.ClientSecret
+ headers.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(plainHeader)))
+ case oauth2.AuthStyleInParams: // AuthStyleInParams corresponds to request-body authentication with ClientID and ClientSecret in the message body.
+ values.Set("client_id", c.ClientID)
+ values.Set("client_secret", c.ClientSecret)
+ case oauth2.AuthStyleAutoDetect:
+ values.Set("client_id", c.ClientID)
+ values.Set("client_secret", c.ClientSecret)
+ default:
+ values.Set("client_id", c.ClientID)
+ values.Set("client_secret", c.ClientSecret)
+ }
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/stsexchange/sts_exchange.go b/vendor/golang.org/x/oauth2/google/internal/stsexchange/sts_exchange.go
new file mode 100644
index 0000000000..1a0bebd159
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/stsexchange/sts_exchange.go
@@ -0,0 +1,125 @@
+// Copyright 2020 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 stsexchange
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+
+ "golang.org/x/oauth2"
+)
+
+func defaultHeader() http.Header {
+ header := make(http.Header)
+ header.Add("Content-Type", "application/x-www-form-urlencoded")
+ return header
+}
+
+// ExchangeToken performs an oauth2 token exchange with the provided endpoint.
+// The first 4 fields are all mandatory. headers can be used to pass additional
+// headers beyond the bare minimum required by the token exchange. options can
+// be used to pass additional JSON-structured options to the remote server.
+func ExchangeToken(ctx context.Context, endpoint string, request *TokenExchangeRequest, authentication ClientAuthentication, headers http.Header, options map[string]interface{}) (*Response, error) {
+ data := url.Values{}
+ data.Set("audience", request.Audience)
+ data.Set("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange")
+ data.Set("requested_token_type", "urn:ietf:params:oauth:token-type:access_token")
+ data.Set("subject_token_type", request.SubjectTokenType)
+ data.Set("subject_token", request.SubjectToken)
+ data.Set("scope", strings.Join(request.Scope, " "))
+ if options != nil {
+ opts, err := json.Marshal(options)
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: failed to marshal additional options: %v", err)
+ }
+ data.Set("options", string(opts))
+ }
+
+ return makeRequest(ctx, endpoint, data, authentication, headers)
+}
+
+func RefreshAccessToken(ctx context.Context, endpoint string, refreshToken string, authentication ClientAuthentication, headers http.Header) (*Response, error) {
+ data := url.Values{}
+ data.Set("grant_type", "refresh_token")
+ data.Set("refresh_token", refreshToken)
+
+ return makeRequest(ctx, endpoint, data, authentication, headers)
+}
+
+func makeRequest(ctx context.Context, endpoint string, data url.Values, authentication ClientAuthentication, headers http.Header) (*Response, error) {
+ if headers == nil {
+ headers = defaultHeader()
+ }
+ client := oauth2.NewClient(ctx, nil)
+ authentication.InjectAuthentication(data, headers)
+ encodedData := data.Encode()
+
+ req, err := http.NewRequest("POST", endpoint, strings.NewReader(encodedData))
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: failed to properly build http request: %v", err)
+ }
+ req = req.WithContext(ctx)
+ for key, list := range headers {
+ for _, val := range list {
+ req.Header.Add(key, val)
+ }
+ }
+ req.Header.Add("Content-Length", strconv.Itoa(len(encodedData)))
+
+ resp, err := client.Do(req)
+
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: invalid response from Secure Token Server: %v", err)
+ }
+ defer resp.Body.Close()
+
+ body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return nil, err
+ }
+ if c := resp.StatusCode; c < 200 || c > 299 {
+ return nil, fmt.Errorf("oauth2/google: status code %d: %s", c, body)
+ }
+ var stsResp Response
+ err = json.Unmarshal(body, &stsResp)
+ if err != nil {
+ return nil, fmt.Errorf("oauth2/google: failed to unmarshal response body from Secure Token Server: %v", err)
+
+ }
+
+ return &stsResp, nil
+}
+
+// TokenExchangeRequest contains fields necessary to make an oauth2 token exchange.
+type TokenExchangeRequest struct {
+ ActingParty struct {
+ ActorToken string
+ ActorTokenType string
+ }
+ GrantType string
+ Resource string
+ Audience string
+ Scope []string
+ RequestedTokenType string
+ SubjectToken string
+ SubjectTokenType string
+}
+
+// Response is used to decode the remote server response during an oauth2 token exchange.
+type Response struct {
+ AccessToken string `json:"access_token"`
+ IssuedTokenType string `json:"issued_token_type"`
+ TokenType string `json:"token_type"`
+ ExpiresIn int `json:"expires_in"`
+ Scope string `json:"scope"`
+ RefreshToken string `json:"refresh_token"`
+}
diff --git a/vendor/golang.org/x/oauth2/google/internal/stsexchange/ya.make b/vendor/golang.org/x/oauth2/google/internal/stsexchange/ya.make
new file mode 100644
index 0000000000..ec7a282671
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/internal/stsexchange/ya.make
@@ -0,0 +1,19 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ clientauth.go
+ sts_exchange.go
+)
+
+GO_TEST_SRCS(
+ clientauth_test.go
+ sts_exchange_test.go
+)
+
+END()
+
+RECURSE(
+ gotest
+)
diff --git a/vendor/golang.org/x/oauth2/google/jwt.go b/vendor/golang.org/x/oauth2/google/jwt.go
new file mode 100644
index 0000000000..e89e6ae17b
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/jwt.go
@@ -0,0 +1,102 @@
+// 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 google
+
+import (
+ "crypto/rsa"
+ "fmt"
+ "strings"
+ "time"
+
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/internal"
+ "golang.org/x/oauth2/jws"
+)
+
+// JWTAccessTokenSourceFromJSON uses a Google Developers service account JSON
+// key file to read the credentials that authorize and authenticate the
+// requests, and returns a TokenSource that does not use any OAuth2 flow but
+// instead creates a JWT and sends that as the access token.
+// The audience is typically a URL that specifies the scope of the credentials.
+//
+// Note that this is not a standard OAuth flow, but rather an
+// optimization supported by a few Google services.
+// Unless you know otherwise, you should use JWTConfigFromJSON instead.
+func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
+ return newJWTSource(jsonKey, audience, nil)
+}
+
+// JWTAccessTokenSourceWithScope uses a Google Developers service account JSON
+// key file to read the credentials that authorize and authenticate the
+// requests, and returns a TokenSource that does not use any OAuth2 flow but
+// instead creates a JWT and sends that as the access token.
+// The scope is typically a list of URLs that specifies the scope of the
+// credentials.
+//
+// Note that this is not a standard OAuth flow, but rather an
+// optimization supported by a few Google services.
+// Unless you know otherwise, you should use JWTConfigFromJSON instead.
+func JWTAccessTokenSourceWithScope(jsonKey []byte, scope ...string) (oauth2.TokenSource, error) {
+ return newJWTSource(jsonKey, "", scope)
+}
+
+func newJWTSource(jsonKey []byte, audience string, scopes []string) (oauth2.TokenSource, error) {
+ if len(scopes) == 0 && audience == "" {
+ return nil, fmt.Errorf("google: missing scope/audience for JWT access token")
+ }
+
+ cfg, err := JWTConfigFromJSON(jsonKey)
+ if err != nil {
+ return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
+ }
+ pk, err := internal.ParseKey(cfg.PrivateKey)
+ if err != nil {
+ return nil, fmt.Errorf("google: could not parse key: %v", err)
+ }
+ ts := &jwtAccessTokenSource{
+ email: cfg.Email,
+ audience: audience,
+ scopes: scopes,
+ pk: pk,
+ pkID: cfg.PrivateKeyID,
+ }
+ tok, err := ts.Token()
+ if err != nil {
+ return nil, err
+ }
+ rts := newErrWrappingTokenSource(oauth2.ReuseTokenSource(tok, ts))
+ return rts, nil
+}
+
+type jwtAccessTokenSource struct {
+ email, audience string
+ scopes []string
+ pk *rsa.PrivateKey
+ pkID string
+}
+
+func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
+ iat := time.Now()
+ exp := iat.Add(time.Hour)
+ scope := strings.Join(ts.scopes, " ")
+ cs := &jws.ClaimSet{
+ Iss: ts.email,
+ Sub: ts.email,
+ Aud: ts.audience,
+ Scope: scope,
+ Iat: iat.Unix(),
+ Exp: exp.Unix(),
+ }
+ hdr := &jws.Header{
+ Algorithm: "RS256",
+ Typ: "JWT",
+ KeyID: string(ts.pkID),
+ }
+ msg, err := jws.Encode(hdr, cs, ts.pk)
+ if err != nil {
+ return nil, fmt.Errorf("google: could not encode JWT: %v", err)
+ }
+ return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
+}
diff --git a/vendor/golang.org/x/oauth2/google/sdk.go b/vendor/golang.org/x/oauth2/google/sdk.go
new file mode 100644
index 0000000000..456224bc78
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/sdk.go
@@ -0,0 +1,201 @@
+// 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 google
+
+import (
+ "bufio"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "os/user"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "time"
+
+ "golang.org/x/oauth2"
+)
+
+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 := 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
+}
+
+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) {
+ 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 {
+ // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
+ if v := os.Getenv("HOME"); v != "" {
+ return v
+ }
+ // Else, fall back to user.Current:
+ if u, err := user.Current(); err == nil {
+ return u.HomeDir
+ }
+ return ""
+}
diff --git a/vendor/golang.org/x/oauth2/google/ya.make b/vendor/golang.org/x/oauth2/google/ya.make
new file mode 100644
index 0000000000..68380362bd
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/google/ya.make
@@ -0,0 +1,32 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ appengine.go
+ appengine_gen2_flex.go
+ default.go
+ doc.go
+ error.go
+ google.go
+ jwt.go
+ sdk.go
+)
+
+GO_TEST_SRCS(
+ default_test.go
+ error_test.go
+ google_test.go
+ jwt_test.go
+ sdk_test.go
+)
+
+GO_XTEST_SRCS(example_test.go)
+
+END()
+
+RECURSE(
+ downscope
+ gotest
+ internal
+)
diff --git a/vendor/golang.org/x/oauth2/internal/doc.go b/vendor/golang.org/x/oauth2/internal/doc.go
new file mode 100644
index 0000000000..03265e888a
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/internal/doc.go
@@ -0,0 +1,6 @@
+// Copyright 2017 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
diff --git a/vendor/golang.org/x/oauth2/internal/oauth2.go b/vendor/golang.org/x/oauth2/internal/oauth2.go
new file mode 100644
index 0000000000..14989beaf4
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/internal/oauth2.go
@@ -0,0 +1,37 @@
+// 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 (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+ "fmt"
+)
+
+// ParseKey converts the binary contents of a private key file
+// to an *rsa.PrivateKey. It detects whether the private key is in a
+// PEM container or not. If so, it extracts the private key
+// from PEM container before conversion. It only supports PEM
+// containers with no passphrase.
+func ParseKey(key []byte) (*rsa.PrivateKey, error) {
+ block, _ := pem.Decode(key)
+ if block != nil {
+ key = block.Bytes
+ }
+ parsedKey, err := x509.ParsePKCS8PrivateKey(key)
+ if err != nil {
+ parsedKey, err = x509.ParsePKCS1PrivateKey(key)
+ if err != nil {
+ return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8; parse error: %v", err)
+ }
+ }
+ parsed, ok := parsedKey.(*rsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("private key is invalid")
+ }
+ return parsed, nil
+}
diff --git a/vendor/golang.org/x/oauth2/internal/token.go b/vendor/golang.org/x/oauth2/internal/token.go
new file mode 100644
index 0000000000..e83ddeef0f
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/internal/token.go
@@ -0,0 +1,352 @@
+// 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 (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "mime"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// Token represents the credentials 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 or error in JSON form.
+// https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
+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
+ // error fields
+ // https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
+ ErrorCode string `json:"error"`
+ ErrorDescription string `json:"error_description"`
+ ErrorURI string `json:"error_uri"`
+}
+
+func (e *tokenJSON) expiry() (t time.Time) {
+ if v := e.ExpiresIn; v != 0 {
+ return time.Now().Add(time.Duration(v) * time.Second)
+ }
+ return
+}
+
+type expirationTime int32
+
+func (e *expirationTime) UnmarshalJSON(b []byte) error {
+ if len(b) == 0 || string(b) == "null" {
+ return nil
+ }
+ var n json.Number
+ err := json.Unmarshal(b, &n)
+ if err != nil {
+ return err
+ }
+ i, err := n.Int64()
+ if err != nil {
+ return err
+ }
+ if i > math.MaxInt32 {
+ i = math.MaxInt32
+ }
+ *e = expirationTime(i)
+ return nil
+}
+
+// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
+//
+// Deprecated: this function no longer does anything. Caller code that
+// wants to avoid potential extra HTTP requests made during
+// auto-probing of the provider's auth style should set
+// Endpoint.AuthStyle.
+func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
+
+// AuthStyle is a copy of the golang.org/x/oauth2 package's AuthStyle type.
+type AuthStyle int
+
+const (
+ AuthStyleUnknown AuthStyle = 0
+ AuthStyleInParams AuthStyle = 1
+ AuthStyleInHeader AuthStyle = 2
+)
+
+// LazyAuthStyleCache is a backwards compatibility compromise to let Configs
+// have a lazily-initialized AuthStyleCache.
+//
+// The two users of this, oauth2.Config and oauth2/clientcredentials.Config,
+// both would ideally just embed an unexported AuthStyleCache but because both
+// were historically allowed to be copied by value we can't retroactively add an
+// uncopyable Mutex to them.
+//
+// We could use an atomic.Pointer, but that was added recently enough (in Go
+// 1.18) that we'd break Go 1.17 users where the tests as of 2023-08-03
+// still pass. By using an atomic.Value, it supports both Go 1.17 and
+// copying by value, even if that's not ideal.
+type LazyAuthStyleCache struct {
+ v atomic.Value // of *AuthStyleCache
+}
+
+func (lc *LazyAuthStyleCache) Get() *AuthStyleCache {
+ if c, ok := lc.v.Load().(*AuthStyleCache); ok {
+ return c
+ }
+ c := new(AuthStyleCache)
+ if !lc.v.CompareAndSwap(nil, c) {
+ c = lc.v.Load().(*AuthStyleCache)
+ }
+ return c
+}
+
+// AuthStyleCache is the set of tokenURLs we've successfully used via
+// RetrieveToken and which style auth we ended up using.
+// It's called a cache, but it doesn't (yet?) shrink. It's expected that
+// the set of OAuth2 servers a program contacts over time is fixed and
+// small.
+type AuthStyleCache struct {
+ mu sync.Mutex
+ m map[string]AuthStyle // keyed by tokenURL
+}
+
+// lookupAuthStyle reports which auth style we last used with tokenURL
+// when calling RetrieveToken and whether we have ever done so.
+func (c *AuthStyleCache) lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ style, ok = c.m[tokenURL]
+ return
+}
+
+// setAuthStyle adds an entry to authStyleCache, documented above.
+func (c *AuthStyleCache) setAuthStyle(tokenURL string, v AuthStyle) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if c.m == nil {
+ c.m = make(map[string]AuthStyle)
+ }
+ c.m[tokenURL] = v
+}
+
+// newTokenRequest returns a new *http.Request to retrieve a new token
+// from tokenURL using the provided clientID, clientSecret, and POST
+// body parameters.
+//
+// inParams is whether the clientID & clientSecret should be encoded
+// as the POST body. An 'inParams' value of true means to send it in
+// the POST body (along with any values in v); false means to send it
+// in the Authorization header.
+func newTokenRequest(tokenURL, clientID, clientSecret string, v url.Values, authStyle AuthStyle) (*http.Request, error) {
+ if authStyle == AuthStyleInParams {
+ v = cloneURLValues(v)
+ 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 authStyle == AuthStyleInHeader {
+ req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
+ }
+ return req, nil
+}
+
+func cloneURLValues(v url.Values) url.Values {
+ v2 := make(url.Values, len(v))
+ for k, vv := range v {
+ v2[k] = append([]string(nil), vv...)
+ }
+ return v2
+}
+
+func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle, styleCache *AuthStyleCache) (*Token, error) {
+ needsAuthStyleProbe := authStyle == 0
+ if needsAuthStyleProbe {
+ if style, ok := styleCache.lookupAuthStyle(tokenURL); ok {
+ authStyle = style
+ needsAuthStyleProbe = false
+ } else {
+ authStyle = AuthStyleInHeader // the first way we'll try
+ }
+ }
+ req, err := newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
+ if err != nil {
+ return nil, err
+ }
+ token, err := doTokenRoundTrip(ctx, req)
+ if err != nil && needsAuthStyleProbe {
+ // If we get an error, assume the server wants the
+ // clientID & clientSecret in a different form.
+ // 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
+ //
+ // We used to maintain a big table in this code of all the sites and which way
+ // they went, but maintaining it didn't scale & got annoying.
+ // So just try both ways.
+ authStyle = AuthStyleInParams // the second way we'll try
+ req, _ = newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
+ token, err = doTokenRoundTrip(ctx, req)
+ }
+ if needsAuthStyleProbe && err == nil {
+ styleCache.setAuthStyle(tokenURL, authStyle)
+ }
+ // Don't overwrite `RefreshToken` with an empty value
+ // if this was a token refreshing request.
+ if token != nil && token.RefreshToken == "" {
+ token.RefreshToken = v.Get("refresh_token")
+ }
+ return token, err
+}
+
+func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
+ r, err := ContextClient(ctx).Do(req.WithContext(ctx))
+ if err != nil {
+ return nil, err
+ }
+ body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
+ r.Body.Close()
+ if err != nil {
+ return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
+ }
+
+ failureStatus := r.StatusCode < 200 || r.StatusCode > 299
+ retrieveError := &RetrieveError{
+ Response: r,
+ Body: body,
+ // attempt to populate error detail below
+ }
+
+ var token *Token
+ content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
+ switch content {
+ case "application/x-www-form-urlencoded", "text/plain":
+ // some endpoints return a query string
+ vals, err := url.ParseQuery(string(body))
+ if err != nil {
+ if failureStatus {
+ return nil, retrieveError
+ }
+ return nil, fmt.Errorf("oauth2: cannot parse response: %v", err)
+ }
+ retrieveError.ErrorCode = vals.Get("error")
+ retrieveError.ErrorDescription = vals.Get("error_description")
+ retrieveError.ErrorURI = vals.Get("error_uri")
+ token = &Token{
+ AccessToken: vals.Get("access_token"),
+ TokenType: vals.Get("token_type"),
+ RefreshToken: vals.Get("refresh_token"),
+ Raw: vals,
+ }
+ e := vals.Get("expires_in")
+ 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 {
+ if failureStatus {
+ return nil, retrieveError
+ }
+ return nil, fmt.Errorf("oauth2: cannot parse json: %v", err)
+ }
+ retrieveError.ErrorCode = tj.ErrorCode
+ retrieveError.ErrorDescription = tj.ErrorDescription
+ retrieveError.ErrorURI = tj.ErrorURI
+ 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
+ }
+ // according to spec, servers should respond status 400 in error case
+ // https://www.rfc-editor.org/rfc/rfc6749#section-5.2
+ // but some unorthodox servers respond 200 in error case
+ if failureStatus || retrieveError.ErrorCode != "" {
+ return nil, retrieveError
+ }
+ if token.AccessToken == "" {
+ return nil, errors.New("oauth2: server response missing access_token")
+ }
+ return token, nil
+}
+
+// mirrors oauth2.RetrieveError
+type RetrieveError struct {
+ Response *http.Response
+ Body []byte
+ ErrorCode string
+ ErrorDescription string
+ ErrorURI string
+}
+
+func (r *RetrieveError) Error() string {
+ if r.ErrorCode != "" {
+ s := fmt.Sprintf("oauth2: %q", r.ErrorCode)
+ if r.ErrorDescription != "" {
+ s += fmt.Sprintf(" %q", r.ErrorDescription)
+ }
+ if r.ErrorURI != "" {
+ s += fmt.Sprintf(" %q", r.ErrorURI)
+ }
+ return s
+ }
+ return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
+}
diff --git a/vendor/golang.org/x/oauth2/internal/transport.go b/vendor/golang.org/x/oauth2/internal/transport.go
new file mode 100644
index 0000000000..572074a637
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/internal/transport.go
@@ -0,0 +1,33 @@
+// 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 (
+ "context"
+ "net/http"
+)
+
+// 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{}
+
+var appengineClientHook func(context.Context) *http.Client
+
+func ContextClient(ctx context.Context) *http.Client {
+ if ctx != nil {
+ if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
+ return hc
+ }
+ }
+ if appengineClientHook != nil {
+ return appengineClientHook(ctx)
+ }
+ return http.DefaultClient
+}
diff --git a/vendor/golang.org/x/oauth2/internal/ya.make b/vendor/golang.org/x/oauth2/internal/ya.make
new file mode 100644
index 0000000000..b1350a0143
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/internal/ya.make
@@ -0,0 +1,18 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ doc.go
+ oauth2.go
+ token.go
+ transport.go
+)
+
+GO_TEST_SRCS(token_test.go)
+
+END()
+
+RECURSE(
+ gotest
+)
diff --git a/vendor/golang.org/x/oauth2/jws/jws.go b/vendor/golang.org/x/oauth2/jws/jws.go
new file mode 100644
index 0000000000..95015648b4
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/jws/jws.go
@@ -0,0 +1,182 @@
+// 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 jws provides a partial implementation
+// of JSON Web Signature encoding and decoding.
+// It exists to support the golang.org/x/oauth2 package.
+//
+// See RFC 7515.
+//
+// Deprecated: this package is not intended for public use and might be
+// removed in the future. It exists for internal use only.
+// Please switch to another JWS package or copy this package into your own
+// source tree.
+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 (seconds since Unix epoch)
+ Iat int64 `json:"iat"` // the time the assertion was issued (seconds since Unix epoch)
+ 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:"-"`
+}
+
+func (c *ClaimSet) encode() (string, error) {
+ // 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)
+ if c.Iat == 0 {
+ c.Iat = now.Unix()
+ }
+ if c.Exp == 0 {
+ c.Exp = now.Add(time.Hour).Unix()
+ }
+ if c.Exp < c.Iat {
+ return "", fmt.Errorf("jws: invalid Exp = %v; must be later than Iat = %v", c.Exp, c.Iat)
+ }
+
+ b, err := json.Marshal(c)
+ if err != nil {
+ return "", err
+ }
+
+ if len(c.PrivateClaims) == 0 {
+ return base64.RawURLEncoding.EncodeToString(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 base64.RawURLEncoding.EncodeToString(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"`
+
+ // The optional hint of which key is being used.
+ KeyID string `json:"kid,omitempty"`
+}
+
+func (h *Header) encode() (string, error) {
+ b, err := json.Marshal(h)
+ if err != nil {
+ return "", err
+ }
+ return base64.RawURLEncoding.EncodeToString(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 := base64.RawURLEncoding.DecodeString(s[1])
+ if err != nil {
+ return nil, err
+ }
+ c := &ClaimSet{}
+ err = json.NewDecoder(bytes.NewBuffer(decoded)).Decode(c)
+ return c, err
+}
+
+// Signer returns a signature for the given data.
+type Signer func(data []byte) (sig []byte, err error)
+
+// EncodeWithSigner encodes a header and claim set with the provided signer.
+func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (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)
+ sig, err := sg([]byte(ss))
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
+}
+
+// Encode encodes a signed JWS with provided header and claim set.
+// This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key.
+func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
+ sg := func(data []byte) (sig []byte, err error) {
+ h := sha256.New()
+ h.Write(data)
+ return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
+ }
+ return EncodeWithSigner(header, c, sg)
+}
+
+// Verify tests whether the provided JWT token's signature was produced by the private key
+// associated with the supplied public key.
+func Verify(token string, key *rsa.PublicKey) error {
+ parts := strings.Split(token, ".")
+ if len(parts) != 3 {
+ return errors.New("jws: invalid token received, token must have 3 parts")
+ }
+
+ signedContent := parts[0] + "." + parts[1]
+ signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
+ if err != nil {
+ return err
+ }
+
+ h := sha256.New()
+ h.Write([]byte(signedContent))
+ return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString)
+}
diff --git a/vendor/golang.org/x/oauth2/jws/ya.make b/vendor/golang.org/x/oauth2/jws/ya.make
new file mode 100644
index 0000000000..21ca432a4f
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/jws/ya.make
@@ -0,0 +1,15 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ jws.go
+)
+
+GO_TEST_SRCS(jws_test.go)
+
+END()
+
+RECURSE(
+ gotest
+)
diff --git a/vendor/golang.org/x/oauth2/jwt/jwt.go b/vendor/golang.org/x/oauth2/jwt/jwt.go
new file mode 100644
index 0000000000..b2bf18298b
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/jwt/jwt.go
@@ -0,0 +1,185 @@
+// 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 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 (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "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
+
+ // PrivateKeyID contains an optional hint indicating which key is being
+ // used.
+ PrivateKeyID string
+
+ // 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
+
+ // Expires optionally specifies how long the token is valid for.
+ Expires time.Duration
+
+ // Audience optionally specifies the intended audience of the
+ // request. If empty, the value of TokenURL is used as the
+ // intended audience.
+ Audience string
+
+ // PrivateClaims optionally specifies custom private claims in the JWT.
+ // See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
+ PrivateClaims map[string]interface{}
+
+ // UseIDToken optionally specifies whether ID token should be used instead
+ // of access token when the server returns both.
+ UseIDToken bool
+}
+
+// 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,
+ PrivateClaims: js.conf.PrivateClaims,
+ }
+ 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
+ }
+ if t := js.conf.Expires; t > 0 {
+ claimSet.Exp = time.Now().Add(t).Unix()
+ }
+ if aud := js.conf.Audience; aud != "" {
+ claimSet.Aud = aud
+ }
+ h := *defaultHeader
+ h.KeyID = js.conf.PrivateKeyID
+ payload, err := jws.Encode(&h, 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, &oauth2.RetrieveError{
+ Response: resp,
+ Body: 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)
+ }
+ if js.conf.UseIDToken {
+ if tokenRes.IDToken == "" {
+ return nil, fmt.Errorf("oauth2: response doesn't have JWT token")
+ }
+ token.AccessToken = tokenRes.IDToken
+ }
+ return token, nil
+}
diff --git a/vendor/golang.org/x/oauth2/jwt/ya.make b/vendor/golang.org/x/oauth2/jwt/ya.make
new file mode 100644
index 0000000000..6b3e758a4a
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/jwt/ya.make
@@ -0,0 +1,17 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ jwt.go
+)
+
+GO_TEST_SRCS(jwt_test.go)
+
+GO_XTEST_SRCS(example_test.go)
+
+END()
+
+RECURSE(
+ gotest
+)
diff --git a/vendor/golang.org/x/oauth2/oauth2.go b/vendor/golang.org/x/oauth2/oauth2.go
new file mode 100644
index 0000000000..90a2c3d6dc
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/oauth2.go
@@ -0,0 +1,421 @@
+// 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 oauth2 provides support for making
+// 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"
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "net/http"
+ "net/url"
+ "strings"
+ "sync"
+ "time"
+
+ "golang.org/x/oauth2/internal"
+)
+
+// NoContext is the default context you should supply if not using
+// your own context.Context (see https://golang.org/x/net/context).
+//
+// Deprecated: Use context.Background() or context.TODO() instead.
+var NoContext = context.TODO()
+
+// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
+//
+// Deprecated: this function no longer does anything. Caller code that
+// wants to avoid potential extra HTTP requests made during
+// auto-probing of the provider's auth style should set
+// Endpoint.AuthStyle.
+func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
+
+// Config describes a typical 3-legged OAuth2 flow, with both the
+// 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 {
+ // ClientID is the application's ID.
+ ClientID string
+
+ // ClientSecret is the application's secret.
+ ClientSecret string
+
+ // Endpoint contains the resource server's token endpoint
+ // URLs. These are constants specific to each server and are
+ // often available via site-specific packages, such as
+ // google.Endpoint or github.Endpoint.
+ Endpoint Endpoint
+
+ // RedirectURL is the URL to redirect users going through
+ // the OAuth flow, after the resource owner's URLs.
+ RedirectURL string
+
+ // Scope specifies optional requested permissions.
+ Scopes []string
+
+ // authStyleCache caches which auth style to use when Endpoint.AuthStyle is
+ // the zero value (AuthStyleAutoDetect).
+ authStyleCache internal.LazyAuthStyleCache
+}
+
+// A TokenSource is anything that can return a token.
+type TokenSource interface {
+ // Token returns a token or an error.
+ // Token must be safe for concurrent use by multiple goroutines.
+ // The returned Token must not be modified.
+ Token() (*Token, error)
+}
+
+// Endpoint represents an OAuth 2.0 provider's authorization and token
+// endpoint URLs.
+type Endpoint struct {
+ AuthURL string
+ DeviceAuthURL string
+ TokenURL string
+
+ // AuthStyle optionally specifies how the endpoint wants the
+ // client ID & client secret sent. The zero value means to
+ // auto-detect.
+ AuthStyle AuthStyle
+}
+
+// AuthStyle represents how requests for tokens are authenticated
+// to the server.
+type AuthStyle int
+
+const (
+ // AuthStyleAutoDetect means to auto-detect which authentication
+ // style the provider wants by trying both ways and caching
+ // the successful way for the future.
+ AuthStyleAutoDetect AuthStyle = 0
+
+ // AuthStyleInParams sends the "client_id" and "client_secret"
+ // in the POST body as application/x-www-form-urlencoded parameters.
+ AuthStyleInParams AuthStyle = 1
+
+ // AuthStyleInHeader sends the client_id and client_password
+ // using HTTP Basic Authorization. This is an optional style
+ // described in the OAuth2 RFC 6749 section 2.3.1.
+ AuthStyleInHeader AuthStyle = 2
+)
+
+var (
+ // AccessTypeOnline and AccessTypeOffline are options passed
+ // to the Options.AuthCodeURL method. They modify the
+ // "access_type" field that gets sent in the URL returned by
+ // AuthCodeURL.
+ //
+ // Online is the default if neither is specified. If your
+ // application needs to refresh access tokens when the user
+ // is not present at the browser, then use offline. This will
+ // result in your application obtaining a refresh token the
+ // first time your application exchanges an authorization
+ // code for a user.
+ AccessTypeOnline AuthCodeOption = SetAuthURLParam("access_type", "online")
+ AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline")
+
+ // ApprovalForce forces the users to view the consent dialog
+ // and confirm the permissions request at the URL returned
+ // from AuthCodeURL, even if they've already done so.
+ ApprovalForce AuthCodeOption = SetAuthURLParam("prompt", "consent")
+)
+
+// An AuthCodeOption is passed to Config.AuthCodeURL.
+type AuthCodeOption interface {
+ setValue(url.Values)
+}
+
+type setParam struct{ k, v string }
+
+func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) }
+
+// SetAuthURLParam builds an AuthCodeOption which passes key/value parameters
+// to a provider's authorization endpoint.
+func SetAuthURLParam(key, value string) AuthCodeOption {
+ return setParam{key, value}
+}
+
+// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
+// that asks for permissions for the required scopes explicitly.
+//
+// State is an opaque value used by the client to maintain state between the
+// request and callback. The authorization server includes this value when
+// redirecting the user agent back to the client.
+//
+// Opts may include AccessTypeOnline or AccessTypeOffline, as well
+// as ApprovalForce.
+//
+// To protect against CSRF attacks, opts should include a PKCE challenge
+// (S256ChallengeOption). Not all servers support PKCE. An alternative is to
+// generate a random state parameter and verify it after exchange.
+// See https://datatracker.ietf.org/doc/html/rfc6749#section-10.12 (predating
+// PKCE), https://www.oauth.com/oauth2-servers/pkce/ and
+// https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.html#name-cross-site-request-forgery (describing both approaches)
+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},
+ }
+ if c.RedirectURL != "" {
+ v.Set("redirect_uri", c.RedirectURL)
+ }
+ if len(c.Scopes) > 0 {
+ v.Set("scope", strings.Join(c.Scopes, " "))
+ }
+ if state != "" {
+ v.Set("state", state)
+ }
+ for _, opt := range opts {
+ opt.setValue(v)
+ }
+ if strings.Contains(c.Endpoint.AuthURL, "?") {
+ buf.WriteByte('&')
+ } else {
+ buf.WriteByte('?')
+ }
+ buf.WriteString(v.Encode())
+ return buf.String()
+}
+
+// PasswordCredentialsToken converts a resource owner username and password
+// pair into a token.
+//
+// Per the RFC, this grant type should only be used "when there is a high
+// degree of trust between the resource owner and the client (e.g., the client
+// is part of the device operating system or a highly privileged application),
+// and when other authorization grant types are not available."
+// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
+//
+// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
+func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
+ v := url.Values{
+ "grant_type": {"password"},
+ "username": {username},
+ "password": {password},
+ }
+ 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.
+//
+// It is used after a resource provider redirects the user back
+// to the Redirect URI (the URL obtained from AuthCodeURL).
+//
+// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
+//
+// The code will be in the *http.Request.FormValue("code"). Before
+// calling Exchange, be sure to validate FormValue("state") if you are
+// using it to protect against CSRF attacks.
+//
+// If using PKCE to protect against CSRF attacks, opts should include a
+// VerifierOption.
+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.
+// The token will auto-refresh as necessary. The underlying
+// HTTP transport will be obtained using the provided context.
+// The returned client and its Transport should not be modified.
+func (c *Config) Client(ctx context.Context, t *Token) *http.Client {
+ return NewClient(ctx, c.TokenSource(ctx, t))
+}
+
+// TokenSource returns a TokenSource that returns t until t expires,
+// automatically refreshing it as necessary using the provided context.
+//
+// Most users will use Config.Client instead.
+func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource {
+ tkr := &tokenRefresher{
+ ctx: ctx,
+ conf: c,
+ }
+ if t != nil {
+ tkr.refreshToken = t.RefreshToken
+ }
+ return &reuseTokenSource{
+ t: t,
+ new: tkr,
+ }
+}
+
+// tokenRefresher is a TokenSource that makes "grant_type"=="refresh_token"
+// HTTP requests to renew a token using a RefreshToken.
+type tokenRefresher struct {
+ ctx context.Context // used to get HTTP requests
+ conf *Config
+ refreshToken string
+}
+
+// WARNING: Token is not safe for concurrent access, as it
+// updates the tokenRefresher's refreshToken field.
+// Within this package, it is used by reuseTokenSource which
+// synchronizes calls to this method with its own mutex.
+func (tf *tokenRefresher) Token() (*Token, error) {
+ if tf.refreshToken == "" {
+ return nil, errors.New("oauth2: token expired and refresh token is not set")
+ }
+
+ tk, err := retrieveToken(tf.ctx, tf.conf, url.Values{
+ "grant_type": {"refresh_token"},
+ "refresh_token": {tf.refreshToken},
+ })
+
+ if err != nil {
+ return nil, err
+ }
+ if tf.refreshToken != tk.RefreshToken {
+ tf.refreshToken = tk.RefreshToken
+ }
+ return tk, err
+}
+
+// reuseTokenSource is a TokenSource that holds a single token in memory
+// and validates its expiry before each call to retrieve it with
+// Token. If it's expired, it will be auto-refreshed using the
+// new TokenSource.
+type reuseTokenSource struct {
+ new TokenSource // called when t is expired.
+
+ mu sync.Mutex // guards t
+ t *Token
+
+ expiryDelta time.Duration
+}
+
+// Token returns the current token if it's still valid, else will
+// refresh the current token (using r.Context for HTTP client
+// information) and return the new one.
+func (s *reuseTokenSource) Token() (*Token, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.t.Valid() {
+ return s.t, nil
+ }
+ t, err := s.new.Token()
+ if err != nil {
+ return nil, err
+ }
+ t.expiryDelta = s.expiryDelta
+ s.t = t
+ return t, nil
+}
+
+// StaticTokenSource returns a TokenSource that always returns the same token.
+// Because the provided token t is never refreshed, StaticTokenSource is only
+// useful for tokens that never expire.
+func StaticTokenSource(t *Token) TokenSource {
+ return staticTokenSource{t}
+}
+
+// staticTokenSource is a TokenSource that always returns the same Token.
+type staticTokenSource struct {
+ t *Token
+}
+
+func (s staticTokenSource) Token() (*Token, error) {
+ return s.t, nil
+}
+
+// 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 internal.ContextKey
+
+// NewClient creates an *http.Client from a Context and TokenSource.
+// The returned client is not valid beyond the lifetime of the context.
+//
+// Note that if a custom *http.Client is provided via the Context it
+// is used only for token acquisition and is not used to configure the
+// *http.Client returned from NewClient.
+//
+// As a special case, if src is nil, a non-OAuth2 client is returned
+// using the provided context. This exists to support related OAuth2
+// packages.
+func NewClient(ctx context.Context, src TokenSource) *http.Client {
+ if src == nil {
+ return internal.ContextClient(ctx)
+ }
+ return &http.Client{
+ Transport: &Transport{
+ Base: internal.ContextClient(ctx).Transport,
+ Source: ReuseTokenSource(nil, src),
+ },
+ }
+}
+
+// ReuseTokenSource returns a TokenSource which repeatedly returns the
+// same token as long as it's valid, starting with t.
+// When its cached token is invalid, a new token is obtained from src.
+//
+// ReuseTokenSource is typically used to reuse tokens from a cache
+// (such as a file on disk) between runs of a program, rather than
+// obtaining new tokens unnecessarily.
+//
+// The initial token t may be nil, in which case the TokenSource is
+// wrapped in a caching version if it isn't one already. This also
+// means it's always safe to wrap ReuseTokenSource around any other
+// TokenSource without adverse effects.
+func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
+ // Don't wrap a reuseTokenSource in itself. That would work,
+ // but cause an unnecessary number of mutex operations.
+ // Just build the equivalent one.
+ if rt, ok := src.(*reuseTokenSource); ok {
+ if t == nil {
+ // Just use it directly.
+ return rt
+ }
+ src = rt.new
+ }
+ return &reuseTokenSource{
+ t: t,
+ new: src,
+ }
+}
+
+// ReuseTokenSource returns a TokenSource that acts in the same manner as the
+// TokenSource returned by ReuseTokenSource, except the expiry buffer is
+// configurable. The expiration time of a token is calculated as
+// t.Expiry.Add(-earlyExpiry).
+func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource {
+ // Don't wrap a reuseTokenSource in itself. That would work,
+ // but cause an unnecessary number of mutex operations.
+ // Just build the equivalent one.
+ if rt, ok := src.(*reuseTokenSource); ok {
+ if t == nil {
+ // Just use it directly, but set the expiryDelta to earlyExpiry,
+ // so the behavior matches what the user expects.
+ rt.expiryDelta = earlyExpiry
+ return rt
+ }
+ src = rt.new
+ }
+ if t != nil {
+ t.expiryDelta = earlyExpiry
+ }
+ return &reuseTokenSource{
+ t: t,
+ new: src,
+ expiryDelta: earlyExpiry,
+ }
+}
diff --git a/vendor/golang.org/x/oauth2/pkce.go b/vendor/golang.org/x/oauth2/pkce.go
new file mode 100644
index 0000000000..50593b6dfe
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/pkce.go
@@ -0,0 +1,68 @@
+// Copyright 2023 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 oauth2
+
+import (
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/base64"
+ "net/url"
+)
+
+const (
+ codeChallengeKey = "code_challenge"
+ codeChallengeMethodKey = "code_challenge_method"
+ codeVerifierKey = "code_verifier"
+)
+
+// GenerateVerifier generates a PKCE code verifier with 32 octets of randomness.
+// This follows recommendations in RFC 7636.
+//
+// A fresh verifier should be generated for each authorization.
+// S256ChallengeOption(verifier) should then be passed to Config.AuthCodeURL
+// (or Config.DeviceAccess) and VerifierOption(verifier) to Config.Exchange
+// (or Config.DeviceAccessToken).
+func GenerateVerifier() string {
+ // "RECOMMENDED that the output of a suitable random number generator be
+ // used to create a 32-octet sequence. The octet sequence is then
+ // base64url-encoded to produce a 43-octet URL-safe string to use as the
+ // code verifier."
+ // https://datatracker.ietf.org/doc/html/rfc7636#section-4.1
+ data := make([]byte, 32)
+ if _, err := rand.Read(data); err != nil {
+ panic(err)
+ }
+ return base64.RawURLEncoding.EncodeToString(data)
+}
+
+// VerifierOption returns a PKCE code verifier AuthCodeOption. It should be
+// passed to Config.Exchange or Config.DeviceAccessToken only.
+func VerifierOption(verifier string) AuthCodeOption {
+ return setParam{k: codeVerifierKey, v: verifier}
+}
+
+// S256ChallengeFromVerifier returns a PKCE code challenge derived from verifier with method S256.
+//
+// Prefer to use S256ChallengeOption where possible.
+func S256ChallengeFromVerifier(verifier string) string {
+ sha := sha256.Sum256([]byte(verifier))
+ return base64.RawURLEncoding.EncodeToString(sha[:])
+}
+
+// S256ChallengeOption derives a PKCE code challenge derived from verifier with
+// method S256. It should be passed to Config.AuthCodeURL or Config.DeviceAccess
+// only.
+func S256ChallengeOption(verifier string) AuthCodeOption {
+ return challengeOption{
+ challenge_method: "S256",
+ challenge: S256ChallengeFromVerifier(verifier),
+ }
+}
+
+type challengeOption struct{ challenge_method, challenge string }
+
+func (p challengeOption) setValue(m url.Values) {
+ m.Set(codeChallengeMethodKey, p.challenge_method)
+ m.Set(codeChallengeKey, p.challenge)
+}
diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go
new file mode 100644
index 0000000000..5bbb332174
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/token.go
@@ -0,0 +1,205 @@
+// 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 oauth2
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "golang.org/x/oauth2/internal"
+)
+
+// defaultExpiryDelta determines how earlier a token should be considered
+// expired than its actual expiration time. It is used to avoid late
+// expirations due to client-server time mismatches.
+const defaultExpiryDelta = 10 * time.Second
+
+// Token represents the credentials used to authorize
+// the requests to access protected resources on the OAuth 2.0
+// provider's backend.
+//
+// Most users of this package should not access fields of Token
+// directly. They're exported mostly for use by related packages
+// implementing derivative OAuth2 flows.
+type Token struct {
+ // AccessToken is the token that authorizes and authenticates
+ // the requests.
+ AccessToken string `json:"access_token"`
+
+ // TokenType is the type of token.
+ // The Type method returns either this or "Bearer", the default.
+ TokenType string `json:"token_type,omitempty"`
+
+ // 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 `json:"refresh_token,omitempty"`
+
+ // 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 `json:"expiry,omitempty"`
+
+ // raw optionally contains extra metadata from the server
+ // when updating a token.
+ raw interface{}
+
+ // expiryDelta is used to calculate when a token is considered
+ // expired, by subtracting from Expiry. If zero, defaultExpiryDelta
+ // is used.
+ expiryDelta time.Duration
+}
+
+// Type returns t.TokenType if non-empty, else "Bearer".
+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 != "" {
+ return t.TokenType
+ }
+ return "Bearer"
+}
+
+// SetAuthHeader sets the Authorization header to r using the access
+// token in t.
+//
+// This method is unnecessary when using Transport or an HTTP Client
+// returned by this package.
+func (t *Token) SetAuthHeader(r *http.Request) {
+ r.Header.Set("Authorization", t.Type()+" "+t.AccessToken)
+}
+
+// WithExtra returns a new Token that's a clone of t, but using the
+// provided raw extra map. This is only intended for use by packages
+// implementing derivative OAuth2 flows.
+func (t *Token) WithExtra(extra interface{}) *Token {
+ t2 := new(Token)
+ *t2 = *t
+ t2.raw = extra
+ return t2
+}
+
+// Extra returns an extra field.
+// Extra fields are key-value pairs returned by the server as a
+// part of the token retrieval response.
+func (t *Token) Extra(key string) interface{} {
+ if raw, ok := t.raw.(map[string]interface{}); ok {
+ return raw[key]
+ }
+
+ 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
+}
+
+// timeNow is time.Now but pulled out as a variable for tests.
+var timeNow = time.Now
+
+// expired reports whether the token is expired.
+// t must be non-nil.
+func (t *Token) expired() bool {
+ if t.Expiry.IsZero() {
+ return false
+ }
+
+ expiryDelta := defaultExpiryDelta
+ if t.expiryDelta != 0 {
+ expiryDelta = t.expiryDelta
+ }
+ return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
+}
+
+// Valid reports whether t is non-nil, has an AccessToken, and is not expired.
+func (t *Token) Valid() bool {
+ return t != nil && t.AccessToken != "" && !t.expired()
+}
+
+// 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, internal.AuthStyle(c.Endpoint.AuthStyle), c.authStyleCache.Get())
+ 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 or populates RFC 6749's 'error' parameter.
+// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
+type RetrieveError struct {
+ Response *http.Response
+ // Body is the body that was consumed by reading Response.Body.
+ // It may be truncated.
+ Body []byte
+ // ErrorCode is RFC 6749's 'error' parameter.
+ ErrorCode string
+ // ErrorDescription is RFC 6749's 'error_description' parameter.
+ ErrorDescription string
+ // ErrorURI is RFC 6749's 'error_uri' parameter.
+ ErrorURI string
+}
+
+func (r *RetrieveError) Error() string {
+ if r.ErrorCode != "" {
+ s := fmt.Sprintf("oauth2: %q", r.ErrorCode)
+ if r.ErrorDescription != "" {
+ s += fmt.Sprintf(" %q", r.ErrorDescription)
+ }
+ if r.ErrorURI != "" {
+ s += fmt.Sprintf(" %q", r.ErrorURI)
+ }
+ return s
+ }
+ return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
+}
diff --git a/vendor/golang.org/x/oauth2/transport.go b/vendor/golang.org/x/oauth2/transport.go
new file mode 100644
index 0000000000..90657915fb
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/transport.go
@@ -0,0 +1,89 @@
+// 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 oauth2
+
+import (
+ "errors"
+ "log"
+ "net/http"
+ "sync"
+)
+
+// Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests,
+// wrapping a base RoundTripper and adding an Authorization header
+// with a token from the supplied Sources.
+//
+// Transport is a low-level mechanism. Most code will use the
+// higher-level Config.Client method instead.
+type Transport struct {
+ // Source supplies the token to add to outgoing requests'
+ // Authorization headers.
+ Source TokenSource
+
+ // Base is the base RoundTripper used to make HTTP requests.
+ // If nil, http.DefaultTransport is used.
+ Base http.RoundTripper
+}
+
+// RoundTrip authorizes and authenticates the request with an
+// 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")
+ }
+ token, err := t.Source.Token()
+ if err != nil {
+ return nil, err
+ }
+
+ req2 := cloneRequest(req) // per RoundTripper contract
+ token.SetAuthHeader(req2)
+
+ // req.Body is assumed to be closed by the base RoundTripper.
+ reqBodyClosed = true
+ return t.base().RoundTrip(req2)
+}
+
+var cancelOnce sync.Once
+
+// CancelRequest does nothing. It used to be a legacy cancellation mechanism
+// but now only it only logs on first use to warn that it's deprecated.
+//
+// Deprecated: use contexts for cancellation instead.
+func (t *Transport) CancelRequest(req *http.Request) {
+ cancelOnce.Do(func() {
+ log.Printf("deprecated: golang.org/x/oauth2: Transport.CancelRequest no longer does anything; use contexts")
+ })
+}
+
+func (t *Transport) base() http.RoundTripper {
+ if t.Base != nil {
+ return t.Base
+ }
+ return http.DefaultTransport
+}
+
+// cloneRequest returns a clone of the provided *http.Request.
+// The clone is a shallow copy of the struct and its Header map.
+func cloneRequest(r *http.Request) *http.Request {
+ // shallow copy of the struct
+ r2 := new(http.Request)
+ *r2 = *r
+ // deep copy of the Header
+ r2.Header = make(http.Header, len(r.Header))
+ for k, s := range r.Header {
+ r2.Header[k] = append([]string(nil), s...)
+ }
+ return r2
+}
diff --git a/vendor/golang.org/x/oauth2/ya.make b/vendor/golang.org/x/oauth2/ya.make
new file mode 100644
index 0000000000..50ffaf1f94
--- /dev/null
+++ b/vendor/golang.org/x/oauth2/ya.make
@@ -0,0 +1,62 @@
+GO_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+SRCS(
+ deviceauth.go
+ oauth2.go
+ pkce.go
+ token.go
+ transport.go
+)
+
+GO_TEST_SRCS(
+ deviceauth_test.go
+ oauth2_test.go
+ token_test.go
+ transport_test.go
+)
+
+GO_XTEST_SRCS(example_test.go)
+
+END()
+
+RECURSE(
+ amazon
+ authhandler
+ bitbucket
+ cern
+ clientcredentials
+ endpoints
+ facebook
+ fitbit
+ foursquare
+ github
+ gitlab
+ google
+ gotest
+ heroku
+ hipchat
+ instagram
+ internal
+ jira
+ jws
+ jwt
+ kakao
+ linkedin
+ mailchimp
+ mailru
+ mediamath
+ microsoft
+ nokiahealth
+ odnoklassniki
+ paypal
+ slack
+ spotify
+ stackoverflow
+ twitch
+ uber
+ vk
+ yahoo
+ yandex
+)