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.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.federation.storage.ComponentExportImportTest;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.runonserver.RunOnServerDeployment; import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
import org.keycloak.testsuite.util.ClientManager; 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.RealmManager;
import org.keycloak.testsuite.util.TokenSignatureUtil; import org.keycloak.testsuite.util.TokenSignatureUtil;
import org.keycloak.testsuite.util.UserManager; import org.keycloak.testsuite.util.UserManager;
import org.keycloak.testsuite.util.WaitUtils;
import org.keycloak.util.BasicAuthHelper; import org.keycloak.util.BasicAuthHelper;
import javax.ws.rs.client.Client; import javax.ws.rs.client.Client;
@ -245,6 +245,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password"); OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
String accessTokenString = tokenResponse.getAccessToken(); String accessTokenString = tokenResponse.getAccessToken();
setTimeOffset(2);
OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(accessTokenString, "password"); OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(accessTokenString, "password");
Assert.assertNotEquals(200, response.getStatusCode()); Assert.assertNotEquals(200, response.getStatusCode());
@ -274,6 +275,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(refreshToken1.getId(), sessionId).assertEvent(); events.expectRefresh(refreshToken1.getId(), sessionId).assertEvent();
setTimeOffset(4);
OAuthClient.AccessTokenResponse response3 = oauth.doRefreshTokenRequest(response1.getRefreshToken(), "password"); OAuthClient.AccessTokenResponse response3 = oauth.doRefreshTokenRequest(response1.getRefreshToken(), "password");
assertEquals(200, response3.getStatusCode()); assertEquals(200, response3.getStatusCode());
@ -313,12 +316,15 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(refreshToken1.getId(), sessionId).assertEvent(); events.expectRefresh(refreshToken1.getId(), sessionId).assertEvent();
setTimeOffset(4);
OAuthClient.AccessTokenResponse response3 = oauth.doRefreshTokenRequest(response1.getRefreshToken(), "password"); OAuthClient.AccessTokenResponse response3 = oauth.doRefreshTokenRequest(response1.getRefreshToken(), "password");
assertEquals(400, response3.getStatusCode()); assertEquals(400, response3.getStatusCode());
events.expectRefresh(refreshToken1.getId(), sessionId).removeDetail(Details.TOKEN_ID).removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent(); 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"); oauth.doRefreshTokenRequest(response2.getRefreshToken(), "password");
events.expectRefresh(refreshToken2.getId(), sessionId).assertEvent(); events.expectRefresh(refreshToken2.getId(), sessionId).assertEvent();
@ -369,6 +375,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(initialRefreshToken.getId(), sessionId).assertEvent(); events.expectRefresh(initialRefreshToken.getId(), sessionId).assertEvent();
setTimeOffset(6);
// Token reused twice, became invalid. // Token reused twice, became invalid.
OAuthClient.AccessTokenResponse responseSecondReuse = oauth.doRefreshTokenRequest(initialResponse.getRefreshToken(), "password"); 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) events.expectRefresh(initialRefreshToken.getId(), sessionId).removeDetail(Details.TOKEN_ID)
.removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent(); .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent();
setTimeOffset(8);
// Refresh token from first use became invalid. // Refresh token from first use became invalid.
OAuthClient.AccessTokenResponse responseUseOfInvalidatedRefreshToken = OAuthClient.AccessTokenResponse responseUseOfInvalidatedRefreshToken =
oauth.doRefreshTokenRequest(responseFirstUse.getRefreshToken(), "password"); oauth.doRefreshTokenRequest(responseFirstUse.getRefreshToken(), "password");
@ -386,6 +394,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(newTokenFirstUse.getId(), sessionId).removeDetail(Details.TOKEN_ID) events.expectRefresh(newTokenFirstUse.getId(), sessionId).removeDetail(Details.TOKEN_ID)
.removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent(); .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID).error("invalid_token").assertEvent();
setTimeOffset(10);
// Refresh token from reuse is still valid. // Refresh token from reuse is still valid.
OAuthClient.AccessTokenResponse responseUseOfValidRefreshToken = OAuthClient.AccessTokenResponse responseUseOfValidRefreshToken =
oauth.doRefreshTokenRequest(responseFirstReuse.getRefreshToken(), "password"); oauth.doRefreshTokenRequest(responseFirstReuse.getRefreshToken(), "password");
@ -522,6 +531,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
try { try {
ClientManager.realm(adminClient.realm("test")).clientId(oauth.getClientId()).enabled(false); ClientManager.realm(adminClient.realm("test")).clientId(oauth.getClientId()).enabled(false);
setTimeOffset(2);
response = oauth.doRefreshTokenRequest(refreshTokenString, "password"); response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
assertEquals(400, response.getStatusCode()); assertEquals(400, response.getStatusCode());
@ -550,6 +560,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
testingClient.testing().removeUserSession("test", sessionId); testingClient.testing().removeUserSession("test", sessionId);
setTimeOffset(2);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password"); tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
assertEquals(400, tokenResponse.getStatusCode()); assertEquals(400, tokenResponse.getStatusCode());
@ -580,10 +591,12 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
tokenResponse2 = oauth.doAccessTokenRequest(code, "password"); tokenResponse2 = oauth.doAccessTokenRequest(code, "password");
setTimeOffset(4);
// Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail // Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail
OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password"); OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password");
assertEquals(400, responseReuseExceeded.getStatusCode()); assertEquals(400, responseReuseExceeded.getStatusCode());
setTimeOffset(6);
// Finally try with valid refresh token // Finally try with valid refresh token
responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password"); responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password");
assertEquals(200, responseReuseExceeded.getStatusCode()); assertEquals(200, responseReuseExceeded.getStatusCode());
@ -594,6 +607,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String refreshToken1 = loginAndForceNewLoginPage(); String refreshToken1 = loginAndForceNewLoginPage();
adminClient.realm("test").logoutAll(); 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(); events.clear();
@ -609,10 +624,14 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
tokenResponse2 = oauth.doAccessTokenRequest(code, "password"); tokenResponse2 = oauth.doAccessTokenRequest(code, "password");
setTimeOffset(4);
// Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail // Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail
OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password"); OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password");
assertEquals(400, responseReuseExceeded.getStatusCode()); assertEquals(400, responseReuseExceeded.getStatusCode());
setTimeOffset(6);
// Finally try with valid refresh token // Finally try with valid refresh token
responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password"); responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password");
assertEquals(200, responseReuseExceeded.getStatusCode()); assertEquals(200, responseReuseExceeded.getStatusCode());
@ -640,10 +659,14 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
tokenResponse2 = oauth.doAccessTokenRequest(code, "password"); tokenResponse2 = oauth.doAccessTokenRequest(code, "password");
setTimeOffset(4);
// Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail // Now try refresh with the original refreshToken1 created in logged-out userSession. It should fail
OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password"); OAuthClient.AccessTokenResponse responseReuseExceeded = oauth.doRefreshTokenRequest(refreshToken1, "password");
assertEquals(400, responseReuseExceeded.getStatusCode()); assertEquals(400, responseReuseExceeded.getStatusCode());
setTimeOffset(6);
// Finally try with valid refresh token // Finally try with valid refresh token
responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password"); responseReuseExceeded = oauth.doRefreshTokenRequest(tokenResponse2.getRefreshToken(), "password");
assertEquals(200, responseReuseExceeded.getStatusCode()); assertEquals(200, responseReuseExceeded.getStatusCode());
@ -689,6 +712,9 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
RealmResource realmResource = adminClient.realm("test"); RealmResource realmResource = adminClient.realm("test");
int lastAccessTokenLifespan = realmResource.toRepresentation().getAccessTokenLifespan(); int lastAccessTokenLifespan = realmResource.toRepresentation().getAccessTokenLifespan();
int originalIdle = realmResource.toRepresentation().getSsoSessionIdleTimeout();
try {
RealmManager.realm(realmResource).accessTokenLifespan(100000); RealmManager.realm(realmResource).accessTokenLifespan(100000);
setTimeOffset(4); setTimeOffset(4);
@ -699,7 +725,6 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
// lastSEssionRefresh should be updated because access code lifespan is higher than sso idle timeout // lastSEssionRefresh should be updated because access code lifespan is higher than sso idle timeout
Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 50))); Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 50)));
int originalIdle = realmResource.toRepresentation().getSsoSessionIdleTimeout();
RealmManager.realm(realmResource).ssoSessionIdleTimeout(1); RealmManager.realm(realmResource).ssoSessionIdleTimeout(1);
events.clear(); events.clear();
@ -714,13 +739,14 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN); events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
} finally {
RealmManager.realm(realmResource).ssoSessionIdleTimeout(originalIdle).accessTokenLifespan(lastAccessTokenLifespan); RealmManager.realm(realmResource).ssoSessionIdleTimeout(originalIdle).accessTokenLifespan(lastAccessTokenLifespan);
events.clear(); events.clear();
setTimeOffset(0); setTimeOffset(0);
} }
}
@Test @Test
public void testUserSessionRefreshAndIdleRememberMe() throws Exception { public void testUserSessionRefreshAndIdleRememberMe() throws Exception {
RealmResource testRealm = adminClient.realm("test"); RealmResource testRealm = adminClient.realm("test");
@ -796,9 +822,10 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
RealmResource realmResource = adminClient.realm("test"); RealmResource realmResource = adminClient.realm("test");
Integer maxLifespan = realmResource.toRepresentation().getSsoSessionMaxLifespan(); Integer maxLifespan = realmResource.toRepresentation().getSsoSessionMaxLifespan();
try {
RealmManager.realm(realmResource).ssoSessionMaxLifespan(1); RealmManager.realm(realmResource).ssoSessionMaxLifespan(1);
setTimeOffset(1); setTimeOffset(2);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password"); tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
@ -806,13 +833,12 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
assertNull(tokenResponse.getAccessToken()); assertNull(tokenResponse.getAccessToken());
assertNull(tokenResponse.getRefreshToken()); assertNull(tokenResponse.getRefreshToken());
RealmManager.realm(realmResource).ssoSessionMaxLifespan(maxLifespan);
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN); events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
} finally {
RealmManager.realm(realmResource).ssoSessionMaxLifespan(maxLifespan);
events.clear(); events.clear();
resetTimeOffset();
setTimeOffset(0); }
} }
/** /**
@ -869,6 +895,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
@Test @Test
public void testCheckSsl() throws Exception { public void testCheckSsl() throws Exception {
Client client = ClientBuilder.newClient(); Client client = ClientBuilder.newClient();
try {
UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT); UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test"); URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri); WebTarget grantTarget = client.target(grantUri);
@ -915,10 +942,11 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
refreshToken = tokenResponse.getRefreshToken(); refreshToken = tokenResponse.getRefreshToken();
response.close(); response.close();
} }
} finally {
client.close(); client.close();
resetTimeOffset();
events.clear(); events.clear();
}
} }
@ -941,6 +969,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
try { try {
UserManager.realm(adminClient.realm("test")).username("test-user@localhost").enabled(false); UserManager.realm(adminClient.realm("test")).username("test-user@localhost").enabled(false);
setTimeOffset(2);
response = oauth.doRefreshTokenRequest(refreshTokenString, "password"); response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
assertEquals(400, response.getStatusCode()); assertEquals(400, response.getStatusCode());
assertEquals("invalid_grant", response.getError()); assertEquals("invalid_grant", response.getError());
@ -970,6 +999,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
events.expectCodeToToken(codeId, sessionId).user(userId).assertEvent(); events.expectCodeToToken(codeId, sessionId).user(userId).assertEvent();
adminClient.realm("test").users().delete(userId); adminClient.realm("test").users().delete(userId);
setTimeOffset(2);
response = oauth.doRefreshTokenRequest(refreshTokenString, "password"); response = oauth.doRefreshTokenRequest(refreshTokenString, "password");
assertEquals(400, response.getStatusCode()); assertEquals(400, response.getStatusCode());
assertEquals("invalid_grant", response.getError()); assertEquals("invalid_grant", response.getError());