1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package externalaccount
16
17 import (
18 "context"
19 "io"
20 "net/http"
21 "net/http/httptest"
22 "testing"
23
24 "cloud.google.com/go/auth/internal"
25 )
26
27 var (
28 baseImpersonateCredsReqBody = "audience=32555940559.apps.googleusercontent.com&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange&requested_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&subject_token=street123&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Ajwt"
29 baseImpersonateCredsRespBody = `{"accessToken":"Second.Access.Token","expireTime":"2020-12-28T15:01:23Z"}`
30 )
31
32 func TestImpersonation(t *testing.T) {
33 var impersonationTests = []struct {
34 name string
35 opts *Options
36 wantBody string
37 metricsHeader string
38 }{
39 {
40 name: "Base Impersonation",
41 opts: &Options{
42 Audience: "32555940559.apps.googleusercontent.com",
43 SubjectTokenType: jwtTokenType,
44 TokenInfoURL: "http://localhost:8080/v1/tokeninfo",
45 ClientSecret: "notsosecret",
46 ClientID: "rbrgnognrhongo3bi4gb9ghg9g",
47 CredentialSource: testBaseCredSource,
48 Scopes: []string{"https://www.googleapis.com/auth/devstorage.full_control"},
49 },
50 wantBody: "{\"lifetime\":\"3600s\",\"scope\":[\"https://www.googleapis.com/auth/devstorage.full_control\"]}",
51 metricsHeader: expectedMetricsHeader("file", true, false),
52 },
53 {
54 name: "With TokenLifetime Set",
55 opts: &Options{
56 Audience: "32555940559.apps.googleusercontent.com",
57 SubjectTokenType: jwtTokenType,
58 TokenInfoURL: "http://localhost:8080/v1/tokeninfo",
59 ClientSecret: "notsosecret",
60 ClientID: "rbrgnognrhongo3bi4gb9ghg9g",
61 CredentialSource: testBaseCredSource,
62 Scopes: []string{"https://www.googleapis.com/auth/devstorage.full_control"},
63 ServiceAccountImpersonationLifetimeSeconds: 10000,
64 },
65 wantBody: "{\"lifetime\":\"10000s\",\"scope\":[\"https://www.googleapis.com/auth/devstorage.full_control\"]}",
66 metricsHeader: expectedMetricsHeader("file", true, false),
67 },
68 }
69 for _, tt := range impersonationTests {
70 t.Run(tt.name, func(t *testing.T) {
71 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
72 if r.URL.Path == "/target" {
73 headerAuth := r.Header.Get("Authorization")
74 if got, want := headerAuth, "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ="; got != want {
75 t.Errorf("got %v, want %v", got, want)
76 }
77 headerContentType := r.Header.Get("Content-Type")
78 if got, want := headerContentType, "application/x-www-form-urlencoded"; got != want {
79 t.Errorf("got %v, want %v", got, want)
80 }
81 body, err := io.ReadAll(r.Body)
82 if err != nil {
83 t.Fatalf("Failed reading request body: %v.", err)
84 }
85 if got, want := string(body), baseImpersonateCredsReqBody; got != want {
86 t.Errorf("got %v, want %v", got, want)
87 }
88 w.Header().Set("Content-Type", "application/json")
89 w.Write([]byte(baseCredsResponseBody))
90 } else if r.URL.Path == "/impersonate" {
91 headerAuth := r.Header.Get("Authorization")
92 if got, want := headerAuth, "Bearer Sample.Access.Token"; got != want {
93 t.Errorf("got %v, want %v", got, want)
94 }
95 headerContentType := r.Header.Get("Content-Type")
96 if got, want := headerContentType, "application/json"; got != want {
97 t.Errorf("got %v, want %v", got, want)
98 }
99 body, err := io.ReadAll(r.Body)
100 if err != nil {
101 t.Fatalf("Failed reading request body: %v.", err)
102 }
103 if got, want := string(body), tt.wantBody; got != want {
104 t.Errorf("got %v, want %v", got, want)
105 }
106 w.Header().Set("Content-Type", "application/json")
107 w.Write([]byte(baseImpersonateCredsRespBody))
108 } else {
109 t.Error("unmapped request")
110 }
111 }))
112 defer ts.Close()
113
114 testImpersonateOpts := tt.opts
115 testImpersonateOpts.ServiceAccountImpersonationURL = ts.URL + "/impersonate"
116 testImpersonateOpts.TokenURL = ts.URL + "/target"
117 testImpersonateOpts.Client = internal.CloneDefaultClient()
118
119 tp, err := NewTokenProvider(testImpersonateOpts)
120 if err != nil {
121 t.Fatalf("Failed to create Provider: %v", err)
122 }
123
124 oldNow := Now
125 defer func() { Now = oldNow }()
126 Now = testNow
127
128 tok, err := tp.Token(context.Background())
129 if err != nil {
130 t.Fatalf("tp.Token() = %v", err)
131 }
132 if got, want := tok.Value, "Second.Access.Token"; got != want {
133 t.Errorf("got %v, want %v", got, want)
134 }
135 if got, want := tok.Type, internal.TokenTypeBearer; got != want {
136 t.Errorf("got %v, want %v", got, want)
137 }
138 })
139 }
140 }
141
View as plain text