KEYCLOAK-11838: Fixed unstable RefreshTokenTest (#6455)

This commit is contained in:
Martin Bartoš 2019-11-08 08:53:23 +01:00 committed by Marek Posolda
parent 28b41623eb
commit bf8184221a

View file

@ -45,7 +45,6 @@ import org.keycloak.testsuite.AbstractAuthTest;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.federation.storage.ComponentExportImportTest;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
import org.keycloak.testsuite.util.ClientManager;
@ -54,6 +53,7 @@ import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.RealmManager;
import org.keycloak.testsuite.util.TokenSignatureUtil;
import org.keycloak.testsuite.util.UserManager;
import org.keycloak.testsuite.util.WaitUtils;
import org.keycloak.util.BasicAuthHelper;
import javax.ws.rs.client.Client;
@ -245,6 +245,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
String accessTokenString = tokenResponse.getAccessToken();
setTimeOffset(2);
OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(accessTokenString, "password");
Assert.assertNotEquals(200, response.getStatusCode());
@ -274,6 +275,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(refreshToken1.getId(), sessionId).assertEvent();
setTimeOffset(4);
OAuthClient.AccessTokenResponse response3 = oauth.doRefreshTokenRequest(response1.getRefreshToken(), "password");
assertEquals(200, response3.getStatusCode());
@ -313,12 +316,15 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(refreshToken1.getId(), sessionId).assertEvent();
setTimeOffset(4);
OAuthClient.AccessTokenResponse response3 = oauth.doRefreshTokenRequest(response1.getRefreshToken(), "password");
assertEquals(400, response3.getStatusCode());
events.expectRefresh(refreshToken1.getId(), sessionId).removeDetail(Details.TOKEN_ID).removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent();
setTimeOffset(6);
oauth.doRefreshTokenRequest(response2.getRefreshToken(), "password");
events.expectRefresh(refreshToken2.getId(), sessionId).assertEvent();
@ -369,6 +375,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(initialRefreshToken.getId(), sessionId).assertEvent();
setTimeOffset(6);
// Token reused twice, became invalid.
OAuthClient.AccessTokenResponse responseSecondReuse = oauth.doRefreshTokenRequest(initialResponse.getRefreshToken(), "password");
@ -377,6 +384,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(initialRefreshToken.getId(), sessionId).removeDetail(Details.TOKEN_ID)
.removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent();
setTimeOffset(8);
// Refresh token from first use became invalid.
OAuthClient.AccessTokenResponse responseUseOfInvalidatedRefreshToken =
oauth.doRefreshTokenRequest(responseFirstUse.getRefreshToken(), "password");
@ -386,6 +394,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(newTokenFirstUse.getId(), sessionId).removeDetail(Details.TOKEN_ID)
.removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent();
setTimeOffset(10);
// Refresh token from reuse is still valid.
OAuthClient.AccessTokenResponse responseUseOfValidRefreshToken =
oauth.doRefreshTokenRequest(responseFirstReuse.getRefreshToken(), "password");
@ -522,6 +531,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
try {
ClientManager.realm(adminClient.realm("test")).clientId(oauth.getClientId()).enabled(false);
setTimeOffset(2);
response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
assertEquals(400, response.getStatusCode());
@ -550,6 +560,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
testingClient.testing().removeUserSession("test", sessionId);
setTimeOffset(2);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
assertEquals(400, tokenResponse.getStatusCode());
@ -580,10 +591,12 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
tokenResponse2 = oauth.doAccessTokenRequest(code, "password");
setTimeOffset(4);
// Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail
OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password");
assertEquals(400, responseReuseExceeded.getStatusCode());
setTimeOffset(6);
// Finally try with valid refresh token
responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password");
assertEquals(200, responseReuseExceeded.getStatusCode());
@ -594,6 +607,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String refreshToken1 = loginAndForceNewLoginPage();
adminClient.realm("test").logoutAll();
// Must wait for server to execute the request. Sometimes, there is issue with the execution and another tests failed, because of this.
WaitUtils.pause(500);
events.clear();
@ -609,10 +624,14 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
tokenResponse2 = oauth.doAccessTokenRequest(code, "password");
setTimeOffset(4);
// Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail
OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password");
assertEquals(400, responseReuseExceeded.getStatusCode());
setTimeOffset(6);
// Finally try with valid refresh token
responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password");
assertEquals(200, responseReuseExceeded.getStatusCode());
@ -640,10 +659,14 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
tokenResponse2 = oauth.doAccessTokenRequest(code, "password");
setTimeOffset(4);
// Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail
OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password");
assertEquals(400, responseReuseExceeded.getStatusCode());
setTimeOffset(6);
// Finally try with valid refresh token
responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password");
assertEquals(200, responseReuseExceeded.getStatusCode());
@ -689,36 +712,39 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
RealmResource realmResource = adminClient.realm("test");
int lastAccessTokenLifespan = realmResource.toRepresentation().getAccessTokenLifespan();
RealmManager.realm(realmResource).accessTokenLifespan(100000);
setTimeOffset(4);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
next = testingClient.testing().getLastSessionRefresh("test", sessionId, false);
// lastSEssionRefresh should be updated because access code lifespan is higher than sso idle timeout
Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 50)));
int originalIdle = realmResource.toRepresentation().getSsoSessionIdleTimeout();
RealmManager.realm(realmResource).ssoSessionIdleTimeout(1);
events.clear();
// Needs to add some additional time due the tollerance allowed by IDLE_TIMEOUT_WINDOW_SECONDS
setTimeOffset(6 + SessionTimeoutHelper.IDLE_TIMEOUT_WINDOW_SECONDS);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
try {
RealmManager.realm(realmResource).accessTokenLifespan(100000);
// test idle timeout
assertEquals(400, tokenResponse.getStatusCode());
assertNull(tokenResponse.getAccessToken());
assertNull(tokenResponse.getRefreshToken());
setTimeOffset(4);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
next = testingClient.testing().getLastSessionRefresh("test", sessionId, false);
RealmManager.realm(realmResource).ssoSessionIdleTimeout(originalIdle).accessTokenLifespan(lastAccessTokenLifespan);
// lastSEssionRefresh should be updated because access code lifespan is higher than sso idle timeout
Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 50)));
events.clear();
RealmManager.realm(realmResource).ssoSessionIdleTimeout(1);
events.clear();
// Needs to add some additional time due the tollerance allowed by IDLE_TIMEOUT_WINDOW_SECONDS
setTimeOffset(6 + SessionTimeoutHelper.IDLE_TIMEOUT_WINDOW_SECONDS);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
// test idle timeout
assertEquals(400, tokenResponse.getStatusCode());
assertNull(tokenResponse.getAccessToken());
assertNull(tokenResponse.getRefreshToken());
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
} finally {
RealmManager.realm(realmResource).ssoSessionIdleTimeout(originalIdle).accessTokenLifespan(lastAccessTokenLifespan);
events.clear();
setTimeOffset(0);
}
setTimeOffset(0);
}
@Test
@ -796,23 +822,23 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
RealmResource realmResource = adminClient.realm("test");
Integer maxLifespan = realmResource.toRepresentation().getSsoSessionMaxLifespan();
RealmManager.realm(realmResource).ssoSessionMaxLifespan(1);
try {
RealmManager.realm(realmResource).ssoSessionMaxLifespan(1);
setTimeOffset(1);
setTimeOffset(2);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
assertEquals(400, tokenResponse.getStatusCode());
assertNull(tokenResponse.getAccessToken());
assertNull(tokenResponse.getRefreshToken());
assertEquals(400, tokenResponse.getStatusCode());
assertNull(tokenResponse.getAccessToken());
assertNull(tokenResponse.getRefreshToken());
RealmManager.realm(realmResource).ssoSessionMaxLifespan(maxLifespan);
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
events.clear();
setTimeOffset(0);
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
} finally {
RealmManager.realm(realmResource).ssoSessionMaxLifespan(maxLifespan);
events.clear();
resetTimeOffset();
}
}
/**
@ -869,57 +895,59 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
@Test
public void testCheckSsl() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
URI uri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget refreshTarget = client.target(uri);
try {
UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
URI uri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget refreshTarget = client.target(uri);
String refreshToken = null;
{
Response response = executeGrantAccessTokenRequest(grantTarget);
assertEquals(200, response.getStatus());
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
refreshToken = tokenResponse.getRefreshToken();
response.close();
}
{
Response response = executeRefreshToken(refreshTarget, refreshToken);
assertEquals(200, response.getStatus());
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
refreshToken = tokenResponse.getRefreshToken();
response.close();
}
if (!AUTH_SERVER_SSL_REQUIRED) { // test checkSsl
RealmResource realmResource = adminClient.realm("test");
String refreshToken = null;
{
RealmManager.realm(realmResource).sslRequired(SslRequired.ALL.toString());
Response response = executeGrantAccessTokenRequest(grantTarget);
assertEquals(200, response.getStatus());
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
refreshToken = tokenResponse.getRefreshToken();
response.close();
}
Response response = executeRefreshToken(refreshTarget, refreshToken);
assertEquals(403, response.getStatus());
response.close();
{
Response response = executeRefreshToken(refreshTarget, refreshToken);
assertEquals(200, response.getStatus());
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
refreshToken = tokenResponse.getRefreshToken();
response.close();
}
if (!AUTH_SERVER_SSL_REQUIRED) { // test checkSsl
RealmResource realmResource = adminClient.realm("test");
{
RealmManager.realm(realmResource).sslRequired(SslRequired.ALL.toString());
}
Response response = executeRefreshToken(refreshTarget, refreshToken);
assertEquals(403, response.getStatus());
response.close();
{
RealmManager.realm(realmResource).sslRequired(SslRequired.EXTERNAL.toString());
}
}
{
RealmManager.realm(realmResource).sslRequired(SslRequired.EXTERNAL.toString());
Response response = executeRefreshToken(refreshTarget, refreshToken);
assertEquals(200, response.getStatus());
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
refreshToken = tokenResponse.getRefreshToken();
response.close();
}
} finally {
client.close();
resetTimeOffset();
events.clear();
}
{
Response response = executeRefreshToken(refreshTarget, refreshToken);
assertEquals(200, response.getStatus());
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
refreshToken = tokenResponse.getRefreshToken();
response.close();
}
client.close();
events.clear();
}
@Test
@ -941,6 +969,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
try {
UserManager.realm(adminClient.realm("test")).username("test-user@localhost").enabled(false);
setTimeOffset(2);
response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
assertEquals(400, response.getStatusCode());
assertEquals("invalid_grant", response.getError());
@ -970,6 +999,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectCodeToToken(codeId, sessionId).user(userId).assertEvent();
adminClient.realm("test").users().delete(userId);
setTimeOffset(2);
response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
assertEquals(400, response.getStatusCode());
assertEquals("invalid_grant", response.getError());