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 a6cb8efd81
)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
356f483038
commit
10fa0d5321
16 changed files with 656 additions and 81 deletions
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
3
vendor/golang.org/x/oauth2/AUTHORS
generated
vendored
3
vendor/golang.org/x/oauth2/AUTHORS
generated
vendored
|
@ -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.
|
3
vendor/golang.org/x/oauth2/CONTRIBUTORS
generated
vendored
3
vendor/golang.org/x/oauth2/CONTRIBUTORS
generated
vendored
|
@ -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.
|
44
vendor/golang.org/x/oauth2/authhandler/authhandler.go
generated
vendored
44
vendor/golang.org/x/oauth2/authhandler/authhandler.go
generated
vendored
|
@ -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...)
|
||||
}
|
||||
|
|
38
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
38
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
|
@ -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,
|
||||
|
|
25
vendor/golang.org/x/oauth2/google/doc.go
generated
vendored
25
vendor/golang.org/x/oauth2/google/doc.go
generated
vendored
|
@ -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
vendor/golang.org/x/oauth2/google/error.go
generated
vendored
Normal file
64
vendor/golang.org/x/oauth2/google/error.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
47
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
47
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
|
@ -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:
|
||||
|
|
76
vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go
generated
vendored
76
vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go
generated
vendored
|
@ -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
|
||||
}
|
||||
|
||||
if cs.region, err = cs.getRegion(); err != nil {
|
||||
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(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
|
||||
|
|
71
vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go
generated
vendored
71
vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go
generated
vendored
|
@ -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
vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go
generated
vendored
Normal file
309
vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go
generated
vendored
Normal file
|
@ -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())
|
||||
}
|
43
vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go
generated
vendored
43
vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go
generated
vendored
|
@ -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)
|
||||
|
|
3
vendor/golang.org/x/oauth2/google/jwt.go
generated
vendored
3
vendor/golang.org/x/oauth2/google/jwt.go
generated
vendored
|
@ -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 {
|
||||
|
|
2
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
2
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
|
@ -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)
|
||||
}
|
||||
|
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue