KEYCLOAK-17457 Failed OfflineServletsAdapterTest

This commit is contained in:
Martin Bartoš 2021-04-19 15:38:14 +02:00 committed by Pedro Igor
parent 1e2db74d86
commit ca019c36e8
3 changed files with 157 additions and 100 deletions

View file

@ -12,8 +12,9 @@ import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
/**
* Updater for client attributes. See {@link ServerResourceUpdater} for further details.

View file

@ -214,15 +214,19 @@ public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
setTimeOffset(timeOffset);
for (String servletUri : servletUris) {
String timeOffsetUri = UriBuilder.fromUri(servletUri)
.queryParam(AdapterActionsFilter.TIME_OFFSET_PARAM, timeOffset)
.build().toString();
DroneUtils.getCurrentDriver().navigate().to(timeOffsetUri);
waitForPageToLoad();
String pageSource = DroneUtils.getCurrentDriver().getPageSource();
System.out.println(pageSource);
setAdapterServletTimeOffset(timeOffset, servletUri);
}
}
protected void setAdapterServletTimeOffset(int timeOffset, String servletUri) {
String timeOffsetUri = UriBuilder.fromUri(servletUri)
.queryParam(AdapterActionsFilter.TIME_OFFSET_PARAM, timeOffset)
.build().toString();
DroneUtils.getCurrentDriver().navigate().to(timeOffsetUri);
waitForPageToLoad();
String pageSource = DroneUtils.getCurrentDriver().getPageSource();
log.info(pageSource);
}
}

View file

@ -5,7 +5,6 @@ import java.util.List;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
@ -19,20 +18,29 @@ import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
import org.keycloak.testsuite.adapter.page.OfflineToken;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
import org.keycloak.testsuite.pages.AccountApplicationsPage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.OAuthGrantPage;
import org.keycloak.testsuite.util.ClientManager;
import org.keycloak.testsuite.utils.io.IOUtil;
import org.keycloak.util.TokenUtil;
import org.hamcrest.Matchers;
import org.openqa.selenium.By;
import java.io.Closeable;
import java.io.IOException;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
/**
@ -58,6 +66,10 @@ public class OfflineServletsAdapterTest extends AbstractServletsAdapterTest {
@Page
protected OAuthGrantPage oauthGrantPage;
private final String DEFAULT_USERNAME = "test-user@localhost";
private final String DEFAULT_PASSWORD = "password";
private final String OFFLINE_CLIENT_ID = "offline-client";
@Deployment(name = OfflineToken.DEPLOYMENT_NAME)
protected static WebArchive offlineClient() {
return servletDeployment(OfflineToken.DEPLOYMENT_NAME, AdapterActionsFilter.class, AbstractShowTokensServlet.class, OfflineTokenServlet.class, ErrorServlet.class, ServletTestUtils.class);
@ -77,131 +89,171 @@ public class OfflineServletsAdapterTest extends AbstractServletsAdapterTest {
}
@Test
public void testServlet() throws Exception {
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
.build().toString();
public void testServlet() {
try {
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
.build().toString();
driver.navigate().to(servletUri);
waitUntilElement(By.tagName("body")).is().visible();
driver.navigate().to(servletUri);
waitUntilElement(By.tagName("body")).is().visible();
loginPage.login("test-user@localhost", "password");
loginPage.assertCurrent();
loginPage.login(DEFAULT_USERNAME, DEFAULT_PASSWORD);
assertCurrentUrlStartsWith(offlineTokenPage);
assertCurrentUrlStartsWith(offlineTokenPage);
Assert.assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineTokenPage.getRefreshToken().getType());
Assert.assertEquals(0, offlineTokenPage.getRefreshToken().getExpiration());
assertThat(offlineTokenPage.getRefreshToken(), notNullValue());
assertThat(TokenUtil.TOKEN_TYPE_OFFLINE, is(offlineTokenPage.getRefreshToken().getType()));
assertThat(offlineTokenPage.getRefreshToken().getExp(), nullValue());
String accessTokenId = offlineTokenPage.getAccessToken().getId();
String refreshTokenId = offlineTokenPage.getRefreshToken().getId();
String accessTokenId = offlineTokenPage.getAccessToken().getId();
String refreshTokenId = offlineTokenPage.getRefreshToken().getId();
setAdapterAndServerTimeOffset(9999);
offlineTokenPage.navigateTo();
assertCurrentUrlStartsWith(offlineTokenPage);
Assert.assertNotEquals(offlineTokenPage.getRefreshToken().getId(), refreshTokenId);
Assert.assertNotEquals(offlineTokenPage.getAccessToken().getId(), accessTokenId);
setAdapterAndServerTimeOffset(9999);
offlineTokenPage.navigateTo();
assertCurrentUrlStartsWith(offlineTokenPage);
// Ensure that logout works for webapp (even if offline token will be still valid in Keycloak DB)
offlineTokenPage.logout();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
offlineTokenPage.navigateTo();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
assertThat(offlineTokenPage.getRefreshToken().getId(), not(refreshTokenId));
assertThat(offlineTokenPage.getAccessToken().getId(), not(accessTokenId));
setAdapterAndServerTimeOffset(0);
events.clear();
// Ensure that logout works for webapp (even if offline token will be still valid in Keycloak DB)
offlineTokenPage.logout();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
offlineTokenPage.navigateTo();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
} finally {
events.clear();
resetTimeOffsetAuthenticated();
}
}
@Test
public void testServletWithRevoke() {
// Login to servlet first with offline token
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
.build().toString();
driver.navigate().to(servletUri);
waitUntilElement(By.tagName("body")).is().visible();
try { // Login to servlet first with offline token
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
.build().toString();
loginPage.login("test-user@localhost", "password");
assertCurrentUrlStartsWith(offlineTokenPage);
driver.navigate().to(servletUri);
waitUntilElement(By.tagName("body")).is().visible();
Assert.assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineTokenPage.getRefreshToken().getType());
loginPage.assertCurrent();
loginPage.login(DEFAULT_USERNAME, DEFAULT_PASSWORD);
assertCurrentUrlStartsWith(offlineTokenPage);
// Assert refresh works with increased time
setAdapterAndServerTimeOffset(9999);
offlineTokenPage.navigateTo();
assertCurrentUrlStartsWith(offlineTokenPage);
setAdapterAndServerTimeOffset(0);
assertThat(offlineTokenPage.getRefreshToken(), notNullValue());
assertThat(offlineTokenPage.getRefreshToken().getType(), is(TokenUtil.TOKEN_TYPE_OFFLINE));
events.clear();
// Assert refresh works with increased time
setAdapterAndServerTimeOffset(9999);
offlineTokenPage.navigateTo();
assertCurrentUrlStartsWith(offlineTokenPage);
setAdapterAndServerTimeOffset(0);
// Go to account service and revoke grant
accountAppPage.open();
events.clear();
List<String> additionalGrants = accountAppPage.getApplications().get("offline-client").getAdditionalGrants();
Assert.assertEquals(1, additionalGrants.size());
Assert.assertEquals("Offline Token", additionalGrants.get(0));
accountAppPage.revokeGrant("offline-client");
pause(500);
Assert.assertEquals(0, accountAppPage.getApplications().get("offline-client").getAdditionalGrants().size());
// Go to account service and revoke grant
accountAppPage.open();
events.expect(EventType.REVOKE_GRANT)
.client("account").detail(Details.REVOKED_CLIENT, "offline-client").assertEvent();
List<String> additionalGrants = accountAppPage.getApplications().get(OFFLINE_CLIENT_ID).getAdditionalGrants();
assertThat(additionalGrants.size(), is(1));
assertThat(additionalGrants.get(0), is("Offline Token"));
// Assert refresh doesn't work now (increase time one more time)
setAdapterAndServerTimeOffset(19999);
offlineTokenPage.navigateTo();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
setAdapterAndServerTimeOffset(0);
accountAppPage.revokeGrant(OFFLINE_CLIENT_ID);
pause(500);
assertThat(accountAppPage.getApplications().get(OFFLINE_CLIENT_ID).getAdditionalGrants().size(), is(0));
events.expect(EventType.REVOKE_GRANT)
.client("account").detail(Details.REVOKED_CLIENT, OFFLINE_CLIENT_ID).assertEvent();
// Assert refresh doesn't work now (increase time one more time)
setAdapterAndServerTimeOffset(19999);
offlineTokenPage.navigateTo();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
} finally {
events.clear();
resetTimeOffsetAuthenticated();
}
}
@Test
public void testServletWithConsent() {
ClientManager.realm(adminClient.realm("test")).clientId("offline-client").consentRequired(true);
public void testServletWithConsent() throws IOException {
try (Closeable cau = ClientAttributeUpdater.forClient(adminClient, TEST, OFFLINE_CLIENT_ID)
.setConsentRequired(true).update()) {
// Assert grant page doesn't have 'Offline Access' role when offline token is not requested
offlineTokenPage.navigateTo();
loginPage.login("test-user@localhost", "password");
oauthGrantPage.assertCurrent();
waitUntilElement(By.xpath("//body")).text().not().contains("Offline access");
oauthGrantPage.cancel();
// Assert grant page doesn't have 'Offline Access' role when offline token is not requested
offlineTokenPage.navigateTo();
// Assert grant page has 'Offline Access' role now
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
.build().toString();
driver.navigate().to(servletUri);
waitUntilElement(By.tagName("body")).is().visible();
loginPage.assertCurrent();
loginPage.login(DEFAULT_USERNAME, DEFAULT_PASSWORD);
loginPage.login("test-user@localhost", "password");
oauthGrantPage.assertCurrent();
waitUntilElement(By.xpath("//body")).text().contains(OAuthGrantPage.OFFLINE_ACCESS_CONSENT_TEXT);
oauthGrantPage.assertCurrent();
waitUntilElement(By.xpath("//body")).text().not().contains("Offline access");
oauthGrantPage.cancel();
oauthGrantPage.accept();
// Assert grant page has 'Offline Access' role now
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
.build().toString();
driver.navigate().to(servletUri);
waitUntilElement(By.tagName("body")).is().visible();
assertCurrentUrlStartsWith(offlineTokenPage);
Assert.assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineTokenPage.getRefreshToken().getType());
loginPage.login(DEFAULT_USERNAME, DEFAULT_PASSWORD);
oauthGrantPage.assertCurrent();
waitUntilElement(By.xpath("//body")).text().contains(OAuthGrantPage.OFFLINE_ACCESS_CONSENT_TEXT);
accountAppPage.open();
AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get("offline-client");
Assert.assertThat(offlineClient.getClientScopesGranted(), Matchers.hasItem(OAuthGrantPage.OFFLINE_ACCESS_CONSENT_TEXT));
Assert.assertThat(offlineClient.getAdditionalGrants(), Matchers.hasItem("Offline Token"));
oauthGrantPage.accept();
//This was necessary to be introduced, otherwise other testcases will fail
offlineTokenPage.logout();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
assertCurrentUrlStartsWith(offlineTokenPage);
assertThat(offlineTokenPage.getRefreshToken(), notNullValue());
assertThat(offlineTokenPage.getRefreshToken().getType(), is(TokenUtil.TOKEN_TYPE_OFFLINE));
events.clear();
// Revert change
ClientManager.realm(adminClient.realm("test")).clientId("offline-client").consentRequired(false);
accountAppPage.open();
AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get(OFFLINE_CLIENT_ID);
assertThat(offlineClient.getClientScopesGranted(), Matchers.hasItem(OAuthGrantPage.OFFLINE_ACCESS_CONSENT_TEXT));
assertThat(offlineClient.getAdditionalGrants(), Matchers.hasItem("Offline Token"));
//This was necessary to be introduced, otherwise other testcases will fail
offlineTokenPage.logout();
assertCurrentUrlDoesntStartWith(offlineTokenPage);
loginPage.assertCurrent();
} finally {
events.clear();
resetTimeOffsetAuthenticated();
}
}
private void setAdapterAndServerTimeOffset(int timeOffset) {
super.setAdapterAndServerTimeOffset(timeOffset, offlineTokenPage.toString());
}
private void resetTimeOffsetAuthenticated() {
resetTimeOffsetAuthenticated(DEFAULT_USERNAME, DEFAULT_PASSWORD);
}
/**
* Reset time offset for remote environment.
* After the token expiration, process of re-authentication is necessary.
*
* @param username
* @param password
*/
private void resetTimeOffsetAuthenticated(String username, String password) {
if (testContext.getAppServerInfo().isUndertow()) {
setAdapterAndServerTimeOffset(0);
return;
}
super.setAdapterServletTimeOffset(0, offlineTokenPage.toString());
if (loginPage.isCurrent()) {
loginPage.login(username, password);
waitForPageToLoad();
offlineTokenPage.logout();
}
setTimeOffset(0);
}
}