google/externalaccount: add Config.UniverseDomain
Change-Id: Ia1caee246da68c01addd06e1367ed1e43645826b
Reviewed-on: https://go-review.googlesource.com/c/oauth2/+/568216
Reviewed-by: Alex Eitzman <eitzman@google.com>
Reviewed-by: Cody Oss <codyoss@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/google/default.go b/google/default.go
index 02ccd08..18f3698 100644
--- a/google/default.go
+++ b/google/default.go
@@ -22,7 +22,7 @@
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 @@
// 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 @@
// 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 @@
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 @@
}
// 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 ca1f354..ebe8b05 100644
--- a/google/downscope/downscoping.go
+++ b/google/downscope/downscoping.go
@@ -51,7 +51,7 @@
const (
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
identityBindingEndpointTemplate = "https://sts.UNIVERSE_DOMAIN/v1/token"
- universeDomainDefault = "googleapis.com"
+ defaultUniverseDomain = "googleapis.com"
)
type accessBoundary struct {
@@ -117,7 +117,7 @@
// 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 71342e4..400aa0a 100644
--- a/google/externalaccount/basecredentials.go
+++ b/google/externalaccount/basecredentials.go
@@ -113,6 +113,7 @@
"net/http"
"regexp"
"strconv"
+ "strings"
"time"
"golang.org/x/oauth2"
@@ -120,6 +121,12 @@
"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 @@
// 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 @@
// 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 @@
// 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 @@
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 5e896ee..33314c3 100644
--- a/google/externalaccount/basecredentials_test.go
+++ b/google/externalaccount/basecredentials_test.go
@@ -454,3 +454,46 @@
})
}
}
+
+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)
+ }
+ }
+}