Skip to content

Commit

Permalink
fix: Invalidate the SA's AccessToken when createScoped() is called (#…
Browse files Browse the repository at this point in the history
…1489)

* fix: Invalidate the SA's AccessToken when createScoped() is called

* chore: Add comments for invalidating the access token

* chore: Fix formatting

* chore: Address PR comments
  • Loading branch information
lqiu96 committed Sep 3, 2024
1 parent f07d19a commit f26fee7
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -684,14 +684,17 @@ public GoogleCredentials createScoped(Collection<String> newScopes) {
}

/**
* Clones the service account with the specified scopes.
* Clones the service account with the specified scopes. The Access Token is invalidated even if
* the same scopes are provided. Access Tokens contain information of the internal values (i.e.
* scope). If an internal value (scope) is modified, then the existing Access Token is no longer
* valid and should not be re-used.
*
* <p>Should be called before use for instances with empty scopes.
*/
@Override
public GoogleCredentials createScoped(
Collection<String> newScopes, Collection<String> newDefaultScopes) {
return this.toBuilder().setScopes(newScopes, newDefaultScopes).build();
return this.toBuilder().setScopes(newScopes, newDefaultScopes).setAccessToken(null).build();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,31 @@ public void onFailure(Throwable exception) {
assertTrue("Should have run onSuccess() callback", success.get());
}

@Test
public void createScopes_existingAccessTokenInvalidated() throws IOException {
PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8);
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN);
GoogleCredentials credentials =
ServiceAccountCredentials.newBuilder()
.setClientId(CLIENT_ID)
.setClientEmail(CLIENT_EMAIL)
.setPrivateKey(privateKey)
.setPrivateKeyId(PRIVATE_KEY_ID)
.setProjectId(PROJECT_ID)
.setQuotaProjectId("my-quota-project-id")
.setHttpTransportFactory(transportFactory)
.setScopes(SCOPES)
.build();
TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), ACCESS_TOKEN);

// Calling createScoped() again will invalidate the existing access token and calling
// `refresh()` is required to get a new Access Token.
credentials = credentials.createScoped("RANDOM_SCOPES");
AccessToken newAccessToken = credentials.getAccessToken();
assertNull(newAccessToken);
}

private void verifyJwtAccess(Map<String, List<String>> metadata, String expectedScopeClaim)
throws IOException {
assertNotNull(metadata);
Expand Down

0 comments on commit f26fee7

Please sign in to comment.