Skip to content

Commit 69cb240

Browse files
authored
feat(auth): refactor public sigs to use Credentials (#9603)
This refactors all public surfaces to use Credentials rather than TokenProvider as the main abstraction. Part 2 of 3 of breaking changes for the auth module.
1 parent 81281c0 commit 69cb240

33 files changed

+286
-197
lines changed

auth/credentials/doc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@
7474
//
7575
// # Credentials
7676
//
77-
// The [Credentials] type represents Google credentials, including Application
78-
// Default Credentials.
77+
// The [cloud.google.com/go/auth.Credentials] type represents Google
78+
// credentials, including Application Default Credentials.
7979
//
8080
// Use [DetectDefault] to obtain Application Default Credentials.
8181
//

auth/credentials/example_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func ExampleDetectDefault() {
3030
log.Fatal(err)
3131
}
3232
client, err := httptransport.NewClient(&httptransport.Options{
33-
TokenProvider: creds,
33+
Credentials: creds,
3434
})
3535
if err != nil {
3636
log.Fatal(err)
@@ -55,7 +55,7 @@ func ExampleDetectDefault_withFilepath() {
5555
log.Fatal(err)
5656
}
5757
client, err := httptransport.NewClient(&httptransport.Options{
58-
TokenProvider: creds,
58+
Credentials: creds,
5959
})
6060
if err != nil {
6161
log.Fatal(err)
@@ -76,7 +76,7 @@ func ExampleDetectDefault_withJSON() {
7676
log.Fatal(err)
7777
}
7878
client, err := httptransport.NewClient(&httptransport.Options{
79-
TokenProvider: creds,
79+
Credentials: creds,
8080
})
8181
if err != nil {
8282
log.Fatal(err)

auth/downscope/doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
// For example, a token broker can be set up on a server in a private network.
3434
// Various workloads (token consumers) in the same network will send
3535
// authenticated requests to that broker for downscoped tokens to access or
36-
// modify specific google cloud storage buckets. See the NewTokenProvider example
36+
// modify specific google cloud storage buckets. See the NewCredentials example
3737
// for an example of how a token broker would use this package.
3838
//
3939
// The broker will use the functionality in this package to generate a

auth/downscope/downscope.go

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ import (
2828

2929
var identityBindingEndpoint = "https://sts.googleapis.com/v1/token"
3030

31-
// Options for configuring [NewTokenProvider].
31+
// Options for configuring [NewCredentials].
3232
type Options struct {
33-
// BaseProvider is the [cloud.google.com/go/auth.TokenProvider] used to
34-
// create the downscoped provider. The downscoped provider therefore has
35-
// some subset of the accesses of the original BaseProvider. Required.
36-
BaseProvider auth.TokenProvider
37-
// Rules defines the accesses held by the new downscoped provider. One or
33+
// Credentials is the [cloud.google.com/go/auth.Credentials] used to
34+
// create the downscoped credentials. Required.
35+
Credentials *auth.Credentials
36+
// Rules defines the accesses held by the new downscoped credentials. One or
3837
// more AccessBoundaryRules are required to define permissions for the new
39-
// downscoped provider. Each one defines an access (or set of accesses) that
40-
// the new provider has to a given resource. There can be a maximum of 10
41-
// AccessBoundaryRules. Required.
38+
// downscoped credentials. Each one defines an access (or set of accesses)
39+
//that the new credentials has to a given resource. There can be a maximum
40+
// of 10 AccessBoundaryRules. Required.
4241
Rules []AccessBoundaryRule
4342
// Client configures the underlying client used to make network requests
4443
// when fetching tokens. Optional.
@@ -84,14 +83,15 @@ type AvailabilityCondition struct {
8483
Description string `json:"description,omitempty"`
8584
}
8685

87-
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider] that is
88-
// more restrictive than [Options.BaseProvider] provided.
89-
func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
86+
// NewCredentials returns a [cloud.google.com/go/auth.Credentials] that is
87+
// more restrictive than [Options.Credentials] provided. The new credentials
88+
// will delegate to the base credentials for all non-token activity.
89+
func NewCredentials(opts *Options) (*auth.Credentials, error) {
9090
if opts == nil {
9191
return nil, fmt.Errorf("downscope: providing opts is required")
9292
}
93-
if opts.BaseProvider == nil {
94-
return nil, fmt.Errorf("downscope: BaseProvider cannot be nil")
93+
if opts.Credentials == nil {
94+
return nil, fmt.Errorf("downscope: Credentials cannot be nil")
9595
}
9696
if len(opts.Rules) == 0 {
9797
return nil, fmt.Errorf("downscope: length of AccessBoundaryRules must be at least 1")
@@ -107,7 +107,12 @@ func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
107107
return nil, fmt.Errorf("downscope: all rules must provide at least one permission")
108108
}
109109
}
110-
return &downscopedTokenProvider{Options: opts, Client: opts.client()}, nil
110+
return auth.NewCredentials(&auth.CredentialsOptions{
111+
TokenProvider: &downscopedTokenProvider{Options: opts, Client: opts.client()},
112+
ProjectIDProvider: auth.CredentialsPropertyFunc(opts.Credentials.ProjectID),
113+
QuotaProjectIDProvider: auth.CredentialsPropertyFunc(opts.Credentials.QuotaProjectID),
114+
UniverseDomainProvider: auth.CredentialsPropertyFunc(opts.Credentials.UniverseDomain),
115+
}), nil
111116
}
112117

113118
// downscopedTokenProvider is used to retrieve a downscoped tokens.
@@ -138,7 +143,7 @@ func (dts *downscopedTokenProvider) Token(ctx context.Context) (*auth.Token, err
138143
},
139144
}
140145

141-
tok, err := dts.Options.BaseProvider.Token(ctx)
146+
tok, err := dts.Options.Credentials.Token(ctx)
142147
if err != nil {
143148
return nil, fmt.Errorf("downscope: unable to obtain root token: %w", err)
144149
}

auth/downscope/downscope_test.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ var (
2929
standardRespBody = `{"access_token":"fake_token","expires_in":42,"token_type":"Bearer"}`
3030
)
3131

32+
func staticCredentials(tok string) *auth.Credentials {
33+
return auth.NewCredentials(&auth.CredentialsOptions{
34+
TokenProvider: staticTokenProvider(tok),
35+
})
36+
}
37+
3238
type staticTokenProvider string
3339

3440
func (s staticTokenProvider) Token(context.Context) (*auth.Token, error) {
@@ -58,8 +64,8 @@ func TestNewTokenProvider(t *testing.T) {
5864
oldEndpoint := identityBindingEndpoint
5965
identityBindingEndpoint = ts.URL
6066
t.Cleanup(func() { identityBindingEndpoint = oldEndpoint })
61-
tp, err := NewTokenProvider(&Options{
62-
BaseProvider: staticTokenProvider("token_base"),
67+
creds, err := NewCredentials(&Options{
68+
Credentials: staticCredentials("token_base"),
6369
Rules: []AccessBoundaryRule{
6470
{
6571
AvailableResource: "test1",
@@ -70,16 +76,16 @@ func TestNewTokenProvider(t *testing.T) {
7076
if err != nil {
7177
t.Fatalf("NewTokenProvider() = %v", err)
7278
}
73-
tok, err := tp.Token(context.Background())
79+
tok, err := creds.Token(context.Background())
7480
if err != nil {
75-
t.Fatalf("NewDownscopedTokenSource failed with error: %v", err)
81+
t.Fatalf("Token failed with error: %v", err)
7682
}
7783
if want := "fake_token"; tok.Value != want {
7884
t.Fatalf("got %v, want %v", tok.Value, want)
7985
}
8086
}
8187

82-
func TestTestNewTokenProvider_Validations(t *testing.T) {
88+
func TestTestNewCredentials_Validations(t *testing.T) {
8389
tests := []struct {
8490
name string
8591
opts *Options
@@ -95,27 +101,27 @@ func TestTestNewTokenProvider_Validations(t *testing.T) {
95101
{
96102
name: "no rules",
97103
opts: &Options{
98-
BaseProvider: staticTokenProvider("token_base"),
104+
Credentials: staticCredentials("token_base"),
99105
},
100106
},
101107
{
102108
name: "too many rules",
103109
opts: &Options{
104-
BaseProvider: staticTokenProvider("token_base"),
105-
Rules: []AccessBoundaryRule{{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}},
110+
Credentials: staticCredentials("token_base"),
111+
Rules: []AccessBoundaryRule{{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}},
106112
},
107113
},
108114
{
109115
name: "no resource",
110116
opts: &Options{
111-
BaseProvider: staticTokenProvider("token_base"),
112-
Rules: []AccessBoundaryRule{{}},
117+
Credentials: staticCredentials("token_base"),
118+
Rules: []AccessBoundaryRule{{}},
113119
},
114120
},
115121
{
116122
name: "no perm",
117123
opts: &Options{
118-
BaseProvider: staticTokenProvider("token_base"),
124+
Credentials: staticCredentials("token_base"),
119125
Rules: []AccessBoundaryRule{{
120126
AvailableResource: "resource",
121127
}},
@@ -124,7 +130,7 @@ func TestTestNewTokenProvider_Validations(t *testing.T) {
124130
}
125131
for _, test := range tests {
126132
t.Run(test.name, func(t *testing.T) {
127-
if _, err := NewTokenProvider(test.opts); err == nil {
133+
if _, err := NewCredentials(test.opts); err == nil {
128134
t.Fatal("want non-nil err")
129135
}
130136
})

auth/downscope/example_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"cloud.google.com/go/auth/downscope"
2323
)
2424

25-
func ExampleNewTokenProvider() {
25+
func ExampleNewCredentials() {
2626
// This shows how to generate a downscoped token. This code would be run on
2727
// the token broker, which holds the root token used to generate the
2828
// downscoped token.
@@ -43,13 +43,13 @@ func ExampleNewTokenProvider() {
4343
baseProvider, err := credentials.DetectDefault(&credentials.DetectOptions{
4444
Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
4545
})
46-
tp, err := downscope.NewTokenProvider(&downscope.Options{BaseProvider: baseProvider, Rules: accessBoundary})
46+
creds, err := downscope.NewCredentials(&downscope.Options{Credentials: baseProvider, Rules: accessBoundary})
4747
if err != nil {
4848
fmt.Printf("failed to generate downscoped token provider: %v", err)
4949
return
5050
}
5151

52-
tok, err := tp.Token(ctx)
52+
tok, err := creds.Token(ctx)
5353
if err != nil {
5454
fmt.Printf("failed to generate token: %v", err)
5555
return

auth/downscope/integration_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,17 @@ func TestDownscopedToken(t *testing.T) {
9191
}
9292
}
9393

94-
func testDownscopedToken(t *testing.T, rule downscope.AccessBoundaryRule, objectName string, tp auth.TokenProvider) error {
94+
func testDownscopedToken(t *testing.T, rule downscope.AccessBoundaryRule, objectName string, creds *auth.Credentials) error {
9595
t.Helper()
9696
ctx := context.Background()
97-
tp, err := downscope.NewTokenProvider(&downscope.Options{BaseProvider: tp, Rules: []downscope.AccessBoundaryRule{rule}})
97+
creds, err := downscope.NewCredentials(&downscope.Options{Credentials: creds, Rules: []downscope.AccessBoundaryRule{rule}})
9898
if err != nil {
99-
return fmt.Errorf("downscope.NewTokenProvider() = %v", err)
99+
return fmt.Errorf("downscope.NewCredentials() = %v", err)
100100
}
101101

102102
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
103103
defer cancel()
104-
client := testgcs.NewClient(tp)
104+
client := testgcs.NewClient(creds)
105105
resp, err := client.DownloadObject(ctx, bucket, objectName)
106106
if err != nil {
107107
return err

auth/example_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ func ExampleNew2LOTokenProvider() {
5353
log.Fatal(err)
5454
}
5555
client, err := httptransport.NewClient(&httptransport.Options{
56-
TokenProvider: tp,
56+
Credentials: auth.NewCredentials(&auth.CredentialsOptions{
57+
TokenProvider: tp,
58+
}),
5759
})
5860
if err != nil {
5961
log.Fatal(err)

auth/grpctransport/dial_socketopt_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"testing"
2727
"time"
2828

29+
"cloud.google.com/go/auth"
2930
"google.golang.org/grpc"
3031
)
3132

@@ -107,9 +108,11 @@ func TestDialWithDirectPathEnabled(t *testing.T) {
107108
})
108109

109110
pool, err := Dial(ctx, true, &Options{
110-
TokenProvider: staticTP("hey"),
111-
GRPCDialOpts: []grpc.DialOption{userDialer},
112-
Endpoint: "example.google.com:443",
111+
Credentials: auth.NewCredentials(&auth.CredentialsOptions{
112+
TokenProvider: staticTP("hey"),
113+
}),
114+
GRPCDialOpts: []grpc.DialOption{userDialer},
115+
Endpoint: "example.google.com:443",
113116
InternalOptions: &InternalOptions{
114117
EnableDirectPath: true,
115118
},

auth/grpctransport/directpath.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ func isDirectPathXdsUsed(o *Options) bool {
9090
// configureDirectPath returns some dial options and an endpoint to use if the
9191
// configuration allows the use of direct path. If it does not the provided
9292
// grpcOpts and endpoint are returned.
93-
func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds auth.TokenProvider) ([]grpc.DialOption, string) {
93+
func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds *auth.Credentials) ([]grpc.DialOption, string) {
9494
if isDirectPathEnabled(endpoint, opts) && metadata.OnGCE() && isTokenProviderDirectPathCompatible(creds, opts) {
9595
// Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
9696
grpcOpts = []grpc.DialOption{
97-
grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcTokenProvider{TokenProvider: creds}}))}
97+
grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcCredentialsProvider{creds: creds}}))}
9898
if timeoutDialerOption != nil {
9999
grpcOpts = append(grpcOpts, timeoutDialerOption)
100100
}

auth/grpctransport/grpctransport.go

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ type Options struct {
6565
// PoolSize is specifies how many connections to balance between when making
6666
// requests. If unset or less than 1, the value defaults to 1.
6767
PoolSize int
68-
// TokenProvider specifies the provider used to add Authorization metadata
69-
// to all requests. If set DetectOpts are ignored.
70-
TokenProvider auth.TokenProvider
68+
// Credentials used to add Authorization metadata to all requests. If set
69+
// DetectOpts are ignored.
70+
Credentials *auth.Credentials
7171
// DetectOpts configures settings for detect Application Default
7272
// Credentials.
7373
DetectOpts *credentials.DetectOptions
@@ -90,7 +90,7 @@ func (o *Options) validate() error {
9090
if o == nil {
9191
return errors.New("grpctransport: opts required to be non-nil")
9292
}
93-
hasCreds := o.TokenProvider != nil ||
93+
hasCreds := o.Credentials != nil ||
9494
(o.DetectOpts != nil && len(o.DetectOpts.CredentialsJSON) > 0) ||
9595
(o.DetectOpts != nil && o.DetectOpts.CredentialsFile != "")
9696
if o.DisableAuthentication && hasCreds {
@@ -204,9 +204,8 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
204204
if err != nil {
205205
return nil, err
206206
}
207-
var tp auth.TokenProvider = creds
208-
if opts.TokenProvider != nil {
209-
tp = opts.TokenProvider
207+
if opts.Credentials != nil {
208+
creds = opts.Credentials
210209
}
211210

212211
qp, err := creds.QuotaProjectID(ctx)
@@ -221,9 +220,9 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
221220
}
222221

223222
grpcOpts = append(grpcOpts,
224-
grpc.WithPerRPCCredentials(&grpcTokenProvider{
225-
TokenProvider: tp,
226-
metadata: metadata,
223+
grpc.WithPerRPCCredentials(&grpcCredentialsProvider{
224+
creds: creds,
225+
metadata: metadata,
227226
}),
228227
)
229228

@@ -240,37 +239,37 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
240239
return grpc.DialContext(ctx, endpoint, grpcOpts...)
241240
}
242241

243-
// grpcTokenProvider satisfies https://pkg.go.dev/google.golang.org/grpc/credentials#PerRPCCredentials.
244-
type grpcTokenProvider struct {
245-
auth.TokenProvider
242+
// grpcCredentialsProvider satisfies https://pkg.go.dev/google.golang.org/grpc/credentials#PerRPCCredentials.
243+
type grpcCredentialsProvider struct {
244+
creds *auth.Credentials
246245

247246
secure bool
248247

249248
// Additional metadata attached as headers.
250249
metadata map[string]string
251250
}
252251

253-
func (tp *grpcTokenProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
254-
token, err := tp.Token(ctx)
252+
func (c *grpcCredentialsProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
253+
token, err := c.creds.Token(ctx)
255254
if err != nil {
256255
return nil, err
257256
}
258-
if tp.secure {
257+
if c.secure {
259258
ri, _ := grpccreds.RequestInfoFromContext(ctx)
260259
if err = grpccreds.CheckSecurityLevel(ri.AuthInfo, grpccreds.PrivacyAndIntegrity); err != nil {
261-
return nil, fmt.Errorf("unable to transfer TokenProvider PerRPCCredentials: %v", err)
260+
return nil, fmt.Errorf("unable to transfer credentials PerRPCCredentials: %v", err)
262261
}
263262
}
264263
metadata := map[string]string{
265264
"authorization": token.Type + " " + token.Value,
266265
}
267-
for k, v := range tp.metadata {
266+
for k, v := range c.metadata {
268267
metadata[k] = v
269268
}
270269
return metadata, nil
271270
}
272271

273-
func (tp *grpcTokenProvider) RequireTransportSecurity() bool {
272+
func (tp *grpcCredentialsProvider) RequireTransportSecurity() bool {
274273
return tp.secure
275274
}
276275

0 commit comments

Comments
 (0)