Fix offline servlets and refactoring
This commit is contained in:
parent
af7fd0ef61
commit
22a94100c8
4 changed files with 73 additions and 42 deletions
|
@ -6,12 +6,16 @@ import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
|
import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
|
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
|
||||||
*/
|
*/
|
||||||
|
@ -56,4 +60,11 @@ public class OfflineToken extends AbstractPageWithInjectedUrl {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void logout() {
|
||||||
|
log.info("Logging out, navigating to: " + getUriBuilder().path("/logout").build().toASCIIString());
|
||||||
|
driver.navigate().to(getUriBuilder().path("/logout").build().toASCIIString());
|
||||||
|
pause(300); // this is needed for FF for some reason
|
||||||
|
waitUntilElement(By.tagName("body")).is().visible();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,8 +21,12 @@ import java.io.IOException;
|
||||||
*/
|
*/
|
||||||
public class OfflineTokenServlet extends HttpServlet {
|
public class OfflineTokenServlet extends HttpServlet {
|
||||||
|
|
||||||
private static final String OFFLINE_CLIENT_APP_URI = "http://localhost:8280/offline-client";
|
private static final String OFFLINE_CLIENT_APP_URI = (System.getProperty("app.server.ssl.required", "false").equals("true")) ?
|
||||||
private static final String ADAPTER_ROOT_URL = "http://localhost:8180";
|
System.getProperty("app.server.ssl.base.url", "https://localhost:8643") + "/offline-client" :
|
||||||
|
System.getProperty("app.server.base.url", "http://localhost:8280") + "/offline-client";
|
||||||
|
private static final String ADAPTER_ROOT_URL = (System.getProperty("auth.server.ssl.required", "false").equals("true")) ?
|
||||||
|
System.getProperty("auth.server.ssl.base.url", "https://localhost:8543") :
|
||||||
|
System.getProperty("auth.server.base.url", "http://localhost:8180");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
|
|
@ -7,7 +7,6 @@ import org.junit.Assert;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.events.Details;
|
import org.keycloak.events.Details;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
@ -19,24 +18,27 @@ import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||||
import org.keycloak.testsuite.util.ClientManager;
|
import org.keycloak.testsuite.util.ClientManager;
|
||||||
import org.keycloak.util.TokenUtil;
|
import org.keycloak.util.TokenUtil;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||||
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
||||||
|
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.waitUntilElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
|
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractOfflineServletsAdapterTest extends AbstractServletsAdapterTest {
|
public abstract class AbstractOfflineServletsAdapterTest extends AbstractServletsAdapterTest {
|
||||||
|
|
||||||
private static final String OFFLINE_CLIENT_APP_URI = "http://localhost:8280/offline-client";
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public AssertEvents events = new AssertEvents(this);
|
public AssertEvents events = new AssertEvents(this);
|
||||||
@Page
|
@Page
|
||||||
protected OfflineToken offlineToken;
|
protected OfflineToken offlineTokenPage;
|
||||||
@Page
|
@Page
|
||||||
protected LoginPage loginPage;
|
protected LoginPage loginPage;
|
||||||
@Page
|
@Page
|
||||||
|
@ -64,74 +66,80 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServlet() throws Exception {
|
public void testServlet() throws Exception {
|
||||||
String servletUri = UriBuilder.fromUri(OFFLINE_CLIENT_APP_URI)
|
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
|
||||||
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
|
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
|
||||||
.build().toString();
|
.build().toString();
|
||||||
oauth.doLogin("test-user@localhost", "password");
|
|
||||||
|
|
||||||
driver.navigate().to(servletUri);
|
driver.navigate().to(servletUri);
|
||||||
|
waitUntilElement(By.tagName("body")).is().visible();
|
||||||
|
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(OFFLINE_CLIENT_APP_URI));
|
loginPage.login("test-user@localhost", "password");
|
||||||
|
|
||||||
Assert.assertEquals(offlineToken.getRefreshToken().getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
|
assertCurrentUrlStartsWith(offlineTokenPage);
|
||||||
Assert.assertEquals(offlineToken.getRefreshToken().getExpiration(), 0);
|
|
||||||
|
|
||||||
String accessTokenId = offlineToken.getAccessToken().getId();
|
Assert.assertEquals(offlineTokenPage.getRefreshToken().getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
|
||||||
String refreshTokenId = offlineToken.getRefreshToken().getId();
|
Assert.assertEquals(offlineTokenPage.getRefreshToken().getExpiration(), 0);
|
||||||
|
|
||||||
setAdapterTimeOffset(9999);
|
String accessTokenId = offlineTokenPage.getAccessToken().getId();
|
||||||
|
String refreshTokenId = offlineTokenPage.getRefreshToken().getId();
|
||||||
|
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(OFFLINE_CLIENT_APP_URI));
|
setAdapterAndServerTimeOffset(9999);
|
||||||
Assert.assertNotEquals(offlineToken.getRefreshToken().getId(), refreshTokenId);
|
|
||||||
Assert.assertNotEquals(offlineToken.getAccessToken().getId(), accessTokenId);
|
assertCurrentUrlStartsWith(offlineTokenPage);
|
||||||
|
Assert.assertNotEquals(offlineTokenPage.getRefreshToken().getId(), refreshTokenId);
|
||||||
|
Assert.assertNotEquals(offlineTokenPage.getAccessToken().getId(), accessTokenId);
|
||||||
|
|
||||||
// Ensure that logout works for webapp (even if offline token will be still valid in Keycloak DB)
|
// Ensure that logout works for webapp (even if offline token will be still valid in Keycloak DB)
|
||||||
driver.navigate().to(OFFLINE_CLIENT_APP_URI + "/logout");
|
offlineTokenPage.logout();
|
||||||
loginPage.assertCurrent();
|
loginPage.assertCurrent();
|
||||||
driver.navigate().to(OFFLINE_CLIENT_APP_URI);
|
offlineTokenPage.navigateTo();
|
||||||
loginPage.assertCurrent();
|
loginPage.assertCurrent();
|
||||||
|
|
||||||
setAdapterTimeOffset(0);
|
setAdapterAndServerTimeOffset(0);
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServletWithRevoke() {
|
public void testServletWithRevoke() {
|
||||||
// Login to servlet first with offline token
|
// Login to servlet first with offline token
|
||||||
String servletUri = UriBuilder.fromUri(OFFLINE_CLIENT_APP_URI)
|
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
|
||||||
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
|
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
|
||||||
.build().toString();
|
.build().toString();
|
||||||
driver.navigate().to(servletUri);
|
driver.navigate().to(servletUri);
|
||||||
loginPage.login("test-user@localhost", "password");
|
waitUntilElement(By.tagName("body")).is().visible();
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(OFFLINE_CLIENT_APP_URI));
|
|
||||||
|
|
||||||
Assert.assertEquals(offlineToken.getRefreshToken().getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
|
loginPage.login("test-user@localhost", "password");
|
||||||
|
assertCurrentUrlStartsWith(offlineTokenPage);
|
||||||
|
|
||||||
|
Assert.assertEquals(offlineTokenPage.getRefreshToken().getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
|
||||||
|
|
||||||
// Assert refresh works with increased time
|
// Assert refresh works with increased time
|
||||||
setAdapterTimeOffset(9999);
|
setAdapterAndServerTimeOffset(9999);
|
||||||
driver.navigate().to(OFFLINE_CLIENT_APP_URI);
|
offlineTokenPage.navigateTo();
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(OFFLINE_CLIENT_APP_URI));
|
assertCurrentUrlStartsWith(offlineTokenPage);
|
||||||
setAdapterTimeOffset(0);
|
setAdapterAndServerTimeOffset(0);
|
||||||
|
|
||||||
events.clear();
|
events.clear();
|
||||||
|
|
||||||
// Go to account service and revoke grant
|
// Go to account service and revoke grant
|
||||||
accountAppPage.open();
|
accountAppPage.open();
|
||||||
|
|
||||||
List<String> additionalGrants = accountAppPage.getApplications().get("offline-client").getAdditionalGrants();
|
List<String> additionalGrants = accountAppPage.getApplications().get("offline-client").getAdditionalGrants();
|
||||||
Assert.assertEquals(additionalGrants.size(), 1);
|
Assert.assertEquals(additionalGrants.size(), 1);
|
||||||
Assert.assertEquals(additionalGrants.get(0), "Offline Token");
|
Assert.assertEquals(additionalGrants.get(0), "Offline Token");
|
||||||
accountAppPage.revokeGrant("offline-client");
|
accountAppPage.revokeGrant("offline-client");
|
||||||
|
pause(500);
|
||||||
Assert.assertEquals(accountAppPage.getApplications().get("offline-client").getAdditionalGrants().size(), 0);
|
Assert.assertEquals(accountAppPage.getApplications().get("offline-client").getAdditionalGrants().size(), 0);
|
||||||
|
|
||||||
events.expect(EventType.REVOKE_GRANT)
|
events.expect(EventType.REVOKE_GRANT)
|
||||||
.client("account").detail(Details.REVOKED_CLIENT, "offline-client").assertEvent();
|
.client("account").detail(Details.REVOKED_CLIENT, "offline-client").assertEvent();
|
||||||
|
|
||||||
// Assert refresh doesn't work now (increase time one more time)
|
// Assert refresh doesn't work now (increase time one more time)
|
||||||
setAdapterTimeOffset(9999);
|
setAdapterAndServerTimeOffset(9999);
|
||||||
driver.navigate().to(OFFLINE_CLIENT_APP_URI);
|
offlineTokenPage.navigateTo();
|
||||||
Assert.assertFalse(driver.getCurrentUrl().startsWith(OFFLINE_CLIENT_APP_URI));
|
assertCurrentUrlDoesntStartWith(offlineTokenPage);
|
||||||
loginPage.assertCurrent();
|
loginPage.assertCurrent();
|
||||||
setAdapterTimeOffset(0);
|
setAdapterAndServerTimeOffset(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -139,24 +147,27 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
|
||||||
ClientManager.realm(adminClient.realm("test")).clientId("offline-client").consentRequired(true);
|
ClientManager.realm(adminClient.realm("test")).clientId("offline-client").consentRequired(true);
|
||||||
|
|
||||||
// Assert grant page doesn't have 'Offline Access' role when offline token is not requested
|
// Assert grant page doesn't have 'Offline Access' role when offline token is not requested
|
||||||
driver.navigate().to(OFFLINE_CLIENT_APP_URI);
|
offlineTokenPage.navigateTo();
|
||||||
loginPage.login("test-user@localhost", "password");
|
loginPage.login("test-user@localhost", "password");
|
||||||
oauthGrantPage.assertCurrent();
|
oauthGrantPage.assertCurrent();
|
||||||
Assert.assertFalse(driver.getPageSource().contains("Offline access"));
|
waitUntilElement(By.xpath("//body")).text().not().contains("Offline access");
|
||||||
oauthGrantPage.cancel();
|
oauthGrantPage.cancel();
|
||||||
|
|
||||||
// Assert grant page has 'Offline Access' role now
|
// Assert grant page has 'Offline Access' role now
|
||||||
String servletUri = UriBuilder.fromUri(OFFLINE_CLIENT_APP_URI)
|
String servletUri = UriBuilder.fromUri(offlineTokenPage.toString())
|
||||||
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
|
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.OFFLINE_ACCESS)
|
||||||
.build().toString();
|
.build().toString();
|
||||||
driver.navigate().to(servletUri);
|
driver.navigate().to(servletUri);
|
||||||
|
waitUntilElement(By.tagName("body")).is().visible();
|
||||||
|
|
||||||
loginPage.login("test-user@localhost", "password");
|
loginPage.login("test-user@localhost", "password");
|
||||||
oauthGrantPage.assertCurrent();
|
oauthGrantPage.assertCurrent();
|
||||||
Assert.assertTrue(driver.getPageSource().contains("Offline access"));
|
waitUntilElement(By.xpath("//body")).text().contains("Offline access");
|
||||||
|
|
||||||
oauthGrantPage.accept();
|
oauthGrantPage.accept();
|
||||||
|
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(OFFLINE_CLIENT_APP_URI));
|
assertCurrentUrlStartsWith(offlineTokenPage);
|
||||||
Assert.assertEquals(offlineToken.getRefreshToken().getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
|
Assert.assertEquals(offlineTokenPage.getRefreshToken().getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
|
||||||
|
|
||||||
accountAppPage.open();
|
accountAppPage.open();
|
||||||
AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get("offline-client");
|
AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get("offline-client");
|
||||||
|
@ -164,7 +175,7 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
|
||||||
Assert.assertTrue(offlineClient.getAdditionalGrants().contains("Offline Token"));
|
Assert.assertTrue(offlineClient.getAdditionalGrants().contains("Offline Token"));
|
||||||
|
|
||||||
//This was necessary to be introduced, otherwise other testcases will fail
|
//This was necessary to be introduced, otherwise other testcases will fail
|
||||||
driver.navigate().to(OFFLINE_CLIENT_APP_URI + "/logout");
|
offlineTokenPage.logout();
|
||||||
loginPage.assertCurrent();
|
loginPage.assertCurrent();
|
||||||
|
|
||||||
events.clear();
|
events.clear();
|
||||||
|
@ -174,13 +185,15 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAdapterTimeOffset(int timeOffset) {
|
private void setAdapterAndServerTimeOffset(int timeOffset) {
|
||||||
Time.setOffset(timeOffset);
|
setTimeOffset(timeOffset);
|
||||||
String timeOffsetUri = UriBuilder.fromUri(OFFLINE_CLIENT_APP_URI)
|
String timeOffsetUri = UriBuilder.fromUri(offlineTokenPage.toString())
|
||||||
.queryParam("timeOffset", timeOffset)
|
.queryParam("timeOffset", timeOffset)
|
||||||
.build().toString();
|
.build().toString();
|
||||||
|
|
||||||
driver.navigate().to(timeOffsetUri);
|
driver.navigate().to(timeOffsetUri);
|
||||||
|
waitUntilElement(By.tagName("body")).is().visible();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,11 @@
|
||||||
|
|
||||||
<adapter.test.props>
|
<adapter.test.props>
|
||||||
-Dapp.server.base.url=http://localhost:${app.server.http.port}
|
-Dapp.server.base.url=http://localhost:${app.server.http.port}
|
||||||
|
-Dauth.server.base.url=http://localhost:${auth.server.http.port}
|
||||||
-Dapp.server.ssl.base.url=https://localhost:${app.server.https.port}
|
-Dapp.server.ssl.base.url=https://localhost:${app.server.https.port}
|
||||||
-Dapp.server.ssl.required=${app.server.ssl.required}
|
-Dapp.server.ssl.required=${app.server.ssl.required}
|
||||||
|
-Dauth.server.ssl.base.url=https://localhost:${auth.server.https.port}
|
||||||
|
-Dauth.server.ssl.required=${auth.server.ssl.required}
|
||||||
-Dmy.host.name=localhost
|
-Dmy.host.name=localhost
|
||||||
-Djava.security.krb5.conf=${project.build.directory}/dependency/kerberos/test-krb5.conf
|
-Djava.security.krb5.conf=${project.build.directory}/dependency/kerberos/test-krb5.conf
|
||||||
</adapter.test.props>
|
</adapter.test.props>
|
||||||
|
|
Loading…
Reference in a new issue