Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(auth): add UniverseDomain to DetectOptions #9536

Merged
merged 22 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cf7d274
feat(auth): add UniverseDomain to detect.Options
quartzmo Mar 8, 2024
48cc4db
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 8, 2024
97b1f3b
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 11, 2024
2b6d1a3
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 13, 2024
8296501
Add detect.Credentials.ValidateUniverseDomain (WIP)
quartzmo Mar 14, 2024
53f3584
update usages of NewCachedTokenProvider
quartzmo Mar 15, 2024
2b1138b
update for latest 9590 and move validateUniverseDomain to transport l…
quartzmo Mar 15, 2024
96cb77b
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 15, 2024
16de789
fixed tests
quartzmo Mar 15, 2024
b7b264b
use sync.Once in computeUniverseDomainProvider
quartzmo Mar 18, 2024
e821843
move transport checks to transport.ValidateUniverseDomain
quartzmo Mar 18, 2024
482f20b
refactorings for remaining TODOs
quartzmo Mar 18, 2024
51e8871
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 18, 2024
aef1cf1
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 19, 2024
9c8bc92
remove creds init from AddAuthorizationMiddleware
quartzmo Mar 19, 2024
f243b45
move ComputeUniverseDomainProvider to internal for shared use
quartzmo Mar 19, 2024
8b5567a
move getClientUniverseDomain methods to CredentialsProviders
quartzmo Mar 19, 2024
64b38a4
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 20, 2024
4927d22
fix golint
quartzmo Mar 20, 2024
daed0bd
fix mismatch error message and refactor filetypes logic
quartzmo Mar 20, 2024
4d779b6
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 20, 2024
cdf1303
Merge branch 'main' into auth-universe-domain-2
quartzmo Mar 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions auth/detect/compute.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"time"
Expand Down Expand Up @@ -82,4 +83,23 @@ func (cs computeProvider) Token(ctx context.Context) (*auth.Token, error) {
Metadata: computeTokenMetadata,
}, nil

} // computeProvider fetches tokens from the google cloud metadata service.
type computeUniverseDomainProvider struct {
// TODO(chridsmith): memoize universe domain (with mutex)
quartzmo marked this conversation as resolved.
Show resolved Hide resolved
}

func (cudp computeUniverseDomainProvider) UniverseDomain(ctx context.Context) (string, error) {
var err error
c := metadata.NewClient(&http.Client{Timeout: time.Second})
// TODO(chridsmith): set ctx on request
ud, err := c.Get("universe/universe_domain")
if err == nil {
return ud, nil
}
if _, ok := err.(metadata.NotDefinedError); ok {
// http.StatusNotFound (404)
return defaultUniverseDomain, nil
} else {
return "", err
}
}
48 changes: 47 additions & 1 deletion auth/detect/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package detect

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -54,11 +55,30 @@ type Credentials struct {
projectID string
quotaProjectID string
// universeDomain is the default service domain for a given Cloud universe.
// The source may be from user configuration (Options.UniverseDomain) or
// from a credentials file. User configuration takes precedence. See
// fileCredentials. Not set from file in the case of compute (GCE),
// therefore udp (below) is typically used instead. Optional.
universeDomain string
// udp, if provided, can fetch a universe domain value if universeDomain
// (above) is blank, which is typically the case for compute (GCE)
// credentials. Optional.
udp universeDomainProvider

auth.TokenProvider
}

// universeDomainProvider fetches a universe domain value. Typically used with
// compute (GCE) credentials. Think of it as a promise for resolving the
// universe domain.
type universeDomainProvider interface {
// UniverseDomain returns a universe domain or an error. It does not return
// an empty string. It may return the default value "googleapis.com".
// The context provided must be sent along to any requests that are made in
// the implementing code.
UniverseDomain(context.Context) (string, error)
}

func newCredentials(tokenProvider auth.TokenProvider, json []byte, projectID string, quotaProjectID string, universeDomain string) *Credentials {
return &Credentials{
json: json,
Expand Down Expand Up @@ -96,6 +116,30 @@ func (c *Credentials) UniverseDomain() string {
return c.universeDomain
}

// ValidateUniverseDomain verifies TODO(chridsmith): doc
func (c *Credentials) ValidateUniverseDomain(ctx context.Context, clientUniverseDomain string) error {
quartzmo marked this conversation as resolved.
Show resolved Hide resolved
ud := defaultUniverseDomain
if c.universeDomain != "" {
ud = c.universeDomain
}
if c.udp != nil {
var err error
ud, err = c.udp.UniverseDomain(ctx)
if err != nil {
return err
}
}
if clientUniverseDomain != ud {
return fmt.Errorf(
"the configured universe domain (%q) does not match the universe "+
"domain found in the credentials (%q). If you haven't configured "+
"WithUniverseDomain explicitly, \"googleapis.com\" is the default",
clientUniverseDomain,
ud)
}
return nil
}

// OnGCE reports whether this process is running in Google Cloud.
func OnGCE() bool {
// TODO(codyoss): once all libs use this auth lib move metadata check here
Expand Down Expand Up @@ -139,7 +183,9 @@ func DefaultCredentials(opts *Options) (*Credentials, error) {

if OnGCE() {
id, _ := metadata.ProjectID()
return newCredentials(computeTokenProvider(opts.EarlyTokenRefresh, opts.Scopes...), nil, id, "", opts.UniverseDomain), nil
creds := newCredentials(computeTokenProvider(opts.EarlyTokenRefresh, opts.Scopes...), nil, id, "", opts.UniverseDomain)
creds.udp = &computeUniverseDomainProvider{}
return creds, nil
}

return nil, fmt.Errorf("detect: could not find default credentials. See %v for more information", adcSetupURL)
Expand Down
5 changes: 3 additions & 2 deletions auth/grpctransport/directpath.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"

"cloud.google.com/go/auth"
"cloud.google.com/go/auth/detect"
"cloud.google.com/go/compute/metadata"
"google.golang.org/grpc"
grpcgoogle "google.golang.org/grpc/credentials/google"
Expand Down Expand Up @@ -90,11 +91,11 @@ func isDirectPathXdsUsed(o *Options) bool {
// configureDirectPath returns some dial options and an endpoint to use if the
// configuration allows the use of direct path. If it does not the provided
// grpcOpts and endpoint are returned.
func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds auth.TokenProvider) ([]grpc.DialOption, string) {
func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds *detect.Credentials) ([]grpc.DialOption, string) {
if isDirectPathEnabled(endpoint, opts) && metadata.OnGCE() && isTokenProviderDirectPathCompatible(creds, opts) {
// Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
grpcOpts = []grpc.DialOption{
grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcTokenProvider{TokenProvider: creds}}))}
grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcTokenProvider{creds: creds}}))}
if timeoutDialerOption != nil {
grpcOpts = append(grpcOpts, timeoutDialerOption)
}
Expand Down
22 changes: 15 additions & 7 deletions auth/grpctransport/grpctransport.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ type Options struct {
// DetectOpts configures settings for detect Application Default
// Credentials.
DetectOpts *detect.Options
// UniverseDomain is the default service domain for a given Cloud universe.
// The default value is "googleapis.com". This is the universe domain
quartzmo marked this conversation as resolved.
Show resolved Hide resolved
// provided via client options.
UniverseDomain string

// InternalOptions are NOT meant to be set directly by consumers of this
// package, they should only be set by generated client code.
Expand Down Expand Up @@ -204,9 +208,8 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
if err != nil {
return nil, err
}
var tp auth.TokenProvider = creds
if opts.TokenProvider != nil {
tp = opts.TokenProvider
creds.TokenProvider = opts.TokenProvider // TODO(chrisdsmith): Is this OK? Are creds non-nil and suitable for WithTokenProvider? Or is new Credentials needed?
}

qp := creds.QuotaProjectID()
Expand All @@ -219,8 +222,9 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er

grpcOpts = append(grpcOpts,
grpc.WithPerRPCCredentials(&grpcTokenProvider{
TokenProvider: tp,
metadata: metadata,
creds: creds,
metadata: metadata,
clientUniverseDomain: opts.UniverseDomain,
}),
)

Expand All @@ -239,16 +243,20 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er

// grpcTokenProvider satisfies https://pkg.go.dev/google.golang.org/grpc/credentials#PerRPCCredentials.
type grpcTokenProvider struct {
auth.TokenProvider
creds *detect.Credentials // TODO(chrisdsmith): convert usages of TokenProvider to creds

secure bool

// Additional metadata attached as headers.
metadata map[string]string
metadata map[string]string
clientUniverseDomain string
}

func (tp *grpcTokenProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
token, err := tp.Token(ctx)
if err := tp.creds.ValidateUniverseDomain(ctx, tp.clientUniverseDomain); err != nil {
quartzmo marked this conversation as resolved.
Show resolved Hide resolved
return nil, err
}
token, err := tp.creds.Token(ctx)
if err != nil {
return nil, err
}
Expand Down
6 changes: 5 additions & 1 deletion auth/httptransport/httptransport.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ type Options struct {
// DetectOpts configures settings for detect Application Default
// Credentials.
DetectOpts *detect.Options
// UniverseDomain is the default service domain for a given Cloud universe.
// The default value is "googleapis.com". This is the universe domain
// provided via client options.
UniverseDomain string

// InternalOptions are NOT meant to be set directly by consumers of this
// package, they should only be set by generated client code.
Expand Down Expand Up @@ -140,7 +144,7 @@ func AddAuthorizationMiddleware(client *http.Client, tp auth.TokenProvider) erro
base = http.DefaultTransport.(*http.Transport).Clone()
}
client.Transport = &authTransport{
provider: auth.NewCachedTokenProvider(tp, nil),
creds: auth.NewCachedTokenProvider(tp, nil),
base: base,
}
return nil
Expand Down
19 changes: 12 additions & 7 deletions auth/httptransport/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,14 @@ func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, err
headers.Set(quotaProjectHeaderKey, qp)
}

var tp auth.TokenProvider = creds
if opts.TokenProvider != nil {
tp = opts.TokenProvider
creds.TokenProvider = opts.TokenProvider
}
creds.TokenProvider = auth.NewCachedTokenProvider(creds.TokenProvider, nil)
trans = &authTransport{
base: trans,
provider: auth.NewCachedTokenProvider(tp, nil),
base: trans,
creds: creds,
clientUniverseDomain: opts.UniverseDomain,
}
}
return trans, nil
Expand Down Expand Up @@ -159,8 +160,9 @@ func addOCTransport(trans http.RoundTripper, opts *Options) http.RoundTripper {
}

type authTransport struct {
provider auth.TokenProvider
base http.RoundTripper
creds *detect.Credentials // TODO(chrisdsmith): convert usages of TokenProvider to creds
base http.RoundTripper
clientUniverseDomain string
}

// RoundTrip authorizes and authenticates the request with an
Expand All @@ -176,7 +178,10 @@ func (t *authTransport) RoundTrip(req *http.Request) (*http.Response, error) {
}
}()
}
token, err := t.provider.Token(req.Context())
if err := t.creds.ValidateUniverseDomain(req.Context(), t.clientUniverseDomain); err != nil {
return nil, err
}
token, err := t.creds.Token(req.Context())
if err != nil {
return nil, err
}
Expand Down
Loading