Skip to content

Commit eeb1a08

Browse files
committed
oauth2/google: fix the logic of sts 0 value of expires_in
1 parent 85231f9 commit eeb1a08

File tree

2 files changed

+102
-27
lines changed

2 files changed

+102
-27
lines changed

google/externalaccount/basecredentials.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,11 +471,12 @@ func (ts tokenSource) Token() (*oauth2.Token, error) {
471471
AccessToken: stsResp.AccessToken,
472472
TokenType: stsResp.TokenType,
473473
}
474-
if stsResp.ExpiresIn < 0 {
474+
475+
// The RFC8693 doesn't define the explicit 0 of "expires_in" field behavior.
476+
if stsResp.ExpiresIn <= 0 {
475477
return nil, fmt.Errorf("oauth2/google/externalaccount: got invalid expiry from security token service")
476-
} else if stsResp.ExpiresIn >= 0 {
477-
accessToken.Expiry = now().Add(time.Duration(stsResp.ExpiresIn) * time.Second)
478478
}
479+
accessToken.Expiry = now().Add(time.Duration(stsResp.ExpiresIn) * time.Second)
479480

480481
if stsResp.RefreshToken != "" {
481482
accessToken.RefreshToken = stsResp.RefreshToken

google/externalaccount/basecredentials_test.go

Lines changed: 98 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package externalaccount
66

77
import (
88
"context"
9+
"encoding/json"
910
"fmt"
1011
"io/ioutil"
1112
"net/http"
@@ -101,15 +102,18 @@ func run(t *testing.T, config *Config, tets *testExchangeTokenServer) (*oauth2.T
101102
return ts.Token()
102103
}
103104

104-
func validateToken(t *testing.T, tok *oauth2.Token) {
105-
if got, want := tok.AccessToken, correctAT; got != want {
105+
func validateToken(t *testing.T, tok *oauth2.Token, expectToken *oauth2.Token) {
106+
if expectToken == nil {
107+
return
108+
}
109+
if got, want := tok.AccessToken, expectToken.AccessToken; got != want {
106110
t.Errorf("Unexpected access token: got %v, but wanted %v", got, want)
107111
}
108-
if got, want := tok.TokenType, "Bearer"; got != want {
112+
if got, want := tok.TokenType, expectToken.TokenType; got != want {
109113
t.Errorf("Unexpected TokenType: got %v, but wanted %v", got, want)
110114
}
111115

112-
if got, want := tok.Expiry, testNow().Add(time.Duration(3600)*time.Second); got != want {
116+
if got, want := tok.Expiry, expectToken.Expiry; got != want {
113117
t.Errorf("Unexpected Expiry: got %v, but wanted %v", got, want)
114118
}
115119
}
@@ -173,30 +177,90 @@ func getExpectedMetricsHeader(source string, saImpersonation bool, configLifetim
173177
}
174178

175179
func TestToken(t *testing.T) {
176-
config := Config{
177-
Audience: "32555940559.apps.googleusercontent.com",
178-
SubjectTokenType: "urn:ietf:params:oauth:token-type:id_token",
179-
ClientSecret: "notsosecret",
180-
ClientID: "rbrgnognrhongo3bi4gb9ghg9g",
181-
CredentialSource: &testBaseCredSource,
182-
Scopes: []string{"https://www.googleapis.com/auth/devstorage.full_control"},
180+
type MockSTSResponse struct {
181+
AccessToken string `json:"access_token"`
182+
IssuedTokenType string `json:"issued_token_type"`
183+
TokenType string `json:"token_type"`
184+
ExpiresIn int32 `json:"expires_in,omitempty"`
185+
Scope string `json:"scopre,omitenpty"`
183186
}
184187

185-
server := testExchangeTokenServer{
186-
url: "/",
187-
authorization: "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ=",
188-
contentType: "application/x-www-form-urlencoded",
189-
metricsHeader: getExpectedMetricsHeader("file", false, false),
190-
body: baseCredsRequestBody,
191-
response: baseCredsResponseBody,
188+
testCases := []struct {
189+
name string
190+
responseBody MockSTSResponse
191+
expectToken *oauth2.Token
192+
expectErrorMsg string
193+
}{
194+
{
195+
name: "happy case",
196+
responseBody: MockSTSResponse{
197+
AccessToken: correctAT,
198+
IssuedTokenType: "urn:ietf:params:oauth:token-type:access_token",
199+
TokenType: "Bearer",
200+
ExpiresIn: 3600,
201+
Scope: "https://www.googleapis.com/auth/cloud-platform",
202+
},
203+
expectToken: &oauth2.Token{
204+
AccessToken: correctAT,
205+
TokenType: "Bearer",
206+
Expiry: testNow().Add(time.Duration(3600) * time.Second),
207+
},
208+
},
209+
{
210+
name: "no expiry time on token",
211+
responseBody: MockSTSResponse{
212+
AccessToken: correctAT,
213+
IssuedTokenType: "urn:ietf:params:oauth:token-type:access_token",
214+
TokenType: "Bearer",
215+
Scope: "https://www.googleapis.com/auth/cloud-platform",
216+
},
217+
expectToken: nil,
218+
expectErrorMsg: "oauth2/google/externalaccount: got invalid expiry from security token service",
219+
},
220+
{
221+
name: "negative expiry time",
222+
responseBody: MockSTSResponse{
223+
AccessToken: correctAT,
224+
IssuedTokenType: "urn:ietf:params:oauth:token-type:access_token",
225+
TokenType: "Bearer",
226+
ExpiresIn: -1,
227+
Scope: "https://www.googleapis.com/auth/cloud-platform",
228+
},
229+
expectToken: nil,
230+
expectErrorMsg: "oauth2/google/externalaccount: got invalid expiry from security token service",
231+
},
192232
}
193233

194-
tok, err := run(t, &config, &server)
234+
for _, testCase := range testCases {
235+
config := Config{
236+
Audience: "32555940559.apps.googleusercontent.com",
237+
SubjectTokenType: "urn:ietf:params:oauth:token-type:id_token",
238+
ClientSecret: "notsosecret",
239+
ClientID: "rbrgnognrhongo3bi4gb9ghg9g",
240+
CredentialSource: &testBaseCredSource,
241+
Scopes: []string{"https://www.googleapis.com/auth/devstorage.full_control"},
242+
}
195243

196-
if err != nil {
197-
t.Fatalf("Unexpected error: %e", err)
244+
responseBody, _ := json.Marshal(testCase.responseBody)
245+
246+
server := testExchangeTokenServer{
247+
url: "/",
248+
authorization: "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ=",
249+
contentType: "application/x-www-form-urlencoded",
250+
metricsHeader: getExpectedMetricsHeader("file", false, false),
251+
body: baseCredsRequestBody,
252+
response: string(responseBody),
253+
}
254+
255+
tok, err := run(t, &config, &server)
256+
257+
if err != nil {
258+
if err.Error() != testCase.expectErrorMsg {
259+
t.Errorf("Error actual = %v, and Expect = %v", err, testCase.expectErrorMsg)
260+
}
261+
}
262+
validateToken(t, tok, testCase.expectToken)
198263
}
199-
validateToken(t, tok)
200264
}
201265

202266
func TestWorkforcePoolTokenWithClientID(t *testing.T) {
@@ -224,7 +288,12 @@ func TestWorkforcePoolTokenWithClientID(t *testing.T) {
224288
if err != nil {
225289
t.Fatalf("Unexpected error: %e", err)
226290
}
227-
validateToken(t, tok)
291+
expectToken := oauth2.Token{
292+
AccessToken: correctAT,
293+
TokenType: "Bearer",
294+
Expiry: testNow().Add(time.Duration(3600) * time.Second),
295+
}
296+
validateToken(t, tok, &expectToken)
228297
}
229298

230299
func TestWorkforcePoolTokenWithoutClientID(t *testing.T) {
@@ -251,7 +320,12 @@ func TestWorkforcePoolTokenWithoutClientID(t *testing.T) {
251320
if err != nil {
252321
t.Fatalf("Unexpected error: %e", err)
253322
}
254-
validateToken(t, tok)
323+
expectToken := oauth2.Token{
324+
AccessToken: correctAT,
325+
TokenType: "Bearer",
326+
Expiry: testNow().Add(time.Duration(3600) * time.Second),
327+
}
328+
validateToken(t, tok, &expectToken)
255329
}
256330

257331
func TestNonworkforceWithWorkforcePoolUserProject(t *testing.T) {

0 commit comments

Comments
 (0)