Преглед изворни кода

vendor: golang.org/x/oauth2 v0.1.0

The golang.org/x/ projects are now doing tagged releases.

Some notable changes:

- authhandler: Add support for PKCE
- Introduce new AuthenticationError type returned by errWrappingTokenSource.Token
- Add support to set JWT Audience in JWTConfigFromJSON()
- google/internal: Add AWS Session Token to Metadata Requests
- go.mod: update vulnerable net library
- google: add support for "impersonated_service_account" credential type.
- google/externalaccount: add support for workforce pool credentials

full diff: https://github.com/golang/oauth2/compare/2bc19b11175f...v0.1.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit a6cb8efd81ac4d99ca8c187f2dbe4d2412bc954a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn пре 2 година
родитељ
комит
10fa0d5321

+ 1 - 1
vendor.mod

@@ -159,7 +159,7 @@ require (
 	go.uber.org/multierr v1.6.0 // indirect
 	go.uber.org/zap v1.17.0 // indirect
 	golang.org/x/crypto v0.1.0 // indirect
-	golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
+	golang.org/x/oauth2 v0.1.0 // indirect
 	golang.org/x/text v0.4.0 // indirect
 	google.golang.org/api v0.54.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect

+ 2 - 1
vendor.sum

@@ -1295,8 +1295,9 @@ golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
 golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
+golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

+ 0 - 3
vendor/golang.org/x/oauth2/AUTHORS

@@ -1,3 +0,0 @@
-# This source code refers to The Go Authors for copyright purposes.
-# The master list of authors is in the main Go distribution,
-# visible at http://tip.golang.org/AUTHORS.

+ 0 - 3
vendor/golang.org/x/oauth2/CONTRIBUTORS

@@ -1,3 +0,0 @@
-# This source code was written by the Go contributors.
-# The master list of contributors is in the main Go distribution,
-# visible at http://tip.golang.org/CONTRIBUTORS.

+ 41 - 3
vendor/golang.org/x/oauth2/authhandler/authhandler.go

@@ -13,11 +13,36 @@ import (
 	"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.
 //
@@ -33,7 +58,7 @@ type AuthorizationHandler func(authCodeURL string) (code string, state string, e
 // 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 oauth2.ReuseTokenSource(nil, authHandlerSource{config: config, ctx: ctx, authHandler: authHandler, state: state})
+	return TokenSourceWithPKCE(ctx, config, state, authHandler, nil)
 }
 
 type authHandlerSource struct {
@@ -41,10 +66,17 @@ type authHandlerSource struct {
 	config      *oauth2.Config
 	authHandler AuthorizationHandler
 	state       string
+	pkce        *PKCEParams
 }
 
 func (source authHandlerSource) Token() (*oauth2.Token, error) {
-	url := source.config.AuthCodeURL(source.state)
+	// 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
@@ -52,5 +84,11 @@ func (source authHandlerSource) Token() (*oauth2.Token, error) {
 	if state != source.state {
 		return nil, errors.New("state mismatch in 3-legged-OAuth flow")
 	}
-	return source.config.Exchange(source.ctx, code)
+
+	// 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...)
 }

+ 21 - 17
vendor/golang.org/x/oauth2/google/default.go

@@ -54,11 +54,14 @@ type CredentialsParams struct {
 	// Optional.
 	Subject string
 
-	// AuthHandler is the AuthorizationHandler used for 3-legged OAuth flow. Optional.
+	// 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. Optional.
+	// 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
 }
 
 func (params CredentialsParams) deepCopy() CredentialsParams {
@@ -94,20 +97,20 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
 // 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.
+//  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()
@@ -176,7 +179,7 @@ func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params
 	if config != nil {
 		return &Credentials{
 			ProjectID:   "",
-			TokenSource: authhandler.TokenSource(ctx, config, params.State, params.AuthHandler),
+			TokenSource: authhandler.TokenSourceWithPKCE(ctx, config, params.State, params.AuthHandler, params.PKCE),
 			JSON:        jsonData,
 		}, nil
 	}
@@ -190,6 +193,7 @@ func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params
 	if err != nil {
 		return nil, err
 	}
+	ts = newErrWrappingTokenSource(ts)
 	return &DefaultCredentials{
 		ProjectID:   f.ProjectID,
 		TokenSource: ts,

+ 15 - 10
vendor/golang.org/x/oauth2/google/doc.go

@@ -15,14 +15,14 @@
 // For more information on using workload identity federation, refer to
 // https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation.
 //
-// OAuth2 Configs
+// # 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
+// # Workload Identity Federation
 //
 // Using workload identity federation, your application can access Google Cloud
 // resources from Amazon Web Services (AWS), Microsoft Azure or any identity
@@ -36,13 +36,14 @@
 // Follow the detailed instructions on how to configure Workload Identity Federation
 // in various platforms:
 //
-//   Amazon Web Services (AWS): https://cloud.google.com/iam/docs/access-resources-aws
-//   Microsoft Azure: https://cloud.google.com/iam/docs/access-resources-azure
-//   OIDC identity provider: https://cloud.google.com/iam/docs/access-resources-oidc
+//	Amazon Web Services (AWS): https://cloud.google.com/iam/docs/access-resources-aws
+//	Microsoft Azure: https://cloud.google.com/iam/docs/access-resources-azure
+//	OIDC identity provider: https://cloud.google.com/iam/docs/access-resources-oidc
 //
-// For OIDC providers, the library can retrieve OIDC tokens either from a
-// local file location (file-sourced credentials) or from a local server
-// (URL-sourced credentials).
+// 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 token prior to expiration.
 // For tokens with one hour lifetimes, the token needs to be updated in the file
@@ -50,9 +51,13 @@
 // For URL-sourced credentials, a local server needs to host a GET endpoint to
 // return the OIDC 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 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/using-workload-identity-federation#oidc
 //
-//
-// Credentials
+// # Credentials
 //
 // The Credentials type represents Google credentials, including Application Default
 // Credentials.

+ 64 - 0
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
+}

+ 39 - 8
vendor/golang.org/x/oauth2/google/google.go

@@ -92,9 +92,10 @@ func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
 
 // JSON key file types.
 const (
-	serviceAccountKey  = "service_account"
-	userCredentialsKey = "authorized_user"
-	externalAccountKey = "external_account"
+	serviceAccountKey          = "service_account"
+	userCredentialsKey         = "authorized_user"
+	externalAccountKey         = "external_account"
+	impersonatedServiceAccount = "impersonated_service_account"
 )
 
 // credentialsFile is the unmarshalled representation of a credentials file.
@@ -121,8 +122,18 @@ type credentialsFile struct {
 	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"`
+
+	// 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 {
@@ -133,6 +144,7 @@ func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config
 		Scopes:       scopes,
 		TokenURL:     f.TokenURL,
 		Subject:      subject, // This is the user email to impersonate
+		Audience:     f.Audience,
 	}
 	if cfg.TokenURL == "" {
 		cfg.TokenURL = JWTTokenURL
@@ -171,13 +183,32 @@ func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsPar
 			TokenURL:                       f.TokenURLExternal,
 			TokenInfoURL:                   f.TokenInfoURL,
 			ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
-			ClientSecret:                   f.ClientSecret,
-			ClientID:                       f.ClientID,
-			CredentialSource:               f.CredentialSource,
-			QuotaProjectID:                 f.QuotaProjectID,
-			Scopes:                         params.Scopes,
+			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 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:

+ 68 - 8
vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go

@@ -52,6 +52,13 @@ const (
 	// 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"
 
@@ -241,6 +248,7 @@ type awsCredentialSource struct {
 	RegionURL                   string
 	RegionalCredVerificationURL string
 	CredVerificationURL         string
+	IMDSv2SessionTokenURL       string
 	TargetResource              string
 	requestSigner               *awsRequestSigner
 	region                      string
@@ -268,12 +276,22 @@ func (cs awsCredentialSource) doRequest(req *http.Request) (*http.Response, erro
 
 func (cs awsCredentialSource) subjectToken() (string, error) {
 	if cs.requestSigner == nil {
-		awsSecurityCredentials, err := cs.getSecurityCredentials()
+		awsSessionToken, err := cs.getAWSSessionToken()
+		if err != nil {
+			return "", err
+		}
+
+		headers := make(map[string]string)
+		if awsSessionToken != "" {
+			headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
+		}
+
+		awsSecurityCredentials, err := cs.getSecurityCredentials(headers)
 		if err != nil {
 			return "", err
 		}
 
-		if cs.region, err = cs.getRegion(); err != nil {
+		if cs.region, err = cs.getRegion(headers); err != nil {
 			return "", err
 		}
 
@@ -340,7 +358,37 @@ func (cs awsCredentialSource) subjectToken() (string, error) {
 	return url.QueryEscape(string(result)), nil
 }
 
-func (cs *awsCredentialSource) getRegion() (string, error) {
+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 envAwsRegion := getenv("AWS_REGION"); envAwsRegion != "" {
 		return envAwsRegion, nil
 	}
@@ -357,6 +405,10 @@ func (cs *awsCredentialSource) getRegion() (string, error) {
 		return "", err
 	}
 
+	for name, value := range headers {
+		req.Header.Add(name, value)
+	}
+
 	resp, err := cs.doRequest(req)
 	if err != nil {
 		return "", err
@@ -381,7 +433,7 @@ func (cs *awsCredentialSource) getRegion() (string, error) {
 	return string(respBody[:respBodyEnd]), nil
 }
 
-func (cs *awsCredentialSource) getSecurityCredentials() (result awsSecurityCredentials, err error) {
+func (cs *awsCredentialSource) getSecurityCredentials(headers map[string]string) (result awsSecurityCredentials, err error) {
 	if accessKeyID := getenv("AWS_ACCESS_KEY_ID"); accessKeyID != "" {
 		if secretAccessKey := getenv("AWS_SECRET_ACCESS_KEY"); secretAccessKey != "" {
 			return awsSecurityCredentials{
@@ -392,12 +444,12 @@ func (cs *awsCredentialSource) getSecurityCredentials() (result awsSecurityCrede
 		}
 	}
 
-	roleName, err := cs.getMetadataRoleName()
+	roleName, err := cs.getMetadataRoleName(headers)
 	if err != nil {
 		return
 	}
 
-	credentials, err := cs.getMetadataSecurityCredentials(roleName)
+	credentials, err := cs.getMetadataSecurityCredentials(roleName, headers)
 	if err != nil {
 		return
 	}
@@ -413,7 +465,7 @@ func (cs *awsCredentialSource) getSecurityCredentials() (result awsSecurityCrede
 	return credentials, nil
 }
 
-func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string) (awsSecurityCredentials, error) {
+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)
@@ -422,6 +474,10 @@ func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string) (
 	}
 	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
@@ -441,7 +497,7 @@ func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string) (
 	return result, err
 }
 
-func (cs *awsCredentialSource) getMetadataRoleName() (string, error) {
+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")
 	}
@@ -451,6 +507,10 @@ func (cs *awsCredentialSource) getMetadataRoleName() (string, error) {
 		return "", err
 	}
 
+	for name, value := range headers {
+		req.Header.Add(name, value)
+	}
+
 	resp, err := cs.doRequest(req)
 	if err != nil {
 		return "", err

+ 59 - 12
vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go

@@ -39,6 +39,9 @@ type Config struct {
 	// 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.
@@ -53,6 +56,11 @@ type Config struct {
 	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
 }
 
 // Each element consists of a list of patterns.  validateURLs checks for matches
@@ -66,13 +74,16 @@ var (
 		regexp.MustCompile(`(?i)^sts\.googleapis\.com$`),
 		regexp.MustCompile(`(?i)^sts\.[^\.\s\/\\]+\.googleapis\.com$`),
 		regexp.MustCompile(`(?i)^[^\.\s\/\\]+-sts\.googleapis\.com$`),
+		regexp.MustCompile(`(?i)^sts-[^\.\s\/\\]+\.p\.googleapis\.com$`),
 	}
 	validImpersonateURLPatterns = []*regexp.Regexp{
 		regexp.MustCompile(`^[^\.\s\/\\]+\.iamcredentials\.googleapis\.com$`),
 		regexp.MustCompile(`^iamcredentials\.googleapis\.com$`),
 		regexp.MustCompile(`^iamcredentials\.[^\.\s\/\\]+\.googleapis\.com$`),
 		regexp.MustCompile(`^[^\.\s\/\\]+-iamcredentials\.googleapis\.com$`),
+		regexp.MustCompile(`^iamcredentials-[^\.\s\/\\]+\.p\.googleapis\.com$`),
 	}
+	validWorkforceAudiencePattern *regexp.Regexp = regexp.MustCompile(`//iam\.googleapis\.com/locations/[^/]+/workforcePools/`)
 )
 
 func validateURL(input string, patterns []*regexp.Regexp, scheme string) bool {
@@ -86,14 +97,17 @@ func validateURL(input string, patterns []*regexp.Regexp, scheme string) bool {
 	toTest := parsed.Host
 
 	for _, pattern := range patterns {
-
-		if valid := pattern.MatchString(toTest); valid {
+		if pattern.MatchString(toTest) {
 			return true
 		}
 	}
 	return false
 }
 
+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, validTokenURLPatterns, validImpersonateURLPatterns, "https")
@@ -115,6 +129,13 @@ func (c *Config) tokenSource(ctx context.Context, tokenURLValidPats []*regexp.Re
 		}
 	}
 
+	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,
@@ -124,11 +145,12 @@ func (c *Config) tokenSource(ctx context.Context, tokenURLValidPats []*regexp.Re
 	}
 	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),
+	imp := ImpersonateTokenSource{
+		Ctx:                  ctx,
+		URL:                  c.ServiceAccountImpersonationURL,
+		Scopes:               scopes,
+		Ts:                   oauth2.ReuseTokenSource(nil, ts),
+		TokenLifetimeSeconds: c.ServiceAccountImpersonationLifetimeSeconds,
 	}
 	return oauth2.ReuseTokenSource(nil, imp), nil
 }
@@ -147,7 +169,7 @@ type format struct {
 }
 
 // CredentialSource stores the information necessary to retrieve the credentials for the STS exchange.
-// Either the File or the URL field should be filled, depending on the kind of credential in question.
+// 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"`
@@ -155,33 +177,50 @@ type CredentialSource struct {
 	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"`
 }
 
-// parse determines the type of CredentialSource needed
+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)
 			}
-			return awsCredentialSource{
+
+			awsCredSource := awsCredentialSource{
 				EnvironmentID:               c.CredentialSource.EnvironmentID,
 				RegionURL:                   c.CredentialSource.RegionURL,
 				RegionalCredVerificationURL: c.CredentialSource.RegionalCredVerificationURL,
 				CredVerificationURL:         c.CredentialSource.URL,
 				TargetResource:              c.Audience,
 				ctx:                         ctx,
-			}, nil
+			}
+			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")
 }
@@ -224,7 +263,15 @@ func (ts tokenSource) Token() (*oauth2.Token, error) {
 		ClientID:     conf.ClientID,
 		ClientSecret: conf.ClientSecret,
 	}
-	stsResp, err := exchangeToken(ts.ctx, conf.TokenURL, &stsRequest, clientAuth, header, nil)
+	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 := exchangeToken(ts.ctx, conf.TokenURL, &stsRequest, clientAuth, header, options)
 	if err != nil {
 		return nil, err
 	}

+ 309 - 0
vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go

@@ -0,0 +1,309 @@
+// 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) 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())
+}

+ 32 - 11
vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go

@@ -29,30 +29,51 @@ type impersonateTokenResponse struct {
 	ExpireTime  string `json:"expireTime"`
 }
 
-type impersonateTokenSource struct {
-	ctx context.Context
-	ts  oauth2.TokenSource
+// 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    string
-	scopes []string
+	// 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) {
+func (its ImpersonateTokenSource) Token() (*oauth2.Token, error) {
+	lifetimeString := "3600s"
+	if its.TokenLifetimeSeconds != 0 {
+		lifetimeString = fmt.Sprintf("%ds", its.TokenLifetimeSeconds)
+	}
 	reqBody := generateAccessTokenReq{
-		Lifetime: "3600s",
-		Scope:    its.scopes,
+		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))
+	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 = req.WithContext(its.Ctx)
 	req.Header.Set("Content-Type", "application/json")
 
 	resp, err := client.Do(req)

+ 2 - 1
vendor/golang.org/x/oauth2/google/jwt.go

@@ -66,7 +66,8 @@ func newJWTSource(jsonKey []byte, audience string, scopes []string) (oauth2.Toke
 	if err != nil {
 		return nil, err
 	}
-	return oauth2.ReuseTokenSource(tok, ts), nil
+	rts := newErrWrappingTokenSource(oauth2.ReuseTokenSource(tok, ts))
+	return rts, nil
 }
 
 type jwtAccessTokenSource struct {

+ 1 - 1
vendor/golang.org/x/oauth2/jws/jws.go

@@ -178,5 +178,5 @@ func Verify(token string, key *rsa.PublicKey) error {
 
 	h := sha256.New()
 	h.Write([]byte(signedContent))
-	return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
+	return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString)
 }

+ 2 - 2
vendor/modules.txt

@@ -939,8 +939,8 @@ golang.org/x/net/ipv6
 golang.org/x/net/proxy
 golang.org/x/net/trace
 golang.org/x/net/websocket
-# golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
-## explicit; go 1.11
+# golang.org/x/oauth2 v0.1.0
+## explicit; go 1.17
 golang.org/x/oauth2
 golang.org/x/oauth2/authhandler
 golang.org/x/oauth2/google