Skip to content

Commit 1a04baf

Browse files
authored
feat(auth): move credentials to base auth package (#9590)
We are moving the credentials struct to the base auth package as we intend to use this as the main abstraction for this library. To better support the new idea of universes having access to the full credential object will be crucial for the client libraries. Also, the detect package has been renamed to `credentials` to make it more generic in the future. We have plans on directly exposing packages like `externalaccount` in the future so having a better name here makes sense. This is the first of two large breaking changes for this module. This module not in use by our libraries yet, is version 0.1.X and has always been explicitly labeled experimental in the readme. As such, we feel comfortable making these changes for the long term health of the module.
1 parent 93c7bc0 commit 1a04baf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+390
-227
lines changed

auth/auth.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ const (
4040
// 3 minutes and 45 seconds before expiration. The shortest MDS cache is 4 minutes,
4141
// so we give it 15 seconds to refresh it's cache before attempting to refresh a token.
4242
defaultExpiryDelta = 215 * time.Second
43+
44+
universeDomainDefault = "googleapis.com"
4345
)
4446

4547
var (
@@ -94,6 +96,112 @@ func (t *Token) isValidWithEarlyExpiry(earlyExpiry time.Duration) bool {
9496
return !t.Expiry.Round(0).Add(-earlyExpiry).Before(timeNow())
9597
}
9698

99+
// Credentials holds Google credentials, including
100+
// [Application Default Credentials](https://developers.google.com/accounts/docs/application-default-credentials).
101+
type Credentials struct {
102+
json []byte
103+
projectID CredentialsPropertyProvider
104+
quotaProjectID CredentialsPropertyProvider
105+
// universeDomain is the default service domain for a given Cloud universe.
106+
universeDomain CredentialsPropertyProvider
107+
108+
TokenProvider
109+
}
110+
111+
// JSON returns the bytes associated with the the file used to source
112+
// credentials if one was used.
113+
func (c *Credentials) JSON() []byte {
114+
return c.json
115+
}
116+
117+
// ProjectID returns the associated project ID from the underlying file or
118+
// environment.
119+
func (c *Credentials) ProjectID(ctx context.Context) (string, error) {
120+
if c.projectID == nil {
121+
return internal.GetProjectID(c.json, ""), nil
122+
}
123+
v, err := c.projectID.GetProperty(ctx)
124+
if err != nil {
125+
return "", err
126+
}
127+
return internal.GetProjectID(c.json, v), nil
128+
}
129+
130+
// QuotaProjectID returns the associated quota project ID from the underlying
131+
// file or environment.
132+
func (c *Credentials) QuotaProjectID(ctx context.Context) (string, error) {
133+
if c.quotaProjectID == nil {
134+
return internal.GetQuotaProject(c.json, ""), nil
135+
}
136+
v, err := c.quotaProjectID.GetProperty(ctx)
137+
if err != nil {
138+
return "", err
139+
}
140+
return internal.GetQuotaProject(c.json, v), nil
141+
}
142+
143+
// UniverseDomain returns the default service domain for a given Cloud universe.
144+
// The default value is "googleapis.com".
145+
func (c *Credentials) UniverseDomain(ctx context.Context) (string, error) {
146+
if c.universeDomain == nil {
147+
return universeDomainDefault, nil
148+
}
149+
v, err := c.universeDomain.GetProperty(ctx)
150+
if err != nil {
151+
return "", err
152+
}
153+
if v == "" {
154+
return universeDomainDefault, nil
155+
}
156+
return v, err
157+
}
158+
159+
// CredentialsPropertyProvider provides an implementation to fetch a property
160+
// value for [Credentials].
161+
type CredentialsPropertyProvider interface {
162+
GetProperty(context.Context) (string, error)
163+
}
164+
165+
// CredentialsPropertyFunc is a type adapter to allow the use of ordinary
166+
// functions as a [CredentialsPropertyProvider].
167+
type CredentialsPropertyFunc func(context.Context) (string, error)
168+
169+
// GetProperty loads the properly value provided the given context.
170+
func (p CredentialsPropertyFunc) GetProperty(ctx context.Context) (string, error) {
171+
return p(ctx)
172+
}
173+
174+
// CredentialsOptions are used to configure [Credentials].
175+
type CredentialsOptions struct {
176+
// TokenProvider is a means of sourcing a token for the credentials. Required.
177+
TokenProvider TokenProvider
178+
// JSON is the raw contents of the credentials file if sourced from a file.
179+
JSON []byte
180+
// ProjectIDProvider resolves the project ID associated with the
181+
// credentials.
182+
ProjectIDProvider CredentialsPropertyProvider
183+
// QuotaProjectIDProvider resolves the quota project ID associated with the
184+
// credentials.
185+
QuotaProjectIDProvider CredentialsPropertyProvider
186+
// UniverseDomainProvider resolves the universe domain with the credentials.
187+
UniverseDomainProvider CredentialsPropertyProvider
188+
}
189+
190+
// NewCredentials returns new [Credentials] from the provided options. Most users
191+
// will want to build this object a function from the
192+
// [cloud.google.com/go/auth/credentials] package.
193+
func NewCredentials(opts *CredentialsOptions) *Credentials {
194+
creds := &Credentials{
195+
TokenProvider: opts.TokenProvider,
196+
json: opts.JSON,
197+
projectID: opts.ProjectIDProvider,
198+
quotaProjectID: opts.QuotaProjectIDProvider,
199+
universeDomain: opts.UniverseDomainProvider,
200+
}
201+
202+
return creds
203+
}
204+
97205
// CachedTokenProviderOptions provided options for configuring a
98206
// CachedTokenProvider.
99207
type CachedTokenProviderOptions struct {

auth/detect/compute.go renamed to auth/credentials/compute.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package detect
15+
package credentials
1616

1717
import (
1818
"context"

auth/detect/compute_test.go renamed to auth/credentials/compute_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package detect
15+
package credentials
1616

1717
import (
1818
"context"

auth/detect/detect.go renamed to auth/credentials/detect.go

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package detect
15+
package credentials
1616

1717
import (
18+
"context"
1819
"encoding/json"
1920
"errors"
2021
"fmt"
@@ -38,72 +39,21 @@ const (
3839

3940
// Help on default credentials
4041
adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc"
41-
42-
universeDomainDefault = "googleapis.com"
4342
)
4443

4544
var (
4645
// for testing
4746
allowOnGCECheck = true
4847
)
4948

50-
// Credentials holds Google credentials, including
51-
// [Application Default Credentials](https://developers.google.com/accounts/docs/application-default-credentials).
52-
type Credentials struct {
53-
json []byte
54-
projectID string
55-
quotaProjectID string
56-
// universeDomain is the default service domain for a given Cloud universe.
57-
universeDomain string
58-
59-
auth.TokenProvider
60-
}
61-
62-
func newCredentials(tokenProvider auth.TokenProvider, json []byte, projectID string, quotaProjectID string, universeDomain string) *Credentials {
63-
return &Credentials{
64-
json: json,
65-
projectID: internal.GetProjectID(json, projectID),
66-
quotaProjectID: internal.GetQuotaProject(json, quotaProjectID),
67-
TokenProvider: tokenProvider,
68-
universeDomain: universeDomain,
69-
}
70-
}
71-
72-
// JSON returns the bytes associated with the the file used to source
73-
// credentials if one was used.
74-
func (c *Credentials) JSON() []byte {
75-
return c.json
76-
}
77-
78-
// ProjectID returns the associated project ID from the underlying file or
79-
// environment.
80-
func (c *Credentials) ProjectID() string {
81-
return c.projectID
82-
}
83-
84-
// QuotaProjectID returns the associated quota project ID from the underlying
85-
// file or environment.
86-
func (c *Credentials) QuotaProjectID() string {
87-
return c.quotaProjectID
88-
}
89-
90-
// UniverseDomain returns the default service domain for a given Cloud universe.
91-
// The default value is "googleapis.com".
92-
func (c *Credentials) UniverseDomain() string {
93-
if c.universeDomain == "" {
94-
return universeDomainDefault
95-
}
96-
return c.universeDomain
97-
}
98-
9949
// OnGCE reports whether this process is running in Google Cloud.
10050
func OnGCE() bool {
10151
// TODO(codyoss): once all libs use this auth lib move metadata check here
10252
return allowOnGCECheck && metadata.OnGCE()
10353
}
10454

105-
// DefaultCredentials searches for "Application Default Credentials" and returns
106-
// a credential based on the [Options] provided.
55+
// DetectDefault searches for "Application Default Credentials" and returns
56+
// a credential based on the [DetectOptions] provided.
10757
//
10858
// It looks for credentials in the following places, preferring the first
10959
// location found:
@@ -119,7 +69,7 @@ func OnGCE() bool {
11969
// - On Google Compute Engine, Google App Engine standard second generation
12070
// runtimes, and Google App Engine flexible environment, it fetches
12171
// credentials from the metadata server.
122-
func DefaultCredentials(opts *Options) (*Credentials, error) {
72+
func DetectDefault(opts *DetectOptions) (*auth.Credentials, error) {
12373
if err := opts.validate(); err != nil {
12474
return nil, err
12575
}
@@ -138,15 +88,19 @@ func DefaultCredentials(opts *Options) (*Credentials, error) {
13888
}
13989

14090
if OnGCE() {
141-
id, _ := metadata.ProjectID()
142-
return newCredentials(computeTokenProvider(opts.EarlyTokenRefresh, opts.Scopes...), nil, id, "", ""), nil
91+
return auth.NewCredentials(&auth.CredentialsOptions{
92+
TokenProvider: computeTokenProvider(opts.EarlyTokenRefresh, opts.Scopes...),
93+
ProjectIDProvider: auth.CredentialsPropertyFunc(func(context.Context) (string, error) {
94+
return metadata.ProjectID()
95+
}),
96+
}), nil
14397
}
14498

14599
return nil, fmt.Errorf("detect: could not find default credentials. See %v for more information", adcSetupURL)
146100
}
147101

148-
// Options provides configuration for [DefaultCredentials].
149-
type Options struct {
102+
// DetectOptions provides configuration for [DetectDefault].
103+
type DetectOptions struct {
150104
// Scopes that credentials tokens should have. Example:
151105
// https://www.googleapis.com/auth/cloud-platform. Required if Audience is
152106
// not provided.
@@ -188,7 +142,7 @@ type Options struct {
188142
Client *http.Client
189143
}
190144

191-
func (o *Options) validate() error {
145+
func (o *DetectOptions) validate() error {
192146
if o == nil {
193147
return errors.New("detect: options must be provided")
194148
}
@@ -201,35 +155,35 @@ func (o *Options) validate() error {
201155
return nil
202156
}
203157

204-
func (o *Options) tokenURL() string {
158+
func (o *DetectOptions) tokenURL() string {
205159
if o.TokenURL != "" {
206160
return o.TokenURL
207161
}
208162
return googleTokenURL
209163
}
210164

211-
func (o *Options) scopes() []string {
165+
func (o *DetectOptions) scopes() []string {
212166
scopes := make([]string, len(o.Scopes))
213167
copy(scopes, o.Scopes)
214168
return scopes
215169
}
216170

217-
func (o *Options) client() *http.Client {
171+
func (o *DetectOptions) client() *http.Client {
218172
if o.Client != nil {
219173
return o.Client
220174
}
221175
return internal.CloneDefaultClient()
222176
}
223177

224-
func readCredentialsFile(filename string, opts *Options) (*Credentials, error) {
178+
func readCredentialsFile(filename string, opts *DetectOptions) (*auth.Credentials, error) {
225179
b, err := os.ReadFile(filename)
226180
if err != nil {
227181
return nil, err
228182
}
229183
return readCredentialsFileJSON(b, opts)
230184
}
231185

232-
func readCredentialsFileJSON(b []byte, opts *Options) (*Credentials, error) {
186+
func readCredentialsFileJSON(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
233187
// attempt to parse jsonData as a Google Developers Console client_credentials.json.
234188
config := clientCredConfigFromJSON(b, opts)
235189
if config != nil {
@@ -240,12 +194,15 @@ func readCredentialsFileJSON(b []byte, opts *Options) (*Credentials, error) {
240194
if err != nil {
241195
return nil, err
242196
}
243-
return newCredentials(tp, b, "", "", ""), nil
197+
return auth.NewCredentials(&auth.CredentialsOptions{
198+
TokenProvider: tp,
199+
JSON: b,
200+
}), nil
244201
}
245202
return fileCredentials(b, opts)
246203
}
247204

248-
func clientCredConfigFromJSON(b []byte, opts *Options) *auth.Options3LO {
205+
func clientCredConfigFromJSON(b []byte, opts *DetectOptions) *auth.Options3LO {
249206
var creds internaldetect.ClientCredentialsFile
250207
var c *internaldetect.Config3LO
251208
if err := json.Unmarshal(b, &creds); err != nil {

0 commit comments

Comments
 (0)