diff --git a/google/default.go b/google/default.go index 02ccd08a7..18f369851 100644 --- a/google/default.go +++ b/google/default.go @@ -22,7 +22,7 @@ import ( const ( adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc" - universeDomainDefault = "googleapis.com" + defaultUniverseDomain = "googleapis.com" ) // Credentials holds Google credentials, including "Application Default Credentials". @@ -58,7 +58,7 @@ type Credentials struct { // See also [The attached service account](https://cloud.google.com/docs/authentication/application-default-credentials#attached-sa). func (c *Credentials) UniverseDomain() string { if c.universeDomain == "" { - return universeDomainDefault + return defaultUniverseDomain } return c.universeDomain } @@ -89,7 +89,7 @@ func (c *Credentials) GetUniverseDomain() (string, error) { // computeUniverseDomain that did not set universeDomain, set the default // universe domain. if c.universeDomain == "" { - c.universeDomain = universeDomainDefault + c.universeDomain = defaultUniverseDomain } return c.universeDomain, nil } @@ -103,7 +103,7 @@ func (c *Credentials) computeUniverseDomain() error { if err != nil { if _, ok := err.(metadata.NotDefinedError); ok { // http.StatusNotFound (404) - c.universeDomain = universeDomainDefault + c.universeDomain = defaultUniverseDomain return nil } else { return err @@ -287,7 +287,7 @@ func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params } // Authorized user credentials are only supported in the googleapis.com universe. if f.Type == userCredentialsKey { - universeDomain = universeDomainDefault + universeDomain = defaultUniverseDomain } ts, err := f.tokenSource(ctx, params) diff --git a/google/downscope/downscoping.go b/google/downscope/downscoping.go index ca1f35462..ebe8b0509 100644 --- a/google/downscope/downscoping.go +++ b/google/downscope/downscoping.go @@ -51,7 +51,7 @@ import ( const ( universeDomainPlaceholder = "UNIVERSE_DOMAIN" identityBindingEndpointTemplate = "https://sts.UNIVERSE_DOMAIN/v1/token" - universeDomainDefault = "googleapis.com" + defaultUniverseDomain = "googleapis.com" ) type accessBoundary struct { @@ -117,7 +117,7 @@ type DownscopingConfig struct { // configured universe domain. func (dc *DownscopingConfig) identityBindingEndpoint() string { if dc.UniverseDomain == "" { - return strings.Replace(identityBindingEndpointTemplate, universeDomainPlaceholder, universeDomainDefault, 1) + return strings.Replace(identityBindingEndpointTemplate, universeDomainPlaceholder, defaultUniverseDomain, 1) } return strings.Replace(identityBindingEndpointTemplate, universeDomainPlaceholder, dc.UniverseDomain, 1) } diff --git a/google/externalaccount/basecredentials.go b/google/externalaccount/basecredentials.go index 71342e42b..400aa0a07 100644 --- a/google/externalaccount/basecredentials.go +++ b/google/externalaccount/basecredentials.go @@ -113,6 +113,7 @@ import ( "net/http" "regexp" "strconv" + "strings" "time" "golang.org/x/oauth2" @@ -120,6 +121,12 @@ import ( "golang.org/x/oauth2/google/internal/stsexchange" ) +const ( + universeDomainPlaceholder = "UNIVERSE_DOMAIN" + defaultTokenURL = "https://sts.UNIVERSE_DOMAIN/v1/token" + defaultUniverseDomain = "googleapis.com" +) + // now aliases time.Now for testing var now = func() time.Time { return time.Now().UTC() @@ -139,7 +146,9 @@ type Config struct { // Required. SubjectTokenType string // TokenURL is the STS token exchange endpoint. If not provided, will default to - // https://sts.googleapis.com/v1/token. Optional. + // https://sts.UNIVERSE_DOMAIN/v1/token, with UNIVERSE_DOMAIN set to the + // default service domain googleapis.com unless UniverseDomain is set. + // Optional. TokenURL string // TokenInfoURL is the token_info endpoint used to retrieve the account related information ( // user attributes like account identifier, eg. email, username, uid, etc). This is @@ -177,6 +186,10 @@ type Config struct { // AwsSecurityCredentialsSupplier is an AWS Security Credential supplier for AWS credentials. // One of SubjectTokenSupplier, AWSSecurityCredentialSupplier or CredentialSource must be provided. Optional. AwsSecurityCredentialsSupplier AwsSecurityCredentialsSupplier + // UniverseDomain is the default service domain for a given Cloud universe. + // This value will be used in the default STS token URL. The default value + // is "googleapis.com". It will not be used if TokenURL is set. Optional. + UniverseDomain string } var ( @@ -246,9 +259,8 @@ func (c *Config) tokenSource(ctx context.Context, scheme string) (oauth2.TokenSo // Subject token file types. const ( - fileTypeText = "text" - fileTypeJSON = "json" - defaultTokenUrl = "https://sts.googleapis.com/v1/token" + fileTypeText = "text" + fileTypeJSON = "json" ) // Format contains information needed to retireve a subject token for URL or File sourced credentials. @@ -336,11 +348,20 @@ type SupplierOptions struct { SubjectTokenType string } +// tokenURL returns the default STS token endpoint with the configured universe +// domain. +func (c *Config) tokenURL() string { + if c.UniverseDomain == "" { + return strings.Replace(defaultTokenURL, universeDomainPlaceholder, defaultUniverseDomain, 1) + } + return strings.Replace(defaultTokenURL, universeDomainPlaceholder, c.UniverseDomain, 1) +} + // parse determines the type of CredentialSource needed. func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) { //set Defaults if c.TokenURL == "" { - c.TokenURL = defaultTokenUrl + c.TokenURL = c.tokenURL() } supplierOptions := SupplierOptions{Audience: c.Audience, SubjectTokenType: c.SubjectTokenType} diff --git a/google/externalaccount/basecredentials_test.go b/google/externalaccount/basecredentials_test.go index 5e896eed0..33314c3f0 100644 --- a/google/externalaccount/basecredentials_test.go +++ b/google/externalaccount/basecredentials_test.go @@ -454,3 +454,46 @@ func TestNewToken(t *testing.T) { }) } } + +func TestConfig_TokenURL(t *testing.T) { + tests := []struct { + tokenURL string + universeDomain string + want string + }{ + { + tokenURL: "https://sts.googleapis.com/v1/token", + universeDomain: "", + want: "https://sts.googleapis.com/v1/token", + }, + { + tokenURL: "", + universeDomain: "", + want: "https://sts.googleapis.com/v1/token", + }, + { + tokenURL: "", + universeDomain: "googleapis.com", + want: "https://sts.googleapis.com/v1/token", + }, + { + tokenURL: "", + universeDomain: "example.com", + want: "https://sts.example.com/v1/token", + }, + } + for _, tt := range tests { + config := &Config{ + Audience: "//iam.googleapis.com/locations/eu/workforcePools/pool-id/providers/provider-id", + SubjectTokenType: "urn:ietf:params:oauth:token-type:id_token", + CredentialSource: &testBaseCredSource, + Scopes: []string{"https://www.googleapis.com/auth/devstorage.full_control"}, + } + config.TokenURL = tt.tokenURL + config.UniverseDomain = tt.universeDomain + config.parse(context.Background()) + if got := config.TokenURL; got != tt.want { + t.Errorf("got %q, want %q", got, tt.want) + } + } +}