Skip to content

Commit

Permalink
Merge branch 'main' into owl-bot-copy
Browse files Browse the repository at this point in the history
  • Loading branch information
codyoss authored Oct 29, 2024
2 parents beff330 + 255c6bf commit 8fcf023
Show file tree
Hide file tree
Showing 11 changed files with 346 additions and 230 deletions.
102 changes: 51 additions & 51 deletions auth/credentials/impersonate/impersonate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"time"

"cloud.google.com/go/auth"
Expand All @@ -30,11 +31,13 @@ import (
)

var (
iamCredentialsEndpoint = "https://iamcredentials.googleapis.com"
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
iamCredentialsEndpoint = "https://iamcredentials.UNIVERSE_DOMAIN"
oauth2Endpoint = "https://oauth2.googleapis.com"
errMissingTargetPrincipal = errors.New("impersonate: target service account must be provided")
errMissingScopes = errors.New("impersonate: scopes must be provided")
errLifetimeOverMax = errors.New("impersonate: max lifetime is 12 hours")
errClientAndCredentials = errors.New("impersonate: client and credentials must not both be provided")
errUniverseNotSupportedDomainWideDelegation = errors.New("impersonate: service account user is configured for the credential. " +
"Domain-wide delegation is not supported in universes other than googleapis.com")
)
Expand Down Expand Up @@ -62,55 +65,49 @@ func NewCredentials(opts *CredentialsOptions) (*auth.Credentials, error) {

var client *http.Client
var creds *auth.Credentials
if opts.Client == nil && opts.Credentials == nil {
if opts.Client == nil {
var err error
creds, err = credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{defaultScope},
UseSelfSignedJWT: true,
})
if err != nil {
return nil, err
if opts.Credentials == nil {
creds, err = credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{defaultScope},
UseSelfSignedJWT: true,
})
if err != nil {
return nil, err
}
} else {
creds = opts.Credentials
}
client, err = httptransport.NewClient(&httptransport.Options{
Credentials: creds,
Credentials: creds,
UniverseDomain: opts.UniverseDomain,
})
if err != nil {
return nil, err
}
} else if opts.Credentials != nil {
creds = opts.Credentials
client = internal.DefaultClient()
if err := httptransport.AddAuthorizationMiddleware(client, opts.Credentials); err != nil {
return nil, err
}
} else {
client = opts.Client
}

universeDomainProvider := resolveUniverseDomainProvider(creds)
// If a subject is specified a domain-wide delegation auth-flow is initiated
// to impersonate as the provided subject (user).
if opts.Subject != "" {
if !opts.isUniverseDomainGDU() {
return nil, errUniverseNotSupportedDomainWideDelegation
}
tp, err := user(opts, client, lifetime, isStaticToken)
tp, err := user(opts, client, lifetime, isStaticToken, universeDomainProvider)
if err != nil {
return nil, err
}
var udp auth.CredentialsPropertyProvider
if creds != nil {
udp = auth.CredentialsPropertyFunc(creds.UniverseDomain)
}
return auth.NewCredentials(&auth.CredentialsOptions{
TokenProvider: tp,
UniverseDomainProvider: udp,
UniverseDomainProvider: universeDomainProvider,
}), nil
}

its := impersonatedTokenProvider{
client: client,
targetPrincipal: opts.TargetPrincipal,
lifetime: fmt.Sprintf("%.fs", lifetime.Seconds()),
client: client,
targetPrincipal: opts.TargetPrincipal,
lifetime: fmt.Sprintf("%.fs", lifetime.Seconds()),
universeDomainProvider: universeDomainProvider,
}
for _, v := range opts.Delegates {
its.delegates = append(its.delegates, formatIAMServiceAccountName(v))
Expand All @@ -125,16 +122,23 @@ func NewCredentials(opts *CredentialsOptions) (*auth.Credentials, error) {
}
}

var udp auth.CredentialsPropertyProvider
if creds != nil {
udp = auth.CredentialsPropertyFunc(creds.UniverseDomain)
}
return auth.NewCredentials(&auth.CredentialsOptions{
TokenProvider: auth.NewCachedTokenProvider(its, tpo),
UniverseDomainProvider: udp,
UniverseDomainProvider: universeDomainProvider,
}), nil
}

// resolveUniverseDomainProvider returns the default service domain for a given
// Cloud universe. This is the universe domain configured for the credentials,
// which will be used in endpoint(s), and compared to the universe domain that
// is separately configured for the client.
func resolveUniverseDomainProvider(creds *auth.Credentials) auth.CredentialsPropertyProvider {
if creds != nil {
return auth.CredentialsPropertyFunc(creds.UniverseDomain)
}
return internal.StaticCredentialsProperty(internal.DefaultUniverseDomain)
}

// CredentialsOptions for generating an impersonated credential token.
type CredentialsOptions struct {
// TargetPrincipal is the email address of the service account to
Expand Down Expand Up @@ -163,11 +167,13 @@ type CredentialsOptions struct {
// will try to be detected from the environment. Optional.
Credentials *auth.Credentials
// Client configures the underlying client used to make network requests
// when fetching tokens. If provided the client should provide it's own
// when fetching tokens. If provided the client should provide its own
// credentials at call time. Optional.
Client *http.Client
// UniverseDomain is the default service domain for a given Cloud universe.
// The default value is "googleapis.com". Optional.
// The default value is "googleapis.com". This is the universe domain
// configured for the client, which will be compared to the universe domain
// that is separately configured for the credentials. Optional.
UniverseDomain string
}

Expand All @@ -184,22 +190,10 @@ func (o *CredentialsOptions) validate() error {
if o.Lifetime.Hours() > 12 {
return errLifetimeOverMax
}
return nil
}

// getUniverseDomain is the default service domain for a given Cloud universe.
// The default value is "googleapis.com".
func (o *CredentialsOptions) getUniverseDomain() string {
if o.UniverseDomain == "" {
return internal.DefaultUniverseDomain
if o.Client != nil && o.Credentials != nil {
return errClientAndCredentials
}
return o.UniverseDomain
}

// isUniverseDomainGDU returns true if the universe domain is the default Google
// universe.
func (o *CredentialsOptions) isUniverseDomainGDU() bool {
return o.getUniverseDomain() == internal.DefaultUniverseDomain
return nil
}

func formatIAMServiceAccountName(name string) string {
Expand All @@ -218,7 +212,8 @@ type generateAccessTokenResponse struct {
}

type impersonatedTokenProvider struct {
client *http.Client
client *http.Client
universeDomainProvider auth.CredentialsPropertyProvider

targetPrincipal string
lifetime string
Expand All @@ -237,7 +232,12 @@ func (i impersonatedTokenProvider) Token(ctx context.Context) (*auth.Token, erro
if err != nil {
return nil, fmt.Errorf("impersonate: unable to marshal request: %w", err)
}
url := fmt.Sprintf("%s/v1/%s:generateAccessToken", iamCredentialsEndpoint, formatIAMServiceAccountName(i.targetPrincipal))
universeDomain, err := i.universeDomainProvider.GetProperty(ctx)
if err != nil {
return nil, err
}
endpoint := strings.Replace(iamCredentialsEndpoint, universeDomainPlaceholder, universeDomain, 1)
url := fmt.Sprintf("%s/v1/%s:generateAccessToken", endpoint, formatIAMServiceAccountName(i.targetPrincipal))
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(b))
if err != nil {
return nil, fmt.Errorf("impersonate: unable to create request: %w", err)
Expand Down
Loading

0 comments on commit 8fcf023

Please sign in to comment.