1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package credentials
16
17 import (
18 "context"
19 "encoding/base64"
20 "encoding/json"
21 "fmt"
22 "net/http"
23 "net/http/httptest"
24 "os"
25 "strings"
26 "testing"
27 "time"
28
29 "cloud.google.com/go/auth"
30 "cloud.google.com/go/auth/credentials/internal/gdch"
31 "cloud.google.com/go/auth/internal"
32 "cloud.google.com/go/auth/internal/credsfile"
33 "cloud.google.com/go/auth/internal/jwt"
34 )
35
36 type tokResp struct {
37 AccessToken string `json:"access_token"`
38 TokenType string `json:"token_type"`
39 ExpiresIn int `json:"expires_in"`
40 }
41
42 func TestDefaultCredentials_GdchServiceAccountKey(t *testing.T) {
43 ctx := context.Background()
44 aud := "http://sample-aud.com/"
45 b, err := os.ReadFile("../internal/testdata/gdch.json")
46 if err != nil {
47 t.Fatal(err)
48 }
49 f, err := credsfile.ParseGDCHServiceAccount(b)
50 if err != nil {
51 t.Fatal(err)
52 }
53 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
54 if r.Method != "POST" {
55 t.Errorf("unexpected request method: %v", r.Method)
56 }
57 if err := r.ParseForm(); err != nil {
58 t.Error(err)
59 }
60 parts := strings.Split(r.FormValue("subject_token"), ".")
61 var header jwt.Header
62 var claims jwt.Claims
63 b, err = base64.RawURLEncoding.DecodeString(parts[0])
64 if err != nil {
65 t.Fatal(err)
66 }
67 if err := json.Unmarshal(b, &header); err != nil {
68 t.Fatal(err)
69 }
70 b, err = base64.RawURLEncoding.DecodeString(parts[1])
71 if err != nil {
72 t.Fatal(err)
73 }
74 if err := json.Unmarshal(b, &claims); err != nil {
75 t.Fatal(err)
76 }
77
78 if got := r.FormValue("audience"); got != aud {
79 t.Errorf("got audience %v, want %v", got, gdch.GrantType)
80 }
81 if want := jwt.HeaderAlgRSA256; header.Algorithm != want {
82 t.Errorf("got alg %q, want %q", header.Algorithm, want)
83 }
84 if want := jwt.HeaderType; header.Type != want {
85 t.Errorf("got typ %q, want %q", header.Type, want)
86 }
87 if want := "abcdef1234567890"; header.KeyID != want {
88 t.Errorf("got kid %q, want %q", header.KeyID, want)
89 }
90
91 if want := "system:serviceaccount:fake_project:sa_name"; claims.Iss != want {
92 t.Errorf("got iss %q, want %q", claims.Iss, want)
93 }
94 if want := "system:serviceaccount:fake_project:sa_name"; claims.Sub != want {
95 t.Errorf("got sub %q, want %q", claims.Sub, want)
96 }
97 if want := fmt.Sprintf("http://%s", r.Host); claims.Aud != want {
98 t.Errorf("got aud %q, want %q", claims.Aud, want)
99 }
100 resp := &tokResp{
101 AccessToken: "a_fake_token",
102 TokenType: internal.TokenTypeBearer,
103 ExpiresIn: 60,
104 }
105 if err := json.NewEncoder(w).Encode(&resp); err != nil {
106 t.Fatal(err)
107 }
108 }))
109 f.TokenURL = ts.URL
110 f.CertPath = "../internal/testdata/cert.pem"
111 b, err = json.Marshal(&f)
112 if err != nil {
113 t.Fatal(err)
114 }
115
116 if _, err := DetectDefault(&DetectOptions{CredentialsJSON: b}); err == nil {
117 t.Fatal("STSAudience should be required")
118 }
119 creds, err := DetectDefault(&DetectOptions{
120 CredentialsJSON: b,
121 STSAudience: aud,
122 })
123 if err != nil {
124 t.Fatal(err)
125 }
126 got, err := creds.ProjectID(ctx)
127 if err != nil {
128 t.Fatal(err)
129 }
130 if want := "fake_project"; got != want {
131 t.Fatalf("got %q, want %q", got, want)
132 }
133 got, err = creds.UniverseDomain(ctx)
134 if err != nil {
135 t.Fatal(err)
136 }
137 if want := "googleapis.com"; got != want {
138 t.Fatalf("got %q, want %q", got, want)
139 }
140 tok, err := creds.Token(context.Background())
141 if err != nil {
142 t.Fatal(err)
143 }
144 if want := "a_fake_token"; tok.Value != want {
145 t.Fatalf("got AccessToken %q, want %q", tok.Value, want)
146 }
147 if want := internal.TokenTypeBearer; tok.Type != want {
148 t.Fatalf("got TokenType %q, want %q", tok.Type, want)
149 }
150 }
151
152 func TestDefaultCredentials_ImpersonatedServiceAccountKey(t *testing.T) {
153 ctx := context.Background()
154 b, err := os.ReadFile("../internal/testdata/imp.json")
155 if err != nil {
156 t.Fatal(err)
157 }
158 f, err := credsfile.ParseImpersonatedServiceAccount(b)
159 if err != nil {
160 t.Fatal(err)
161 }
162 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
163 resp := &struct {
164 AccessToken string `json:"accessToken"`
165 ExpireTime string `json:"expireTime"`
166 }{
167 AccessToken: "a_fake_token",
168 ExpireTime: "2006-01-02T15:04:05Z",
169 }
170 if err := json.NewEncoder(w).Encode(&resp); err != nil {
171 t.Fatal(err)
172 }
173 }))
174 f.ServiceAccountImpersonationURL = ts.URL
175 b, err = json.Marshal(f)
176 if err != nil {
177 t.Fatal(err)
178 }
179
180 creds, err := DetectDefault(&DetectOptions{
181 CredentialsJSON: b,
182 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
183 UseSelfSignedJWT: true,
184 })
185 if err != nil {
186 t.Fatal(err)
187 }
188 got, err := creds.UniverseDomain(ctx)
189 if err != nil {
190 t.Fatal(err)
191 }
192 if want := "googleapis.com"; got != want {
193 t.Fatalf("got %q, want %q", got, want)
194 }
195 tok, err := creds.Token(context.Background())
196 if err != nil {
197 t.Fatalf("creds.Token() = %v", err)
198 }
199 if want := "a_fake_token"; tok.Value != want {
200 t.Fatalf("got %q, want %q", tok.Value, want)
201 }
202 if want := internal.TokenTypeBearer; tok.Type != want {
203 t.Fatalf("got %q, want %q", tok.Type, want)
204 }
205 }
206
207 func TestDefaultCredentials_UserCredentialsKey(t *testing.T) {
208 ctx := context.Background()
209 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
210 w.Header().Set("Content-Type", "application/json")
211 resp := &tokResp{
212 AccessToken: "a_fake_token",
213 TokenType: internal.TokenTypeBearer,
214 ExpiresIn: 60,
215 }
216 if err := json.NewEncoder(w).Encode(&resp); err != nil {
217 t.Fatal(err)
218 }
219 }))
220
221 creds, err := DetectDefault(&DetectOptions{
222 CredentialsFile: "../internal/testdata/user.json",
223 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
224 TokenURL: ts.URL,
225 })
226 if err != nil {
227 t.Fatal(err)
228 }
229 got, err := creds.QuotaProjectID(ctx)
230 if err != nil {
231 t.Fatal(err)
232 }
233 if want := "fake_project2"; got != want {
234 t.Fatalf("got %q, want %q", got, want)
235 }
236 got, err = creds.UniverseDomain(ctx)
237 if err != nil {
238 t.Fatal(err)
239 }
240 if want := "googleapis.com"; got != want {
241 t.Fatalf("got %q, want %q", got, want)
242 }
243 tok, err := creds.Token(context.Background())
244 if err != nil {
245 t.Fatalf("creds.Token() = %v", err)
246 }
247 if want := "a_fake_token"; tok.Value != want {
248 t.Fatalf("got %q, want %q", tok.Value, want)
249 }
250 if want := internal.TokenTypeBearer; tok.Type != want {
251 t.Fatalf("got %q, want %q", tok.Type, want)
252 }
253 }
254
255 func TestDefaultCredentials_UserCredentialsKey_UniverseDomain(t *testing.T) {
256 ctx := context.Background()
257 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
258 w.Header().Set("Content-Type", "application/json")
259 resp := &tokResp{
260 AccessToken: "a_fake_token",
261 TokenType: internal.TokenTypeBearer,
262 ExpiresIn: 60,
263 }
264 if err := json.NewEncoder(w).Encode(&resp); err != nil {
265 t.Fatal(err)
266 }
267 }))
268
269 creds, err := DetectDefault(&DetectOptions{
270 CredentialsFile: "../internal/testdata/user_universe_domain.json",
271 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
272 TokenURL: ts.URL,
273 })
274 if err != nil {
275 t.Fatal(err)
276 }
277 got, err := creds.QuotaProjectID(ctx)
278 if err != nil {
279 t.Fatal(err)
280 }
281 if want := "fake_project2"; got != want {
282 t.Fatalf("got %q, want %q", got, want)
283 }
284 got, err = creds.UniverseDomain(ctx)
285 if err != nil {
286 t.Fatal(err)
287 }
288 if want := "example.com"; got != want {
289 t.Fatalf("got %q, want %q", got, want)
290 }
291 tok, err := creds.Token(context.Background())
292 if err != nil {
293 t.Fatalf("creds.Token() = %v", err)
294 }
295 if want := "a_fake_token"; tok.Value != want {
296 t.Fatalf("got %q, want %q", tok.Value, want)
297 }
298 if want := internal.TokenTypeBearer; tok.Type != want {
299 t.Fatalf("got %q, want %q", tok.Type, want)
300 }
301 }
302
303 func TestDefaultCredentials_ServiceAccountKey(t *testing.T) {
304 ctx := context.Background()
305 b, err := os.ReadFile("../internal/testdata/sa.json")
306 if err != nil {
307 t.Fatal(err)
308 }
309 f, err := credsfile.ParseServiceAccount(b)
310 if err != nil {
311 t.Fatal(err)
312 }
313 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
314 resp := &tokResp{
315 AccessToken: "a_fake_token",
316 TokenType: internal.TokenTypeBearer,
317 ExpiresIn: 60,
318 }
319 if err := json.NewEncoder(w).Encode(&resp); err != nil {
320 t.Fatal(err)
321 }
322 }))
323 f.TokenURL = ts.URL
324 b, err = json.Marshal(f)
325 if err != nil {
326 t.Fatal(err)
327 }
328
329 creds, err := DetectDefault(&DetectOptions{
330 CredentialsJSON: b,
331 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
332 })
333 if err != nil {
334 t.Fatal(err)
335 }
336 got, err := creds.ProjectID(ctx)
337 if err != nil {
338 t.Fatal(err)
339 }
340 if want := "fake_project"; got != want {
341 t.Fatalf("got %q, want %q", got, want)
342 }
343 got, err = creds.UniverseDomain(ctx)
344 if err != nil {
345 t.Fatal(err)
346 }
347 if want := "googleapis.com"; got != want {
348 t.Fatalf("got %q, want %q", got, want)
349 }
350 tok, err := creds.Token(context.Background())
351 if err != nil {
352 t.Fatalf("creds.Token() = %v", err)
353 }
354 if want := "a_fake_token"; tok.Value != want {
355 t.Fatalf("got %q, want %q", tok.Value, want)
356 }
357 if want := internal.TokenTypeBearer; tok.Type != want {
358 t.Fatalf("got %q, want %q", tok.Type, want)
359 }
360 }
361
362 func TestDefaultCredentials_ServiceAccountKeySelfSigned(t *testing.T) {
363 ctx := context.Background()
364 b, err := os.ReadFile("../internal/testdata/sa.json")
365 if err != nil {
366 t.Fatal(err)
367 }
368 oldNow := now
369 now = func() time.Time { return time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC) }
370 defer func() { now = oldNow }()
371 wantTok := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFiY2RlZjEyMzQ1Njc4OTAifQ.eyJpc3MiOiJnb3BoZXJAZmFrZV9wcm9qZWN0LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2NvcGUiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2Nsb3VkLXBsYXRmb3JtIiwiZXhwIjo5NDk0MTE4MDAsImlhdCI6OTQ5NDA4MjAwLCJhdWQiOiIiLCJzdWIiOiJnb3BoZXJAZmFrZV9wcm9qZWN0LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0.n9Hggd-1Vw4WTQiWkh7q9r5eDsz-khU5vwkZl2VmgdUF3ZxDq1ARzchCNtTifeorzbp9C0i0vCr855G7FZkVCJXPVMcnxbwfMSafUYmVsmutbQiV9eTWfWM0_Ljiwa9GEbv1bN06Lz4LrelPKEaxsDbY6tU8LJUiome_gSMLfLk"
372
373 creds, err := DetectDefault(&DetectOptions{
374 CredentialsJSON: b,
375 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
376 UseSelfSignedJWT: true,
377 })
378 if err != nil {
379 t.Fatal(err)
380 }
381
382 got, err := creds.ProjectID(ctx)
383 if err != nil {
384 t.Fatal(err)
385 }
386 if want := "fake_project"; got != want {
387 t.Fatalf("got %q, want %q", got, want)
388 }
389 got, err = creds.UniverseDomain(ctx)
390 if err != nil {
391 t.Fatal(err)
392 }
393 if want := "googleapis.com"; got != want {
394 t.Fatalf("got %q, want %q", got, want)
395 }
396 tok, err := creds.Token(context.Background())
397 if err != nil {
398 t.Fatalf("creds.Token() = %v", err)
399 }
400 if tok.Value != wantTok {
401 t.Fatalf("got %q, want %q", tok.Value, wantTok)
402 }
403 if want := internal.TokenTypeBearer; tok.Type != want {
404 t.Fatalf("got %q, want %q", tok.Type, want)
405 }
406 }
407
408 func TestDefaultCredentials_ServiceAccountKeySelfSigned_UniverseDomain(t *testing.T) {
409 ctx := context.Background()
410 b, err := os.ReadFile("../internal/testdata/sa_universe_domain.json")
411 if err != nil {
412 t.Fatal(err)
413 }
414 oldNow := now
415 now = func() time.Time { return time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC) }
416 defer func() { now = oldNow }()
417 wantTok := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFiY2RlZjEyMzQ1Njc4OTAifQ.eyJpc3MiOiJnb3BoZXJAZmFrZV9wcm9qZWN0LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2NvcGUiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2Nsb3VkLXBsYXRmb3JtIiwiZXhwIjo5NDk0MTE4MDAsImlhdCI6OTQ5NDA4MjAwLCJhdWQiOiIiLCJzdWIiOiJnb3BoZXJAZmFrZV9wcm9qZWN0LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0.n9Hggd-1Vw4WTQiWkh7q9r5eDsz-khU5vwkZl2VmgdUF3ZxDq1ARzchCNtTifeorzbp9C0i0vCr855G7FZkVCJXPVMcnxbwfMSafUYmVsmutbQiV9eTWfWM0_Ljiwa9GEbv1bN06Lz4LrelPKEaxsDbY6tU8LJUiome_gSMLfLk"
418
419 creds, err := DetectDefault(&DetectOptions{
420 CredentialsJSON: b,
421 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
422 UseSelfSignedJWT: true,
423 })
424 if err != nil {
425 t.Fatal(err)
426 }
427 got, err := creds.ProjectID(ctx)
428 if err != nil {
429 t.Fatal(err)
430 }
431 if want := "fake_project"; got != want {
432 t.Fatalf("got %q, want %q", got, want)
433 }
434 got, err = creds.UniverseDomain(ctx)
435 if err != nil {
436 t.Fatal(err)
437 }
438 if want := "example.com"; got != want {
439 t.Fatalf("got %q, want %q", got, want)
440 }
441 tok, err := creds.Token(context.Background())
442 if err != nil {
443 t.Fatalf("creds.Token() = %v", err)
444 }
445 if tok.Value != wantTok {
446 t.Fatalf("got %q, want %q", tok.Value, wantTok)
447 }
448 if want := internal.TokenTypeBearer; tok.Type != want {
449 t.Fatalf("got %q, want %q", tok.Type, want)
450 }
451 }
452
453 func TestDefaultCredentials_ClientCredentials(t *testing.T) {
454 ctx := context.Background()
455 b, err := os.ReadFile("../internal/testdata/clientcreds_installed.json")
456 if err != nil {
457 t.Fatal(err)
458 }
459 f, err := credsfile.ParseClientCredentials(b)
460 if err != nil {
461 t.Fatal(err)
462 }
463
464 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
465 w.Header().Set("Content-Type", "application/json")
466 resp := &tokResp{
467 AccessToken: "a_fake_token",
468 TokenType: internal.TokenTypeBearer,
469 ExpiresIn: 60,
470 }
471 if err := json.NewEncoder(w).Encode(&resp); err != nil {
472 t.Fatal(err)
473 }
474 }))
475 f.Installed.TokenURI = ts.URL
476 b, err = json.Marshal(f)
477 if err != nil {
478 t.Fatal(err)
479 }
480
481 creds, err := DetectDefault(&DetectOptions{
482 CredentialsJSON: b,
483 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
484 TokenURL: ts.URL,
485 AuthHandlerOptions: &auth.AuthorizationHandlerOptions{
486 Handler: func(authCodeURL string) (code string, state string, err error) {
487 return "code", "state", nil
488 },
489 State: "state",
490 PKCEOpts: &auth.PKCEOptions{
491 Challenge: "codeChallenge",
492 ChallengeMethod: "plain",
493 Verifier: "codeChallenge",
494 },
495 },
496 })
497 if err != nil {
498 t.Fatal(err)
499 }
500 got, err := creds.UniverseDomain(ctx)
501 if err != nil {
502 t.Fatal(err)
503 }
504 if want := "googleapis.com"; got != want {
505 t.Fatalf("got %q, want %q", got, want)
506 }
507 tok, err := creds.Token(context.Background())
508 if err != nil {
509 t.Fatalf("creds.Token() = %v", err)
510 }
511 if want := "a_fake_token"; tok.Value != want {
512 t.Fatalf("got %q, want %q", tok.Value, want)
513 }
514 if want := internal.TokenTypeBearer; tok.Type != want {
515 t.Fatalf("got %q, want %q", tok.Type, want)
516 }
517 }
518
519
520 func TestDefaultCredentials_ExternalAccountKey(t *testing.T) {
521 ctx := context.Background()
522 b, err := os.ReadFile("../internal/testdata/exaccount_url.json")
523 if err != nil {
524 t.Fatal(err)
525 }
526 f, err := credsfile.ParseExternalAccount(b)
527 if err != nil {
528 t.Fatal(err)
529 }
530 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
531 defer r.Body.Close()
532 if r.URL.Path == "/token" {
533 resp := &struct {
534 Token string `json:"id_token"`
535 }{
536 Token: "a_fake_token_base",
537 }
538 if err := json.NewEncoder(w).Encode(&resp); err != nil {
539 t.Error(err)
540 }
541 } else if r.URL.Path == "/sts" {
542 r.ParseForm()
543 if got, want := r.Form.Get("subject_token"), "a_fake_token_base"; got != want {
544 t.Errorf("got %q, want %q", got, want)
545 }
546
547 resp := &struct {
548 AccessToken string `json:"access_token"`
549 ExpiresIn int `json:"expires_in"`
550 }{
551 AccessToken: "a_fake_token_sts",
552 ExpiresIn: 60,
553 }
554 if err := json.NewEncoder(w).Encode(&resp); err != nil {
555 t.Error(err)
556 }
557 } else if r.URL.Path == "/impersonate" {
558 if want := "a_fake_token_sts"; !strings.Contains(r.Header.Get("Authorization"), want) {
559 t.Errorf("missing sts token: got %q, want %q", r.Header.Get("Authorization"), want)
560 }
561
562 resp := &struct {
563 AccessToken string `json:"accessToken"`
564 ExpireTime string `json:"expireTime"`
565 }{
566 AccessToken: "a_fake_token",
567 ExpireTime: "2006-01-02T15:04:05Z",
568 }
569 if err := json.NewEncoder(w).Encode(&resp); err != nil {
570 t.Error(err)
571 }
572 } else {
573 t.Errorf("unexpected call to %q", r.URL.Path)
574 }
575 }))
576 f.ServiceAccountImpersonationURL = ts.URL + "/impersonate"
577 f.CredentialSource.URL = ts.URL + "/token"
578 f.TokenURL = ts.URL + "/sts"
579 b, err = json.Marshal(f)
580 if err != nil {
581 t.Fatal(err)
582 }
583
584 creds, err := DetectDefault(&DetectOptions{
585 CredentialsJSON: b,
586 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
587 UseSelfSignedJWT: true,
588 })
589 if err != nil {
590 t.Fatal(err)
591 }
592 got, err := creds.UniverseDomain(ctx)
593 if err != nil {
594 t.Fatal(err)
595 }
596 if want := "googleapis.com"; got != want {
597 t.Fatalf("got %q, want %q", got, want)
598 }
599 tok, err := creds.Token(ctx)
600 if err != nil {
601 t.Fatalf("creds.Token() = %v", err)
602 }
603 if want := "a_fake_token"; tok.Value != want {
604 t.Fatalf("got %q, want %q", tok.Value, want)
605 }
606 if want := internal.TokenTypeBearer; tok.Type != want {
607 t.Fatalf("got %q, want %q", tok.Type, want)
608 }
609 }
610 func TestDefaultCredentials_ExternalAccountAuthorizedUserKey(t *testing.T) {
611 b, err := os.ReadFile("../internal/testdata/exaccount_user.json")
612 if err != nil {
613 t.Fatal(err)
614 }
615 f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
616 if err != nil {
617 t.Fatal(err)
618 }
619 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
620 defer r.Body.Close()
621 if got, want := r.URL.Path, "/sts"; got != want {
622 t.Errorf("got %q, want %q", got, want)
623 }
624 r.ParseForm()
625 if got, want := r.Form.Get("refresh_token"), "refreshing"; got != want {
626 t.Errorf("got %q, want %q", got, want)
627 }
628 if got, want := r.Form.Get("grant_type"), "refresh_token"; got != want {
629 t.Errorf("got %q, want %q", got, want)
630 }
631
632 resp := &struct {
633 AccessToken string `json:"access_token"`
634 ExpiresIn int `json:"expires_in"`
635 }{
636 AccessToken: "a_fake_token",
637 ExpiresIn: 60,
638 }
639 if err := json.NewEncoder(w).Encode(&resp); err != nil {
640 t.Error(err)
641 }
642 }))
643 f.TokenURL = ts.URL + "/sts"
644 b, err = json.Marshal(f)
645 if err != nil {
646 t.Fatal(err)
647 }
648
649 creds, err := DetectDefault(&DetectOptions{
650 CredentialsJSON: b,
651 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
652 UseSelfSignedJWT: true,
653 })
654 if err != nil {
655 t.Fatal(err)
656 }
657 tok, err := creds.Token(context.Background())
658 if err != nil {
659 t.Fatalf("creds.Token() = %v", err)
660 }
661 if want := "a_fake_token"; tok.Value != want {
662 t.Fatalf("got %q, want %q", tok.Value, want)
663 }
664 if want := internal.TokenTypeBearer; tok.Type != want {
665 t.Fatalf("got %q, want %q", tok.Type, want)
666 }
667 }
668
669 func TestDefaultCredentials_Fails(t *testing.T) {
670 t.Setenv(credsfile.GoogleAppCredsEnvVar, "nothingToSeeHere")
671 t.Setenv("HOME", "nothingToSeeHere")
672 t.Setenv("APPDATA", "nothingToSeeHere")
673 allowOnGCECheck = false
674 defer func() { allowOnGCECheck = true }()
675 if _, err := DetectDefault(&DetectOptions{
676 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
677 }); !strings.Contains(err.Error(), adcSetupURL) {
678 t.Fatalf("got %v, wanted to contain %v", err, adcSetupURL)
679 }
680 }
681
682 func TestDefaultCredentials_BadFiletype(t *testing.T) {
683 if _, err := DetectDefault(&DetectOptions{
684 CredentialsJSON: []byte(`{"type":"42"}`),
685 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
686 }); err == nil {
687 t.Fatal("got nil, want non-nil err")
688 }
689 }
690
691 func TestDefaultCredentials_BadFileName(t *testing.T) {
692 if _, err := DetectDefault(&DetectOptions{
693 CredentialsFile: "a/bad/filepath",
694 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
695 }); err == nil {
696 t.Fatal("got nil, want non-nil err")
697 }
698 }
699
700 func TestDefaultCredentials_Validate(t *testing.T) {
701 tests := []struct {
702 name string
703 opts *DetectOptions
704 }{
705 {
706 name: "missing options",
707 },
708 {
709 name: "scope and audience provided",
710 opts: &DetectOptions{
711 Scopes: []string{"scope"},
712 Audience: "aud",
713 },
714 },
715 {
716 name: "file and json provided",
717 opts: &DetectOptions{
718 Scopes: []string{"scope"},
719 CredentialsFile: "path",
720 CredentialsJSON: []byte(`{"some":"json"}`),
721 },
722 },
723 }
724 for _, tt := range tests {
725 t.Run(tt.name, func(t *testing.T) {
726 if _, err := DetectDefault(tt.opts); err == nil {
727 t.Error("got nil, want an error")
728 }
729 })
730 }
731 }
732
733 func TestDefaultCredentials_UniverseDomain(t *testing.T) {
734 ctx := context.Background()
735 tests := []struct {
736 name string
737 opts *DetectOptions
738 want string
739 }{
740 {
741 name: "service account json",
742 opts: &DetectOptions{
743 CredentialsFile: "../internal/testdata/sa.json",
744 },
745 want: "googleapis.com",
746 },
747 {
748 name: "service account json with file universe domain",
749 opts: &DetectOptions{
750 CredentialsFile: "../internal/testdata/sa_universe_domain.json",
751 UseSelfSignedJWT: true,
752 },
753 want: "example.com",
754 },
755 {
756 name: "service account json with options universe domain",
757 opts: &DetectOptions{
758 CredentialsFile: "../internal/testdata/sa.json",
759 UseSelfSignedJWT: true,
760 UniverseDomain: "foo.com",
761 },
762 want: "foo.com",
763 },
764 {
765 name: "service account json with file and options universe domain",
766 opts: &DetectOptions{
767 CredentialsFile: "../internal/testdata/sa_universe_domain.json",
768 UseSelfSignedJWT: true,
769 UniverseDomain: "foo.com",
770 },
771 want: "foo.com",
772 },
773 {
774 name: "user json",
775 opts: &DetectOptions{
776 CredentialsFile: "../internal/testdata/user.json",
777 TokenURL: "example.com",
778 },
779 want: "googleapis.com",
780 },
781 {
782 name: "user json with options universe domain",
783 opts: &DetectOptions{
784 CredentialsFile: "../internal/testdata/user.json",
785 UniverseDomain: "foo.com",
786 },
787 want: "googleapis.com",
788 },
789 {
790 name: "user json with file universe domain",
791 opts: &DetectOptions{
792 CredentialsFile: "../internal/testdata/user_universe_domain.json",
793 TokenURL: "example.com",
794 },
795 want: "example.com",
796 },
797 {
798 name: "user json with file and options universe domain",
799 opts: &DetectOptions{
800 CredentialsFile: "../internal/testdata/user_universe_domain.json",
801 UniverseDomain: "foo.com",
802 },
803 want: "example.com",
804 },
805 {
806 name: "external account json",
807 opts: &DetectOptions{
808 CredentialsFile: "../internal/testdata/exaccount_url.json",
809 },
810 want: "googleapis.com",
811 },
812 {
813 name: "external account json with file universe domain",
814 opts: &DetectOptions{
815 CredentialsFile: "../internal/testdata/exaccount_url_universe_domain.json",
816 },
817 want: "example.com",
818 },
819 {
820 name: "external account json with options universe domain",
821 opts: &DetectOptions{
822 CredentialsFile: "../internal/testdata/exaccount_url.json",
823 UniverseDomain: "foo.com",
824 },
825 want: "foo.com",
826 },
827 {
828 name: "external account json with file and options universe domain",
829 opts: &DetectOptions{
830 CredentialsFile: "../internal/testdata/exaccount_url_universe_domain.json",
831 UniverseDomain: "foo.com",
832 },
833 want: "foo.com",
834 },
835 {
836 name: "external account user json",
837 opts: &DetectOptions{
838 CredentialsFile: "../internal/testdata/exaccount_user.json",
839 },
840 want: "googleapis.com",
841 },
842 {
843 name: "external account user json with file universe domain",
844 opts: &DetectOptions{
845 CredentialsFile: "../internal/testdata/exaccount_user_universe_domain.json",
846 },
847 want: "example.com",
848 },
849 {
850 name: "external account user json with options universe domain",
851 opts: &DetectOptions{
852 CredentialsFile: "../internal/testdata/exaccount_user.json",
853 UniverseDomain: "foo.com",
854 },
855 want: "googleapis.com",
856 },
857 {
858 name: "external account user json with file and options universe domain",
859 opts: &DetectOptions{
860 CredentialsFile: "../internal/testdata/exaccount_user_universe_domain.json",
861 UniverseDomain: "foo.com",
862 },
863 want: "example.com",
864 },
865 {
866 name: "impersonated service account json",
867 opts: &DetectOptions{
868 CredentialsFile: "../internal/testdata/imp.json",
869 UseSelfSignedJWT: true,
870 },
871 want: "googleapis.com",
872 },
873 {
874 name: "impersonated service account json with file universe domain",
875 opts: &DetectOptions{
876 CredentialsFile: "../internal/testdata/imp_universe_domain.json",
877 },
878 want: "example.com",
879 },
880 {
881 name: "impersonated service account json with options universe domain",
882 opts: &DetectOptions{
883 CredentialsFile: "../internal/testdata/imp.json",
884 UseSelfSignedJWT: true,
885 UniverseDomain: "foo.com",
886 },
887 want: "foo.com",
888 },
889 {
890 name: "impersonated service account json with file and options universe domain",
891 opts: &DetectOptions{
892 CredentialsFile: "../internal/testdata/imp_universe_domain.json",
893 UniverseDomain: "foo.com",
894 },
895 want: "foo.com",
896 },
897 }
898 for _, tt := range tests {
899 t.Run(tt.name, func(t *testing.T) {
900 creds, err := DetectDefault(tt.opts)
901 if err != nil {
902 t.Fatalf("%v", err)
903 }
904 ud, err := creds.UniverseDomain(ctx)
905 if err != nil {
906 t.Fatal(err)
907 }
908 if ud != tt.want {
909 t.Fatalf("got %q, want %q", ud, tt.want)
910 }
911 })
912 }
913 }
914
View as plain text