Skip to content

Commit

Permalink
Change default of refresh token format (#2406)
Browse files Browse the repository at this point in the history
* Change default of refresh token format

Default should be opaque, at least the default.
History about cloudfoundry/uaa-release#93
Some tests rely on JWT for refresh, therefore added for these tests again
jwt.token.refresh.format=jwt

* more default changes

* more default changes
  • Loading branch information
strehle committed Jul 27, 2023
1 parent ad89d72 commit 11b086c
Show file tree
Hide file tree
Showing 10 changed files with 24 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import java.util.stream.Collector;
import java.util.stream.Collectors;

import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.TokenFormat.JWT;
import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.TokenFormat.OPAQUE;

@JsonIgnoreProperties(ignoreUnknown = true)
public class TokenPolicy {
Expand All @@ -43,7 +43,7 @@ public class TokenPolicy {
private boolean jwtRevocable = false;
private boolean refreshTokenUnique = false;
private boolean refreshTokenRotate = false;
private String refreshTokenFormat = JWT.getStringValue();
private String refreshTokenFormat = OPAQUE.getStringValue();

@JsonGetter("keys")
@JsonInclude(JsonInclude.Include.NON_NULL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void test_default_values() {
assertFalse(policy.isRefreshTokenUnique());
assertFalse(policy.isJwtRevocable());
assertFalse(policy.isRefreshTokenRotate());
assertEquals(TokenConstants.TokenFormat.JWT.getStringValue(), policy.getRefreshTokenFormat());
assertEquals(TokenConstants.TokenFormat.OPAQUE.getStringValue(), policy.getRefreshTokenFormat());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ public void testCreateAccessTokenRefreshGrant() {
@Test
public void testCreateAccessTokenRefreshGrant_with_an_old_refresh_token_format_containing_scopes_claim() {
//Given
IdentityZoneHolder.get().getConfig().getTokenPolicy().setRefreshTokenFormat(JWT.getStringValue());
OAuth2AccessToken accessToken = getOAuth2AccessToken();
String refreshTokenJwt = accessToken.getRefreshToken().getValue();

Expand Down Expand Up @@ -1879,6 +1880,7 @@ public void testWrongClientDoesNotLeakToken() {

@Test
public void createRefreshToken_JwtDoesNotContainScopeClaim() {
IdentityZoneHolder.get().getConfig().getTokenPolicy().setRefreshTokenFormat(JWT.getStringValue());
AuthorizationRequest authorizationRequest = new AuthorizationRequest(CLIENT_ID, tokenSupport.requestedAuthScopes);
Map<String, String> authzParameters = new HashMap<>(authorizationRequest.getRequestParameters());
authzParameters.put(GRANT_TYPE, GRANT_TYPE_PASSWORD);
Expand Down
2 changes: 1 addition & 1 deletion uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@
<property name="activeKeyId" value="${jwt.token.policy.activeKeyId:#{null}}"/>
<property name="jwtRevocable" value="${jwt.token.revocable:false}"/>
<property name="refreshTokenFormat"
value="${jwt.token.refresh.format:#{T(org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.TokenFormat).JWT.getStringValue()}}"/>
value="${jwt.token.refresh.format:#{T(org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.TokenFormat).OPAQUE.getStringValue()}}"/>
<property name="refreshTokenUnique" value="${jwt.token.refresh.unique:false}"/>
<property name="refreshTokenRotate" value="${jwt.token.refresh.rotate:false}"/>
</bean>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ void reset() {
}

private void createClientAndUserInRandomZone() throws Exception {
createClientAndUserInRandomZone(null);
}

private void createClientAndUserInRandomZone(String refreshTokenFormat) throws Exception {
RandomValueStringGenerator generator = new RandomValueStringGenerator();
zone = setupIdentityZone(generator.generate());
IdentityZoneHolder.set(zone);
Expand All @@ -151,6 +155,9 @@ private void createClientAndUserInRandomZone() throws Exception {
keys.put("key2", signingKey2);
zone.getConfig().getTokenPolicy().setKeys(keys);
zone.getConfig().getTokenPolicy().setActiveKeyId("key1");
if (refreshTokenFormat != null) {
zone.getConfig().getTokenPolicy().setRefreshTokenFormat(refreshTokenFormat);
}
zone = identityZoneProvisioning.update(zone);

String clientId = "refreshclient";
Expand Down Expand Up @@ -284,7 +291,7 @@ void test_refresh_token_after_key_rotation() throws Exception {

@Test
void test_default_refresh_tokens_count() throws Exception {
createClientAndUserInRandomZone();
createClientAndUserInRandomZone("jwt");
template.update("delete from revocable_tokens");
assertEquals(0, countTokens(client.getClientId(), user.getId()));
getJwtRefreshToken(client.getClientId(), SECRET, user.getUserName(), SECRET, getZoneHostUrl(zone));
Expand Down Expand Up @@ -411,7 +418,7 @@ void refreshTokenGrantType_returnsIdToken_toOpenIdClients_withOpaqueRefreshToken

@Test
void refreshTokenGrantType_withJwtTokens_preservesRefreshTokenExpiryClaim() throws Exception {
createClientAndUserInRandomZone();
createClientAndUserInRandomZone("jwt");
when(timeService.getCurrentTimeMillis()).thenReturn(1000L);
CompositeToken tokenResponse = getTokensWithPasswordGrant(client.getClientId(), SECRET, user.getUserName(), SECRET, getZoneHostUrl(zone), "jwt");
String refreshToken = tokenResponse.getRefreshToken().getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@TestPropertySource(properties = {"uaa.url=https://localhost:8080/uaa"})
@TestPropertySource(properties = {"uaa.url=https://localhost:8080/uaa", "jwt.token.refresh.format=jwt"})
public class TokenMvcMockTests extends AbstractTokenMockMvcTests {
private String BADSECRET = "badsecret";
protected RandomValueStringGenerator generator = new RandomValueStringGenerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class IdentityZoneEndpointDocs extends EndpointDocs {
private static final String KEYS_CERT_DESC = "PEM encoded X.509 to be used in x5c, e.g. [RFC7517](https://tools.ietf.org/html/rfc7517#section-4.7)";
private static final String ACCESS_TOKEN_VALIDITY_DESC = "Time in seconds between when a access token is issued and when it expires. Defaults to global `accessTokenValidity`";
private static final String REFRESH_TOKEN_VALIDITY_DESC = "Time in seconds between when a refresh token is issued and when it expires. Defaults to global `refreshTokenValidity`";
private static final String REFRESH_TOKEN_FORMAT = "The format for the refresh token. Allowed values are `jwt`, `opaque`. Defaults to `jwt`.";
private static final String REFRESH_TOKEN_FORMAT = "The format for the refresh token. Allowed values are `jwt`, `opaque`. Defaults to `opaque`.";
private static final String REFRESH_TOKEN_UNIQUE = "If true, uaa will only issue one refresh token per client_id/user_id combination. Defaults to `false`.";
private static final String REFRESH_TOKEN_ROTATE = "If true, uaa will issue a new refresh token value in grant type refresh_token. Defaults to `false`.";
private static final String JWT_REVOCABLE_DESC = "Set to true if JWT tokens should be stored in the token store, and thus made individually revocable. Opaque tokens are always stored and revocable.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.UAA;
import static org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils.CookieCsrfPostProcessor.cookieCsrf;
import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.GRANT_TYPE_AUTHORIZATION_CODE;
import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.TokenFormat.JWT;
import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.TokenFormat.OPAQUE;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
Expand Down Expand Up @@ -2258,7 +2257,7 @@ private IdentityZone createZoneReturn() throws Exception {
assertEquals(id.toLowerCase(), zone.getSubdomain());
assertFalse(zone.getConfig().getTokenPolicy().isRefreshTokenUnique());
assertFalse(zone.getConfig().getTokenPolicy().isRefreshTokenRotate());
assertEquals(JWT.getStringValue(), zone.getConfig().getTokenPolicy().getRefreshTokenFormat());
assertEquals(OPAQUE.getStringValue(), zone.getConfig().getTokenPolicy().getRefreshTokenFormat());
checkAuditEventListener(1, AuditEventType.IdentityZoneCreatedEvent, zoneModifiedEventListener, IdentityZone.getUaaZoneId(), "http://localhost:8080/uaa/oauth/token", "identity");

//validate that default groups got created
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@

@DisplayName("Uaa Token Services Tests")
@DefaultTestContext
@TestPropertySource(properties = {"uaa.url=https://uaa.some.test.domain.com:555/uaa"})
@TestPropertySource(properties = {"uaa.url=https://uaa.some.test.domain.com:555/uaa", "jwt.token.refresh.format=jwt"})
class UaaTokenServicesTests {
@Autowired
private UaaTokenServices tokenServices;
Expand Down
6 changes: 5 additions & 1 deletion uaa/src/test/resources/integration_test_properties.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ jwt:
HYeZSkMuQDYHcaO9xtYP3QdhD+nLXbNrCxaSSaSX8tS4BjdcSH1yMyLFg5OqiJYg
wYFiptyKFm5QqFhFTY+20aE=
-----END PRIVATE KEY-----
revocable: false
refresh:
format: opaque
rotate: false
unique: false
login:
serviceProviderKey: |
-----BEGIN RSA PRIVATE KEY-----
Expand Down

0 comments on commit 11b086c

Please sign in to comment.