diff --git a/storage/bucket.go b/storage/bucket.go index 5601357c9b2b..4183187213f9 100644 --- a/storage/bucket.go +++ b/storage/bucket.go @@ -200,11 +200,11 @@ func (b *BucketHandle) SignedURL(object string, opts *SignedURLOptions) (string, newopts.GoogleAccessID = id } if newopts.SignBytes == nil && len(newopts.PrivateKey) == 0 { - if b.c.creds != nil && len(b.c.creds.JSON) > 0 { + if j := b.c.credsJSON(); len(j) > 0 { var sa struct { PrivateKey string `json:"private_key"` } - err := json.Unmarshal(b.c.creds.JSON, &sa) + err := json.Unmarshal(j, &sa) if err == nil && sa.PrivateKey != "" { newopts.PrivateKey = []byte(sa.PrivateKey) } @@ -248,11 +248,11 @@ func (b *BucketHandle) GenerateSignedPostPolicyV4(object string, opts *PostPolic newopts.GoogleAccessID = id } if newopts.SignBytes == nil && newopts.SignRawBytes == nil && len(newopts.PrivateKey) == 0 { - if b.c.creds != nil && len(b.c.creds.JSON) > 0 { + if j := b.c.credsJSON(); len(j) > 0 { var sa struct { PrivateKey string `json:"private_key"` } - err := json.Unmarshal(b.c.creds.JSON, &sa) + err := json.Unmarshal(j, &sa) if err == nil && sa.PrivateKey != "" { newopts.PrivateKey = []byte(sa.PrivateKey) } @@ -270,14 +270,14 @@ func (b *BucketHandle) GenerateSignedPostPolicyV4(object string, opts *PostPolic func (b *BucketHandle) detectDefaultGoogleAccessID() (string, error) { returnErr := errors.New("no credentials found on client and not on GCE (Google Compute Engine)") - if b.c.creds != nil && len(b.c.creds.JSON) > 0 { + if j := b.c.credsJSON(); len(j) > 0 { var sa struct { ClientEmail string `json:"client_email"` SAImpersonationURL string `json:"service_account_impersonation_url"` CredType string `json:"type"` } - err := json.Unmarshal(b.c.creds.JSON, &sa) + err := json.Unmarshal(j, &sa) if err != nil { returnErr = err } else { diff --git a/storage/bucket_test.go b/storage/bucket_test.go index abd117d6e45a..223e162af755 100644 --- a/storage/bucket_test.go +++ b/storage/bucket_test.go @@ -21,12 +21,12 @@ import ( "testing" "time" + "cloud.google.com/go/auth/credentials" "cloud.google.com/go/compute/metadata" "cloud.google.com/go/internal/testutil" "cloud.google.com/go/storage/internal/apiv2/storagepb" "github.com/google/go-cmp/cmp" gax "github.com/googleapis/gax-go/v2" - "golang.org/x/oauth2/google" "google.golang.org/api/googleapi" "google.golang.org/api/option" raw "google.golang.org/api/storage/v1" @@ -1291,11 +1291,16 @@ func TestDetectDefaultGoogleAccessID(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + jsonBytes := []byte(tc.creds(tc.serviceAccount)) + credsAuth, err := credentials.DetectDefault(&credentials.DetectOptions{ + CredentialsJSON: jsonBytes, + }) + if tc.expectSuccess && err != nil { + t.Fatal(err) + } bucket := BucketHandle{ c: &Client{ - creds: &google.Credentials{ - JSON: []byte(tc.creds(tc.serviceAccount)), - }, + credsAuth: credsAuth, }, name: "my-bucket", } diff --git a/storage/storage.go b/storage/storage.go index 66fba72e6a49..51d55e84c34a 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -38,6 +38,7 @@ import ( "time" "unicode/utf8" + "cloud.google.com/go/auth" "cloud.google.com/go/internal/optional" "cloud.google.com/go/internal/trace" "cloud.google.com/go/storage/internal" @@ -118,12 +119,26 @@ type Client struct { xmlHost string // May be nil. creds *google.Credentials - retry *retryConfig + // May be nil. + credsAuth *auth.Credentials + retry *retryConfig // tc is the transport-agnostic client implemented with either gRPC or HTTP. tc storageClient } +// credsJSON returns the raw JSON of the Client's creds, or an empty slice +// if no credentials JSON is available. +func (c Client) credsJSON() []byte { + var json []byte + if c.creds != nil && len(c.creds.JSON) > 0 { + json = c.creds.JSON + } else if c.credsAuth != nil && len(c.credsAuth.JSON()) > 0 { + json = c.credsAuth.JSON() + } + return json +} + // NewClient creates a new Google Cloud Storage client using the HTTP transport. // The default scope is ScopeFullControl. To use a different scope, like // ScopeReadOnly, use option.WithScopes. @@ -135,6 +150,7 @@ type Client struct { // package. You may also use options defined in this package, such as [WithJSONReads]. func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { var creds *google.Credentials + var credsAuth *auth.Credentials // In general, it is recommended to use raw.NewService instead of htransport.NewClient // since raw.NewService configures the correct default endpoints when initializing the @@ -208,12 +224,13 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error } return &Client{ - hc: hc, - raw: rawService, - scheme: u.Scheme, - xmlHost: u.Host, - creds: creds, - tc: tc, + hc: hc, + raw: rawService, + scheme: u.Scheme, + xmlHost: u.Host, + creds: creds, + credsAuth: credsAuth, + tc: tc, }, nil } @@ -302,6 +319,7 @@ func (c *Client) Close() error { c.hc = nil c.raw = nil c.creds = nil + c.credsAuth = nil if c.tc != nil { return c.tc.Close() }