@@ -12,6 +12,8 @@ import (
1212 "strings"
1313 "testing"
1414 "time"
15+
16+ "golang.org/x/oauth2"
1517)
1618
1719const (
@@ -35,66 +37,175 @@ var testConfig = Config{
3537}
3638
3739var (
38- baseCredsRequestBody = "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%2Fdevstorage.full_control&subject_token=street123&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Ajwt"
39- baseCredsResponseBody = `{"access_token":"Sample.Access.Token","issued_token_type":"urn:ietf:params:oauth:token-type:access_token","token_type":"Bearer","expires_in":3600,"scope":"https://www.googleapis.com/auth/cloud-platform"}`
40- correctAT = "Sample.Access.Token"
41- expiry int64 = 234852
40+ baseCredsRequestBody = "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%2Fdevstorage.full_control&subject_token=street123&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aid_token"
41+ baseCredsResponseBody = `{"access_token":"Sample.Access.Token","issued_token_type":"urn:ietf:params:oauth:token-type:access_token","token_type":"Bearer","expires_in":3600,"scope":"https://www.googleapis.com/auth/cloud-platform"}`
42+ workforcePoolRequestBodyWithClientId = "audience=%2F%2Fiam.googleapis.com%2Flocations%2Feu%2FworkforcePools%2Fpool-id%2Fproviders%2Fprovider-id&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%2Fdevstorage.full_control&subject_token=street123&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aid_token"
43+ workforcePoolRequestBodyWithoutClientId = "audience=%2F%2Fiam.googleapis.com%2Flocations%2Feu%2FworkforcePools%2Fpool-id%2Fproviders%2Fprovider-id&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange&options=%7B%22userProject%22%3A%22myProject%22%7D&requested_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdevstorage.full_control&subject_token=street123&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aid_token"
44+ correctAT = "Sample.Access.Token"
45+ expiry int64 = 234852
4246)
4347var (
4448 testNow = func () time.Time { return time .Unix (expiry , 0 ) }
4549)
4650
47- func TestToken (t * testing.T ) {
51+ type testExchangeTokenServer struct {
52+ url string
53+ authorization string
54+ contentType string
55+ body string
56+ response string
57+ }
4858
49- targetServer := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
50- if got , want := r .URL .String (), "/" ; got != want {
59+ func run (t * testing.T , config * Config , tets * testExchangeTokenServer ) (* oauth2.Token , error ) {
60+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
61+ if got , want := r .URL .String (), tets .url ; got != want {
5162 t .Errorf ("URL.String(): got %v but want %v" , got , want )
5263 }
5364 headerAuth := r .Header .Get ("Authorization" )
54- if got , want := headerAuth , "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ=" ; got != want {
65+ if got , want := headerAuth , tets . authorization ; got != want {
5566 t .Errorf ("got %v but want %v" , got , want )
5667 }
5768 headerContentType := r .Header .Get ("Content-Type" )
58- if got , want := headerContentType , "application/x-www-form-urlencoded" ; got != want {
69+ if got , want := headerContentType , tets . contentType ; got != want {
5970 t .Errorf ("got %v but want %v" , got , want )
6071 }
6172 body , err := ioutil .ReadAll (r .Body )
6273 if err != nil {
6374 t .Fatalf ("Failed reading request body: %s." , err )
6475 }
65- if got , want := string (body ), baseCredsRequestBody ; got != want {
76+ if got , want := string (body ), tets . body ; got != want {
6677 t .Errorf ("Unexpected exchange payload: got %v but want %v" , got , want )
6778 }
6879 w .Header ().Set ("Content-Type" , "application/json" )
69- w .Write ([]byte (baseCredsResponseBody ))
80+ w .Write ([]byte (tets . response ))
7081 }))
71- defer targetServer .Close ()
72-
73- testConfig .TokenURL = targetServer .URL
74- ourTS := tokenSource {
75- ctx : context .Background (),
76- conf : & testConfig ,
77- }
82+ defer server .Close ()
83+ config .TokenURL = server .URL
7884
7985 oldNow := now
8086 defer func () { now = oldNow }()
8187 now = testNow
8288
83- tok , err := ourTS . Token ()
84- if err != nil {
85- t . Fatalf ( "Unexpected error: %e" , err )
89+ ts := tokenSource {
90+ ctx : context . Background (),
91+ conf : config ,
8692 }
93+
94+ return ts .Token ()
95+ }
96+
97+ func validateToken (t * testing.T , tok * oauth2.Token ) {
8798 if got , want := tok .AccessToken , correctAT ; got != want {
8899 t .Errorf ("Unexpected access token: got %v, but wanted %v" , got , want )
89100 }
90101 if got , want := tok .TokenType , "Bearer" ; got != want {
91102 t .Errorf ("Unexpected TokenType: got %v, but wanted %v" , got , want )
92103 }
93104
94- if got , want := tok .Expiry , now ().Add (time .Duration (3600 )* time .Second ); got != want {
105+ if got , want := tok .Expiry , testNow ().Add (time .Duration (3600 )* time .Second ); got != want {
95106 t .Errorf ("Unexpected Expiry: got %v, but wanted %v" , got , want )
96107 }
108+ }
109+
110+ func TestToken (t * testing.T ) {
111+ config := Config {
112+ Audience : "32555940559.apps.googleusercontent.com" ,
113+ SubjectTokenType : "urn:ietf:params:oauth:token-type:id_token" ,
114+ ClientSecret : "notsosecret" ,
115+ ClientID : "rbrgnognrhongo3bi4gb9ghg9g" ,
116+ CredentialSource : testBaseCredSource ,
117+ Scopes : []string {"https://www.googleapis.com/auth/devstorage.full_control" },
118+ }
119+
120+ server := testExchangeTokenServer {
121+ url : "/" ,
122+ authorization : "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ=" ,
123+ contentType : "application/x-www-form-urlencoded" ,
124+ body : baseCredsRequestBody ,
125+ response : baseCredsResponseBody ,
126+ }
127+
128+ tok , err := run (t , & config , & server )
97129
130+ if err != nil {
131+ t .Fatalf ("Unexpected error: %e" , err )
132+ }
133+ validateToken (t , tok )
134+ }
135+
136+ func TestWorkforcePoolTokenWithClientID (t * testing.T ) {
137+ config := Config {
138+ Audience : "//iam.googleapis.com/locations/eu/workforcePools/pool-id/providers/provider-id" ,
139+ SubjectTokenType : "urn:ietf:params:oauth:token-type:id_token" ,
140+ ClientSecret : "notsosecret" ,
141+ ClientID : "rbrgnognrhongo3bi4gb9ghg9g" ,
142+ CredentialSource : testBaseCredSource ,
143+ Scopes : []string {"https://www.googleapis.com/auth/devstorage.full_control" },
144+ WorkforcePoolUserProject : "myProject" ,
145+ }
146+
147+ server := testExchangeTokenServer {
148+ url : "/" ,
149+ authorization : "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ=" ,
150+ contentType : "application/x-www-form-urlencoded" ,
151+ body : workforcePoolRequestBodyWithClientId ,
152+ response : baseCredsResponseBody ,
153+ }
154+
155+ tok , err := run (t , & config , & server )
156+
157+ if err != nil {
158+ t .Fatalf ("Unexpected error: %e" , err )
159+ }
160+ validateToken (t , tok )
161+ }
162+
163+ func TestWorkforcePoolTokenWithoutClientID (t * testing.T ) {
164+ config := Config {
165+ Audience : "//iam.googleapis.com/locations/eu/workforcePools/pool-id/providers/provider-id" ,
166+ SubjectTokenType : "urn:ietf:params:oauth:token-type:id_token" ,
167+ ClientSecret : "notsosecret" ,
168+ CredentialSource : testBaseCredSource ,
169+ Scopes : []string {"https://www.googleapis.com/auth/devstorage.full_control" },
170+ WorkforcePoolUserProject : "myProject" ,
171+ }
172+
173+ server := testExchangeTokenServer {
174+ url : "/" ,
175+ authorization : "" ,
176+ contentType : "application/x-www-form-urlencoded" ,
177+ body : workforcePoolRequestBodyWithoutClientId ,
178+ response : baseCredsResponseBody ,
179+ }
180+
181+ tok , err := run (t , & config , & server )
182+
183+ if err != nil {
184+ t .Fatalf ("Unexpected error: %e" , err )
185+ }
186+ validateToken (t , tok )
187+ }
188+
189+ func TestNonworkforceWithWorkforcePoolUserProject (t * testing.T ) {
190+ config := Config {
191+ Audience : "32555940559.apps.googleusercontent.com" ,
192+ SubjectTokenType : "urn:ietf:params:oauth:token-type:id_token" ,
193+ TokenURL : "https://sts.googleapis.com" ,
194+ ClientSecret : "notsosecret" ,
195+ ClientID : "rbrgnognrhongo3bi4gb9ghg9g" ,
196+ CredentialSource : testBaseCredSource ,
197+ Scopes : []string {"https://www.googleapis.com/auth/devstorage.full_control" },
198+ WorkforcePoolUserProject : "myProject" ,
199+ }
200+
201+ _ , err := config .TokenSource (context .Background ())
202+
203+ if err == nil {
204+ t .Fatalf ("Expected error but found none" )
205+ }
206+ if got , want := err .Error (), "oauth2/google: workforce_pool_user_project should not be set for non-workforce pool credentials" ; got != want {
207+ t .Errorf ("Incorrect error received.\n Expected: %s\n Recieved: %s" , want , got )
208+ }
98209}
99210
100211func TestValidateURLTokenURL (t * testing.T ) {
@@ -210,3 +321,41 @@ func TestValidateURLImpersonateURL(t *testing.T) {
210321 })
211322 }
212323}
324+
325+ func TestWorkforcePoolCreation (t * testing.T ) {
326+ var audienceValidatyTests = []struct {
327+ audience string
328+ expectSuccess bool
329+ }{
330+ {"//iam.googleapis.com/locations/global/workforcePools/pool-id/providers/provider-id" , true },
331+ {"//iam.googleapis.com/locations/eu/workforcePools/pool-id/providers/provider-id" , true },
332+ {"//iam.googleapis.com/locations/eu/workforcePools/workloadIdentityPools/providers/provider-id" , true },
333+ {"identitynamespace:1f12345:my_provider" , false },
334+ {"//iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/pool-id/providers/provider-id" , false },
335+ {"//iam.googleapis.com/projects/123456/locations/eu/workloadIdentityPools/pool-id/providers/provider-id" , false },
336+ {"//iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/workforcePools/providers/provider-id" , false },
337+ {"//iamgoogleapis.com/locations/eu/workforcePools/pool-id/providers/provider-id" , false },
338+ {"//iam.googleapiscom/locations/eu/workforcePools/pool-id/providers/provider-id" , false },
339+ {"//iam.googleapis.com/locations/workforcePools/pool-id/providers/provider-id" , false },
340+ {"//iam.googleapis.com/locations/eu/workforcePool/pool-id/providers/provider-id" , false },
341+ {"//iam.googleapis.com/locations//workforcePool/pool-id/providers/provider-id" , false },
342+ }
343+
344+ ctx := context .Background ()
345+ for _ , tt := range audienceValidatyTests {
346+ t .Run (" " + tt .audience , func (t * testing.T ) { // We prepend a space ahead of the test input when outputting for sake of readability.
347+ config := testConfig
348+ config .TokenURL = "https://sts.googleapis.com" // Setting the most basic acceptable tokenURL
349+ config .ServiceAccountImpersonationURL = "https://iamcredentials.googleapis.com"
350+ config .Audience = tt .audience
351+ config .WorkforcePoolUserProject = "myProject"
352+ _ , err := config .TokenSource (ctx )
353+
354+ if tt .expectSuccess && err != nil {
355+ t .Errorf ("got %v but want nil" , err )
356+ } else if ! tt .expectSuccess && err == nil {
357+ t .Errorf ("got nil but expected an error" )
358+ }
359+ })
360+ }
361+ }
0 commit comments