KEYCLOAK-4368 Switch default WebDriver impl to htmlUnit

This commit is contained in:
mposolda 2017-01-31 14:49:54 +01:00
parent ec32acec27
commit f6bc0806d5
22 changed files with 691 additions and 224 deletions

View file

@ -53,6 +53,9 @@ import java.util.regex.Pattern;
* @version $Revision: 1 $
*/
public class KeycloakOIDCFilter implements Filter {
public static final String SKIP_PATTERN_PARAM = "keycloak.config.skipPattern";
protected AdapterDeploymentContext deploymentContext;
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
protected NodesRegistrationManagement nodesRegistrationManagement;
@ -63,7 +66,7 @@ public class KeycloakOIDCFilter implements Filter {
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
String skipPatternDefinition = filterConfig.getInitParameter("keycloak.config.skipPattern");
String skipPatternDefinition = filterConfig.getInitParameter(SKIP_PATTERN_PARAM);
if (skipPatternDefinition != null) {
skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
}

View file

@ -5,67 +5,101 @@ How To Run various testsuite configurations
It's recomended to build the workspace including distribution.
````
cd $KEYCLOAK_SOURCES
mvn clean install -DskipTests=true
cd distribution
mvn clean install
````
cd $KEYCLOAK_SOURCES
mvn clean install -DskipTests=true
cd distribution
mvn clean install
## Debugging - tips & tricks
### Arquillian debugging
Adding this system property when running any test:
-Darquillian.debug=true
will add lots of info to the log. Especially about all the triggered arquillian lifecycle events and executed observers listening to those events.
Also the bootstrap of WebDriver will be unlimited (by default there is 1 minute timeout and test is cancelled when WebDriver is not bootstrapped within it.)
### WebDriver timeout
By default, WebDriver has 10 seconds timeout to load every page and it timeouts with error after that. Use this to increase timeout to 1 hour instead:
-Dpageload.timeout=3600000
### Surefire debugging
For debugging, the best is to run the test from IDE and debug it directly. When you use embedded Undertow (which is by default), then JUnit test, Keycloak server
and adapter are all in the same JVM and you can debug them easily. If it is not an option and you are forced to test with Maven and Wildfly (or EAP), you can use this:
-Dmaven.surefire.debug=true
and you will be able to attach remote debugger to the test. Unfortunately server and adapter are running in different JVMs, so you won't be able to debug them.
TODO: Improve and add more info about Wildfly debugging...
## Run adapter tests
### Wildfly
````
# Prepare servers
mvn -f testsuite/integration-arquillian/servers/pom.xml clean install \
-Pauth-server-wildfly \
-Papp-server-wildfly
# Prepare servers
mvn -f testsuite/integration-arquillian/servers/pom.xml clean install \
-Pauth-server-wildfly \
-Papp-server-wildfly
# Run tests
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-wildfly
````
# Run tests
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-wildfly
### JBoss Fuse 6.3
----------------------------------------
1) Download JBoss Fuse 6.3 to your filesystem. It can be downloaded from http://origin-repository.jboss.org/nexus/content/groups/m2-proxy/org/jboss/fuse/jboss-fuse-karaf
Assumed you downloaded `jboss-fuse-karaf-6.3.0.redhat-229.zip`
2) Install to your local maven repository and change the properties according to your env (This step can be likely avoided if you somehow configure your local maven settings to point directly to Fuse repo):
````
mvn install:install-file \
-DgroupId=org.jboss.fuse \
-DartifactId=jboss-fuse-karaf \
-Dversion=6.3.0.redhat-229 \
-Dpackaging=zip \
-Dfile=/mydownloads/jboss-fuse-karaf-6.3.0.redhat-229.zip
````
mvn install:install-file \
-DgroupId=org.jboss.fuse \
-DartifactId=jboss-fuse-karaf \
-Dversion=6.3.0.redhat-229 \
-Dpackaging=zip \
-Dfile=/mydownloads/jboss-fuse-karaf-6.3.0.redhat-229.zip
3) Prepare Fuse and run the tests (change props according to your environment, versions etc):
````
# Prepare Fuse server
mvn -f testsuite/integration-arquillian/servers \
clean install \
-Pauth-server-wildfly \
-Papp-server-fuse63 \
-Dfuse63.version=6.3.0.redhat-229 \
-Dapp.server.karaf.update.config=true \
-Dmaven.local.settings=$HOME/.m2/settings.xml \
-Drepositories=,http://download.eng.bos.redhat.com/brewroot/repos/sso-7.1-build/latest/maven/ \
-Dmaven.repo.local=$HOME/.m2/repository
# Prepare Fuse server
mvn -f testsuite/integration-arquillian/servers \
clean install \
-Pauth-server-wildfly \
-Papp-server-fuse63 \
-Dfuse63.version=6.3.0.redhat-229 \
-Dapp.server.karaf.update.config=true \
-Dmaven.local.settings=$HOME/.m2/settings.xml \
-Drepositories=,http://download.eng.bos.redhat.com/brewroot/repos/sso-7.1-build/latest/maven/ \
-Dmaven.repo.local=$HOME/.m2/repository
# Run the Fuse adapter tests
mvn -f testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-fuse63 \
-Dfuse63.version=6.3.0.redhat-229
````
# Run the Fuse adapter tests
mvn -f testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-fuse63 \
-Dfuse63.version=6.3.0.redhat-229
### EAP6 with Hawtio
@ -73,45 +107,45 @@ mvn -f testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xm
2) Install to your local maven repository and change the properties according to your env (This step can be likely avoided if you somehow configure your local maven settings to point directly to EAP repo):
````
mvn install:install-file \
-DgroupId=org.jboss.as \
-DartifactId=jboss-as-dist \
-Dversion=7.5.0.Final-redhat-21 \
-Dpackaging=zip \
-Dfile=/mydownloads/jboss-eap-6.4.0.zip
````
mvn install:install-file \
-DgroupId=org.jboss.as \
-DartifactId=jboss-as-dist \
-Dversion=7.5.0.Final-redhat-21 \
-Dpackaging=zip \
-Dfile=/mydownloads/jboss-eap-6.4.0.zip
3) Download Fuse EAP installer (for example from http://origin-repository.jboss.org/nexus/content/groups/m2-proxy/com/redhat/fuse/eap/fuse-eap-installer/6.3.0.redhat-220/ )
4) Install previously downloaded file manually
````
mvn install:install-file \
-DgroupId=com.redhat.fuse.eap \
-DartifactId=fuse-eap-installer \
-Dversion=6.3.0.redhat-220 \
-Dpackaging=jar \
-Dfile=/fuse-eap-installer-6.3.0.redhat-220.jar
````
mvn install:install-file \
-DgroupId=com.redhat.fuse.eap \
-DartifactId=fuse-eap-installer \
-Dversion=6.3.0.redhat-220 \
-Dpackaging=jar \
-Dfile=/fuse-eap-installer-6.3.0.redhat-220.jar
5) Prepare EAP6 with Hawtio and run the test
````
# Prepare EAP6 and deploy hawtio
mvn -f testsuite/integration-arquillian/servers \
clean install \
-Pauth-server-wildfly \
-Papp-server-eap6-fuse \
-Dapp.server.jboss.version=7.5.0.Final-redhat-21 \
-Dfuse.installer.version=6.3.0.redhat-220
# Prepare EAP6 and deploy hawtio
mvn -f testsuite/integration-arquillian/servers \
clean install \
-Pauth-server-wildfly \
-Papp-server-eap6-fuse \
-Dapp.server.jboss.version=7.5.0.Final-redhat-21 \
-Dfuse.installer.version=6.3.0.redhat-220
# Run the test
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-eap6-fuse
# Run the test
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-eap6-fuse
````
## Migration test
@ -129,34 +163,34 @@ This test will:
2) Run the test (Update according to your DB connection, versions etc):
````
export DB_HOST=localhost
mvn -f testsuite/integration-arquillian/pom.xml \
clean install \
-Pauth-server-wildfly,jpa,clean-jpa,auth-server-migration \
-Dtest=MigrationTest \
-Dmigration.mode=auto \
-Dmigrated.auth.server.version=1.9.8.Final \
-Djdbc.mvn.groupId=mysql \
-Djdbc.mvn.version=5.1.29 \
-Djdbc.mvn.artifactId=mysql-connector-java \
-Dkeycloak.connectionsJpa.url=jdbc:mysql://$DB_HOST/keycloak \
-Dkeycloak.connectionsJpa.user=keycloak \
-Dkeycloak.connectionsJpa.password=keycloak
````
export DB_HOST=localhost
mvn -f testsuite/integration-arquillian/pom.xml \
clean install \
-Pauth-server-wildfly,jpa,clean-jpa,auth-server-migration \
-Dtest=MigrationTest \
-Dmigration.mode=auto \
-Dmigrated.auth.server.version=1.9.8.Final \
-Djdbc.mvn.groupId=mysql \
-Djdbc.mvn.version=5.1.29 \
-Djdbc.mvn.artifactId=mysql-connector-java \
-Dkeycloak.connectionsJpa.url=jdbc:mysql://$DB_HOST/keycloak \
-Dkeycloak.connectionsJpa.user=keycloak \
-Dkeycloak.connectionsJpa.password=keycloak
### JSON export/import migration test
This will start latest Keycloak and import the realm JSON file, which was previously exported from Keycloak 1.9.8.Final
````
mvn -f testsuite/integration-arquillian/pom.xml \
clean install \
-Pauth-server-wildfly,migration-import \
-Dtest=MigrationTest \
-Dmigration.mode=import \
-Dmigrated.auth.server.version=1.9.8.Final
````
mvn -f testsuite/integration-arquillian/pom.xml \
clean install \
-Pauth-server-wildfly,migration-import \
-Dtest=MigrationTest \
-Dmigration.mode=import \
-Dmigrated.auth.server.version=1.9.8.Final
## Social Login

View file

@ -17,6 +17,8 @@
package org.keycloak.testsuite.rest;
import org.jboss.resteasy.annotations.Query;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.jose.jws.JWSInput;
@ -35,6 +37,7 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@ -166,6 +169,33 @@ public class TestApplicationResourceProvider implements RealmResourceProvider {
return sb.toString();
}
@GET
@NoCache
@Produces(MediaType.TEXT_HTML)
@Path("/get-account-profile")
public String getAccountProfile(@QueryParam("token") String token, @QueryParam("account-uri") String accountUri) {
StringBuilder sb = new StringBuilder();
sb.append("function getProfile() {\n");
sb.append(" var req = new XMLHttpRequest();\n");
sb.append(" req.open('GET', '" + accountUri + "', false);\n");
if (token != null) {
sb.append(" req.setRequestHeader('Authorization', 'Bearer " + token + "');\n");
}
sb.append(" req.setRequestHeader('Accept', 'application/json');\n");
sb.append(" req.send(null);\n");
sb.append(" document.getElementById('profileOutput').innerHTML=\"<span id='innerOutput'>\" + req.status + '///' + req.responseText; + \"</span>\"\n");
sb.append("}");
String jsScript = sb.toString();
sb = new StringBuilder();
sb.append("<html><head><title>Account Profile JS Test</title><script>\n")
.append(jsScript)
.append( "</script></head>\n")
.append("<body onload='getProfile()'><div id='profileOutput'></div></body>")
.append("</html>");
return sb.toString();
}
@Path("/oidc-client-endpoints")
public TestingOIDCEndpointsApplicationResource getTestingOIDCClientEndpoints() {
return new TestingOIDCEndpointsApplicationResource(oidcClientData);

View file

@ -95,6 +95,14 @@ class SimpleWebXmlParser {
Class<? extends Filter> filterClazz = (Class<? extends Filter>) Class.forName(filterClass);
FilterInfo undertowFilter = new FilterInfo(filterName, filterClazz);
List<ElementWrapper> initParams = filter.getElementsByTagName("init-param");
for (ElementWrapper initParam : initParams) {
String paramName = initParam.getElementByTagName("param-name").getText();
String paramValue = initParam.getElementByTagName("param-value").getText();
undertowFilter.addInitParam(paramName, paramValue);
}
di.addFilter(undertowFilter);
if (filterMappings.containsKey(filterName)) {

View file

@ -75,9 +75,11 @@ public class InputServlet extends HttpServlet {
return;
}
resp.setContentType("text/plain");
resp.setContentType("text/html");
PrintWriter pw = resp.getWriter();
pw.printf("parameter=" + req.getParameter("parameter"));
pw.printf("<html><head><title>%s</title></head><body>", "Input Page");
pw.printf("parameter=hello");
pw.print("</body></html>");
pw.flush();
}

View file

@ -28,6 +28,7 @@ import org.jboss.logging.Logger.Level;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.keycloak.adapters.servlet.KeycloakOIDCFilter;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
import org.keycloak.testsuite.util.IOUtil;
@ -207,6 +208,28 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
filter.appendChild(filterClass);
appendChildInDocument(webXmlDoc, "web-app", filter);
filter.appendChild(filterName);
filter.appendChild(filterClass);
// Limitation that all deployments of annotated class use same skipPattern. Refactor if something more flexible is needed (would require more tricky web.xml parsing though...)
String skipPattern = testClass.getAnnotation(UseServletFilter.class).skipPattern();
if (skipPattern != null && !skipPattern.isEmpty()) {
Element initParam = webXmlDoc.createElement("init-param");
Element paramName = webXmlDoc.createElement("param-name");
paramName.setTextContent(KeycloakOIDCFilter.SKIP_PATTERN_PARAM);
Element paramValue = webXmlDoc.createElement("param-value");
paramValue.setTextContent(skipPattern);
initParam.appendChild(paramName);
initParam.appendChild(paramValue);
filter.appendChild(initParam);
}
appendChildInDocument(webXmlDoc, "web-app", filter);
Element filterMapping = webXmlDoc.createElement("filter-mapping");

View file

@ -23,6 +23,10 @@ import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourcePro
import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
import org.jboss.arquillian.core.spi.LoadableExtension;
import org.jboss.arquillian.drone.spi.Configurator;
import org.jboss.arquillian.drone.spi.Instantiator;
import org.jboss.arquillian.drone.webdriver.factory.HtmlUnitDriverFactory;
import org.jboss.arquillian.drone.webdriver.factory.WebDriverFactory;
import org.jboss.arquillian.graphene.location.ContainerCustomizableURLResourceProvider;
import org.jboss.arquillian.graphene.location.CustomizableURLResourceProvider;
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
@ -35,6 +39,10 @@ import org.keycloak.testsuite.arquillian.provider.OAuthClientProvider;
import org.keycloak.testsuite.arquillian.provider.SuiteContextProvider;
import org.keycloak.testsuite.arquillian.provider.TestContextProvider;
import org.keycloak.testsuite.arquillian.provider.URLProvider;
import org.keycloak.testsuite.drone.HtmlUnitScreenshots;
import org.keycloak.testsuite.drone.KeycloakDronePostSetup;
import org.keycloak.testsuite.drone.KeycloakHtmlUnitInstantiator;
import org.keycloak.testsuite.drone.KeycloakWebDriverConfigurator;
/**
*
@ -67,6 +75,13 @@ public class KeycloakArquillianExtension implements LoadableExtension {
.override(ResourceProvider.class, ContainerCustomizableURLResourceProvider.class, URLProvider.class)
.override(ApplicationArchiveProcessor.class, OSGiApplicationArchiveProcessor.class, KeycloakOSGiApplicationArchiveProcessor.class);
builder
.override(Configurator.class, WebDriverFactory.class, KeycloakWebDriverConfigurator.class)
.override(Instantiator.class, HtmlUnitDriverFactory.class, KeycloakHtmlUnitInstantiator.class)
.observer(HtmlUnitScreenshots.class)
.observer(KeycloakDronePostSetup.class);
}
}

View file

@ -22,4 +22,5 @@ public @interface UseServletFilter {
String filterClass();
String filterPattern() default "/*";
String dispatcherType() default "";
String skipPattern() default "";
}

View file

@ -17,6 +17,7 @@
package org.keycloak.testsuite.client.resources;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.representations.adapters.action.LogoutAction;
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
import org.keycloak.representations.adapters.action.TestAvailabilityAction;
@ -25,6 +26,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@ -53,6 +55,11 @@ public interface TestApplicationResource {
@Path("/clear-admin-actions")
Response clearAdminActions();
@GET
@Produces(MediaType.TEXT_HTML)
@Path("/get-account-profile")
String getAccountProfile(@QueryParam("token") String token, @QueryParam("account-uri") String accountUri);
@Path("/oidc-client-endpoints")
TestOIDCEndpointsApplicationResource oidcClientEndpoints();
}

View file

@ -0,0 +1,50 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.drone;
import org.arquillian.extension.recorder.screenshooter.ScreenshooterConfiguration;
import org.arquillian.extension.recorder.screenshooter.event.ScreenshooterExtensionConfigured;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
/**
* Disable screenshots for HTMLUnitDriver as it doesn't work
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class HtmlUnitScreenshots {
protected final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(HtmlUnitScreenshots.class);
@Inject
private Instance<ScreenshooterConfiguration> configuration;
public void configureExtension(@Observes ScreenshooterExtensionConfigured event) {
ScreenshooterConfiguration conf = configuration.get();
if (System.getProperty("browser").equals("htmlUnit")) {
conf.setProperty("takeWhenTestFailed", "false");
log.info("Screenshots disabled as htmlUnit is used");
} else {
log.info("Screenshots are enabled");
}
}
}

View file

@ -0,0 +1,124 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.drone;
import java.util.concurrent.TimeUnit;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.drone.spi.DroneContext;
import org.jboss.arquillian.drone.spi.DronePoint;
import org.jboss.arquillian.drone.spi.event.AfterDroneEnhanced;
import org.jboss.arquillian.graphene.proxy.GrapheneProxyInstance;
import org.jboss.arquillian.graphene.proxy.Interceptor;
import org.jboss.arquillian.graphene.proxy.InvocationContext;
import org.jboss.logging.Logger;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class KeycloakDronePostSetup {
protected static final Logger log = org.jboss.logging.Logger.getLogger(KeycloakDronePostSetup.class);
public void configureWebDriver(@Observes AfterDroneEnhanced event, DroneContext droneContext) {
DronePoint<?> dronePoint = event.getDronePoint();
Object drone = droneContext.get(dronePoint).getInstance();
if (drone instanceof WebDriver) {
WebDriver webDriver = (WebDriver) drone;
configureDriverSettings(webDriver);
} else {
log.warn("Drone is not instanceof WebDriver! Drone is " + drone);
}
if (drone instanceof GrapheneProxyInstance) {
GrapheneProxyInstance droneProxy = (GrapheneProxyInstance) drone;
if (drone instanceof HtmlUnitDriver) {
droneProxy.registerInterceptor(new HtmlUnitInterceptor());
}
} else {
log.warn("Drone is not instanceof GrapheneProxyInstance! Drone is " + drone);
}
}
private void configureDriverSettings(WebDriver driver) {
long implicitWaitMillis = WaitUtils.IMPLICIT_ELEMENT_WAIT_MILLIS;
long pageLoadTimeoutMillis = WaitUtils.PAGELOAD_TIMEOUT_MILLIS;
log.infof("Configuring driver settings. implicitWait=%d, pageLoadTimeout=%d", implicitWaitMillis, pageLoadTimeoutMillis);
driver.manage().timeouts().implicitlyWait(implicitWaitMillis, TimeUnit.MILLISECONDS);
driver.manage().timeouts().pageLoadTimeout(pageLoadTimeoutMillis, TimeUnit.MILLISECONDS);
driver.manage().window().maximize();
}
public static class HtmlUnitInterceptor implements Interceptor {
@Override
public Object intercept(InvocationContext context) throws Throwable {
if (context.getMethod().getName().equals("executeScript")) {
String currentUrl = ((WebDriver) context.getTarget()).getCurrentUrl();
int refreshCount = 0;
while (true) {
try {
// htmlUnit is not able to run javascript on about:blank page
if ("about:blank".equals(currentUrl)) {
log.debug("Ignored JS as we are on about:blank page now");
return null;
}
return context.invoke();
} catch (UnsupportedOperationException e) {
// htmlUnit may require to refresh the page after the action
if ("Cannot execute JS against a plain text page".equals(e.getMessage())) {
refreshCount += 1;
if (refreshCount < 2) {
log.debugf("Will try to refresh current page: %s", currentUrl);
((WebDriver) context.getProxy()).navigate().to(currentUrl);
} else {
log.debugf("Current page doesn't seem to support javascript. Current url: %s", currentUrl);
return null;
}
} else {
throw e;
}
}
}
} else {
return context.invoke();
}
}
@Override
public int getPrecedence() {
return -1;
}
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.drone;
import java.lang.reflect.Method;
import com.gargoylesoftware.htmlunit.WebClient;
import org.jboss.arquillian.drone.spi.Instantiator;
import org.jboss.arquillian.drone.webdriver.configuration.WebDriverConfiguration;
import org.jboss.arquillian.drone.webdriver.factory.HtmlUnitDriverFactory;
import org.jboss.logging.Logger;
import org.keycloak.common.util.reflections.Reflections;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class KeycloakHtmlUnitInstantiator extends HtmlUnitDriverFactory implements Instantiator<HtmlUnitDriver, WebDriverConfiguration> {
protected final Logger log = Logger.getLogger(KeycloakHtmlUnitInstantiator.class);
@Override
public int getPrecedence() {
return 1;
}
@Override
public HtmlUnitDriver createInstance(WebDriverConfiguration configuration) {
HtmlUnitDriver htmlUnitDriver = super.createInstance(configuration);
// Disable CSS
Method getWebClient = Reflections.findDeclaredMethod(HtmlUnitDriver.class, "getWebClient");
WebClient webClient = (WebClient) Reflections.invokeMethod(true, getWebClient, htmlUnitDriver);
webClient.getOptions().setCssEnabled(false);
return htmlUnitDriver;
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.drone;
import java.util.HashMap;
import java.util.Map;
import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
import org.jboss.arquillian.drone.spi.Configurator;
import org.jboss.arquillian.drone.spi.DronePoint;
import org.jboss.arquillian.drone.webdriver.configuration.WebDriverConfiguration;
import org.jboss.arquillian.drone.webdriver.factory.BrowserCapabilitiesList;
import org.jboss.arquillian.drone.webdriver.factory.WebDriverFactory;
import org.jboss.logging.Logger;
import org.openqa.selenium.WebDriver;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class KeycloakWebDriverConfigurator extends WebDriverFactory implements Configurator<WebDriver, WebDriverConfiguration> {
protected final Logger log = Logger.getLogger(KeycloakWebDriverConfigurator.class);
@Override
public int getPrecedence() {
return 1;
}
@Override
public WebDriverConfiguration createConfiguration(ArquillianDescriptor descriptor, DronePoint<WebDriver> dronePoint) {
WebDriverConfiguration webDriverCfg = super.createConfiguration(descriptor, dronePoint);
if (webDriverCfg.getBrowser().equals("htmlUnit")) {
updateCapabilities(webDriverCfg);
}
return webDriverCfg;
}
// This is to ensure that default value of capabilities like "version" will be used just for the HtmlUnitDriver, but not for other drivers.
// Hence in configs we have "htmlUnit.version" instead of "version"
protected void updateCapabilities(WebDriverConfiguration configuration) {
Map<String, Object> newCapabilities = new HashMap<>();
for (Map.Entry<String, ?> capability : configuration.getCapabilities().asMap().entrySet()) {
if (capability.getKey().startsWith("htmlUnit.")) {
newCapabilities.put(capability.getKey().substring(9), capability.getValue());
}
}
log.debug("Adding new capabilities for HtmlUnitDriver: " + newCapabilities);
KcHtmlUnitCapabilities mergedBrowser = new KcHtmlUnitCapabilities(newCapabilities);
configuration.setBrowserInternal(mergedBrowser);
}
private static class KcHtmlUnitCapabilities extends BrowserCapabilitiesList.HtmlUnit {
private final Map<String, Object> newCapabilities;
public KcHtmlUnitCapabilities(Map<String, Object> newCapabilities) {
this.newCapabilities = newCapabilities;
}
@Override
public Map<String, ?> getRawCapabilities() {
Map<String, ?> parent = super.getRawCapabilities();
Map<String, Object> merged = new HashMap<>(parent);
merged.putAll(newCapabilities);
return merged;
}
}
}

View file

@ -41,7 +41,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.ws.rs.NotFoundException;
import org.jboss.arquillian.container.test.api.RunAsClient;
@ -76,7 +75,6 @@ import org.keycloak.testsuite.auth.page.login.UpdatePassword;
import org.keycloak.testsuite.client.KeycloakTestingClient;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.TestEventsLogger;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.WebDriver;
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
@ -155,8 +153,6 @@ public abstract class AbstractKeycloakTest {
setDefaultPageUriParameters();
driverSettings();
TestEventsLogger.setDriver(driver);
if (!suiteContext.isAdminPasswordUpdated()) {
@ -198,12 +194,6 @@ public abstract class AbstractKeycloakTest {
driver.manage().deleteAllCookies();
}
protected void driverSettings() {
driver.manage().timeouts().implicitlyWait(WaitUtils.IMPLICIT_ELEMENT_WAIT_MILLIS, TimeUnit.MILLISECONDS);
driver.manage().timeouts().pageLoadTimeout(WaitUtils.PAGELOAD_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
driver.manage().window().maximize();
}
public void setDefaultPageUriParameters() {
masterRealmPage.setAuthRealm(MASTER);
loginPage.setAuthRealm(MASTER);

View file

@ -23,11 +23,14 @@ import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jboss.arquillian.drone.api.annotation.Default;
import org.jboss.arquillian.graphene.context.GrapheneContext;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.admin.client.resource.RoleScopeResource;
import org.keycloak.models.AccountRoles;
@ -37,15 +40,25 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.client.resources.TestApplicationResource;
import org.keycloak.testsuite.pages.AccountApplicationsPage;
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.OAuthGrantPage;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.RealmRepUtil;
import org.keycloak.testsuite.util.UserBuilder;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import twitter4j.JSONArray;
import twitter4j.JSONObject;
@ -79,6 +92,7 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
.password("password")
.build();
RealmBuilder.edit(testRealm)
.accessTokenLifespan(1000)
.user(user2);
ClientBuilder.edit(RealmRepUtil.findClientByClientId(testRealm, "test-app"))
@ -155,12 +169,15 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
driver.navigate().to("http://localtest.me:8180/app");
driver.navigate().to("http://localtest.me:8180/auth/realms/test/account");
String[] response = doGetProfileJs(token);
String[] response = doGetProfileJs("http://localtest.me:8180/auth", token);
assertEquals("200", response[0]);
}
// WARN: If it's failing for phantomJS, make sure to enable CORS by using:
// -Dphantomjs.cli.args="--ignore-ssl-errors=true --web-security=true"
@Test
public void getProfileCorsInvalidOrigin() throws Exception {
oauth.doLogin("test-user@localhost", "password");
@ -168,12 +185,16 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
driver.navigate().to("http://invalid.localtest.me:8180");
String[] response = null;
try {
doGetProfileJs(token);
fail("Expected failure");
} catch (Throwable t) {
response = doGetProfileJs("http://invalid.localtest.me:8180/auth", token);
} catch (WebDriverException ex) {
// Expected
}
// Some webDrivers throw exception (htmlUnit) , some just doesn't return anything.
if (response != null && response.length > 0 && response[0].equals("200")) {
fail("Not expected to retrieve response. Make sure CORS are enabled for your browser!");
}
}
@ -182,7 +203,7 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
profilePage.open();
loginPage.login("test-user@localhost", "password");
String[] response = doGetProfileJs(null);
String[] response = doGetProfileJs(OAuthClient.AUTH_SERVER_ROOT, null);
assertEquals("200", response[0]);
JSONObject profile = new JSONObject(response[1]);
@ -253,19 +274,36 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
return client.execute(get);
}
private String[] doGetProfileJs(String token) {
StringBuilder sb = new StringBuilder();
sb.append("var req = new XMLHttpRequest();\n");
sb.append("req.open('GET', '" + getAccountURI().toString() + "', false);\n");
if (token != null) {
sb.append("req.setRequestHeader('Authorization', 'Bearer " + token + "');\n");
}
sb.append("req.setRequestHeader('Accept', 'application/json');\n");
sb.append("req.send(null);\n");
sb.append("return req.status + '///' + req.responseText;\n");
private String[] doGetProfileJs(String authServerRoot, String token) {
UriBuilder uriBuilder = UriBuilder.fromUri(authServerRoot)
.path(TestApplicationResource.class)
.path(TestApplicationResource.class, "getAccountProfile")
.queryParam("account-uri", getAccountURI().toString());
JavascriptExecutor js = (JavascriptExecutor) driver;
String response = (String) js.executeScript(sb.toString());
if (token != null) {
uriBuilder.queryParam("token", token);
// Remove Keycloak cookies. Some browsers send cookies even in preflight requests
driver.navigate().to(OAuthClient.AUTH_SERVER_ROOT + "/realms/test/account");
driver.manage().deleteAllCookies();
}
String accountProfileUri = uriBuilder.build().toString();
log.info("Retrieve profile with URI: " + accountProfileUri);
driver.navigate().to(accountProfileUri);
WaitUtils.waitUntilElement(By.id("innerOutput"));
String response = driver.findElement(By.id("innerOutput")).getText();
return response.split("///");
}
private WebDriver getHtmlUnitDriver() {
DesiredCapabilities cap = new DesiredCapabilities();
cap.setPlatform(Platform.ANY);
cap.setJavascriptEnabled(true);
cap.setVersion("chrome");
cap.setBrowserName("htmlunit");
HtmlUnitDriver driver = new HtmlUnitDriver(cap);
return driver;
}
}

View file

@ -9,7 +9,7 @@ import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
*/
@UseServletFilter(filterName = "oidc-filter", filterClass = "org.keycloak.adapters.servlet.KeycloakOIDCFilter",
filterDependency = "org.keycloak:keycloak-servlet-filter-adapter")
filterDependency = "org.keycloak:keycloak-servlet-filter-adapter", skipPattern = "/error.html")
public abstract class AbstractDemoFilterServletAdapterTest extends AbstractDemoServletsAdapterTest {

View file

@ -23,13 +23,17 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.common.Version;
import org.keycloak.common.util.Time;
import org.keycloak.common.util.UriUtils;
import org.keycloak.constants.AdapterConstants;
import org.keycloak.events.Details;
import org.keycloak.events.EventType;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.representations.AccessToken;
@ -37,6 +41,7 @@ import org.keycloak.representations.VersionRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
import org.keycloak.testsuite.adapter.page.*;
@ -49,7 +54,6 @@ import org.keycloak.testsuite.util.URLUtils;
import org.keycloak.util.BasicAuthHelper;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
@ -116,6 +120,9 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
@Page
private Config configPage;
@Rule
public AssertEvents assertEvents = new AssertEvents(this);
@Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
protected static WebArchive customerPortal() {
return servletDeployment(CustomerPortal.DEPLOYMENT_NAME, CustomerServlet.class, ErrorServlet.class, ServletTestUtils.class);
@ -192,8 +199,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
testRealmLoginPage.form().login("bburke@redhat.com", "password");
assertCurrentUrlEquals(driver, inputPortal + "/secured/post");
String pageSource = driver.getPageSource();
assertTrue(pageSource.contains("parameter=hello"));
waitUntilElement(By.xpath("//body")).text().contains("parameter=hello");
String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
.queryParam(OAuth2Constants.REDIRECT_URI, customerPortal.toString())
@ -353,6 +359,10 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
@Test
public void testLoginSSOMax() throws InterruptedException {
// Delete cookies
driver.navigate().to(customerPortal + "/error.html");
driver.manage().deleteAllCookies();
// test login to customer-portal which does a bearer request to customer-db
customerPortal.navigateTo();
testRealmLoginPage.form().waitForUsernameInputPresent();
@ -600,6 +610,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
RealmRepresentation realm = testRealmResource().toRepresentation();
realm.setEventsEnabled(true);
realm.setEnabledEventTypes(Arrays.asList("REVOKE_GRANT", "LOGIN"));
realm.setEventsListeners(Arrays.asList("jboss-logging", "event-queue"));
testRealmResource().update(realm);
customerPortal.navigateTo();
@ -613,6 +624,26 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
waitUntilElement(By.xpath("//body")).text().contains("Bill Burke");
waitUntilElement(By.xpath("//body")).text().contains("Stian Thorgersen");
String userId = ApiUtil.findUserByUsername(testRealmResource(), "bburke@redhat.com").getId();
assertEvents.expectLogin()
.realm(realm.getId())
.client("customer-portal")
.user(userId)
.detail(Details.USERNAME, "bburke@redhat.com")
.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
.detail(Details.REDIRECT_URI, customerPortal.getInjectedUrl().toString())
.removeDetail(Details.CODE_ID)
.assertEvent();
assertEvents.expectCodeToToken(null, null)
.realm(realm.getId())
.client("customer-portal")
.user(userId)
.session(AssertEvents.isUUID())
.removeDetail(Details.CODE_ID)
.assertEvent();
applicationsPage.navigateTo();
applicationsPage.revokeGrantForApplication("customer-portal");
@ -620,42 +651,14 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
assertTrue(oAuthGrantPage.isCurrent());
loginEventsPage.navigateTo();
assertEvents.expect(EventType.REVOKE_GRANT)
.realm(realm.getId())
.client("account")
.user(userId)
.detail(Details.REVOKED_CLIENT, "customer-portal")
.assertEvent();
if (!testContext.isAdminLoggedIn()) {
loginPage.form().login(adminUser);
testContext.setAdminLoggedIn(true);
}
loginEventsPage.table().filter();
loginEventsPage.table().filterForm().addEventType("REVOKE_GRANT");
loginEventsPage.table().update();
List<WebElement> resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='REVOKE_GRANT']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='account']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='revoked_client']/../td[text()='customer-portal']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("LOGIN");
loginEventsPage.table().update();
resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='LOGIN']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='customer-portal']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='username']/../td[text()='bburke@redhat.com']"));
resultList.get(0).findElement(By.xpath(".//td[text()='consent']/../td[text()='consent_granted']"));
configPage.navigateTo();
configPage.form().clearLoginEvents();
driver.findElement(By.xpath("//div[@class='modal-dialog']//button[text()='Delete']")).click();
assertEvents.assertEmpty();
}
@Test
@ -663,6 +666,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
RealmRepresentation realm = testRealmResource().toRepresentation();
realm.setEventsEnabled(true);
realm.setEnabledEventTypes(Arrays.asList("LOGIN", "LOGIN_ERROR", "LOGOUT", "CODE_TO_TOKEN"));
realm.setEventsListeners(Arrays.asList("jboss-logging", "event-queue"));
testRealmResource().update(realm);
customerPortal.navigateTo();
@ -672,53 +676,37 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
waitUntilElement(By.xpath("//body")).text().contains("Bill Burke");
waitUntilElement(By.xpath("//body")).text().contains("Stian Thorgersen");
String userId = ApiUtil.findUserByUsername(testRealmResource(), "bburke@redhat.com").getId();
assertEvents.expectLogin()
.realm(realm.getId())
.client("customer-portal")
.user(userId)
.detail(Details.USERNAME, "bburke@redhat.com")
.detail(Details.CONSENT, Details.CONSENT_VALUE_NO_CONSENT_REQUIRED)
.detail(Details.REDIRECT_URI, customerPortal.getInjectedUrl().toString())
.removeDetail(Details.CODE_ID)
.assertEvent();
assertEvents.expectCodeToToken(null, null)
.realm(realm.getId())
.client("customer-portal")
.user(userId)
.session(AssertEvents.isUUID())
.removeDetail(Details.CODE_ID)
.assertEvent();
driver.navigate().to(testRealmPage.getOIDCLogoutUrl() + "?redirect_uri=" + customerPortal);
loginEventsPage.navigateTo();
assertEvents.expectLogout(null)
.realm(realm.getId())
.user(userId)
.session(AssertEvents.isUUID())
.detail(Details.REDIRECT_URI, customerPortal.getInjectedUrl().toString())
.assertEvent();
if (!testContext.isAdminLoggedIn()) {
loginPage.form().login(adminUser);
testContext.setAdminLoggedIn(true);
}
loginEventsPage.table().filter();
loginEventsPage.table().filterForm().addEventType("LOGOUT");
loginEventsPage.table().update();
List<WebElement> resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='LOGOUT']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("LOGIN");
loginEventsPage.table().update();
resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='LOGIN']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='customer-portal']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='username']/../td[text()='bburke@redhat.com']"));
loginEventsPage.table().reset();
loginEventsPage.table().filterForm().addEventType("CODE_TO_TOKEN");
loginEventsPage.table().update();
resultList = loginEventsPage.table().rows();
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath(".//td[text()='CODE_TO_TOKEN']"));
resultList.get(0).findElement(By.xpath(".//td[text()='Client']/../td[text()='customer-portal']"));
resultList.get(0).findElement(By.xpath(".//td[text()='IP Address']/../td[text()='127.0.0.1' or text()='0:0:0:0:0:0:0:1']"));
resultList.get(0).findElement(By.xpath(".//td[text()='refresh_token_type']/../td[text()='Refresh']"));
configPage.navigateTo();
configPage.form().clearLoginEvents();
driver.findElement(By.xpath("//div[@class='modal-dialog']//button[text()='Delete']")).click();
assertEvents.assertEmpty();
String serverLogPath = null;

View file

@ -34,6 +34,7 @@ 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.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
@ -84,7 +85,7 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
}
@Test
public void testProviderIdpInitiatedLogin() {
public void testProviderIdpInitiatedLogin() throws Exception {
driver.navigate().to(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker"));
waitForPage("log in to");
@ -114,7 +115,7 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
boolean isUserFound = users.stream().anyMatch(user -> user.getUsername().equals("mytest") && user.getEmail().equals("test@localhost"));
Assert.assertTrue("There must be user " + "mytest" + " in realm " + REALM_CONS_NAME, isUserFound);
Assert.assertThat(driver.findElement(org.openqa.selenium.By.tagName("form")).getAttribute("action"), containsString("http://localhost:18080/sales-post-enc/"));
Assert.assertThat(driver.findElement(By.tagName("a")).getAttribute("id"), containsString("account"));
}
private String getSamlIdpInitiatedUrl(String realmName, String samlIdpInitiatedSsoUrlName) {

View file

@ -24,8 +24,9 @@
<extension qualifier="webdriver">
<property name="browser">${browser}</property>
<property name="htmlUnit.version">${htmlUnitBrowserVersion}</property>
<property name="firefox_binary">${firefox_binary}</property>
<property name="phantomjs.cli.args">--ignore-ssl-errors=true --web-security=false</property>
<property name="phantomjs.cli.args">${phantomjs.cli.args}</property>
</extension>
<extension qualifier="graphene">

View file

@ -66,4 +66,4 @@ log4j.logger.org.apache.directory.server.core=warn
# log4j.logger.org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticator=trace
# log4j.logger.org.keycloak.keys.infinispan=trace
log4j.logger.org.keycloak.services.clientregistration.policy=debug
log4j.logger.org.keycloak.services.clientregistration.policy=debug

View file

@ -5,18 +5,18 @@
"sslRequired" : "external",
"roles" : {
"client" : {
"http://localhost:18080/sales-post-enc/" : [ {
"http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth" : [ {
"name" : "manager"
} ]
}
},
"clients" : [ {
"clientId": "http://localhost:18080/sales-post-enc/",
"clientId": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth",
"enabled": true,
"protocol": "saml",
"fullScopeAllowed": true,
"redirectUris": [
"http://localhost:18080/sales-post-enc/*"
"http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth/*"
],
"attributes": {
"saml.authnstatement": "true",
@ -28,8 +28,8 @@
"saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
"saml_idp_initiated_sso_url_name" : "sales"
},
"baseUrl": "http://localhost:18080/sales-post-enc/",
"adminUrl": "http://localhost:18080/sales-post-enc/saml"
"baseUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth",
"adminUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth"
} ],
"identityProviders" : [ {
"alias" : "saml-leaf",
@ -57,7 +57,7 @@
"identityProviderMapper" : "saml-role-idp-mapper",
"config" : {
"attribute.value" : "manager",
"role" : "http://localhost:18080/sales-post-enc/.manager",
"role" : "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth.manager",
"attribute.name" : "Role"
}
} ]

View file

@ -70,8 +70,10 @@
<migration.import.properties/>
<examples.home>${project.build.directory}/examples</examples.home>
<browser>phantomjs</browser>
<browser>htmlUnit</browser>
<htmlUnitBrowserVersion>chrome</htmlUnitBrowserVersion>
<firefox_binary>/usr/bin/firefox</firefox_binary>
<phantomjs.cli.args>--ignore-ssl-errors=true --web-security=false</phantomjs.cli.args>
<frontend.console.output>true</frontend.console.output>
<backends.console.output>true</backends.console.output>
@ -181,7 +183,9 @@
<test.intermittent>${test.intermittent}</test.intermittent>
<browser>${browser}</browser>
<htmlUnitBrowserVersion>${htmlUnitBrowserVersion}</htmlUnitBrowserVersion>
<firefox_binary>${firefox_binary}</firefox_binary>
<phantomjs.cli.args>${phantomjs.cli.args}</phantomjs.cli.args>
<project.version>${project.version}</project.version>
<migration.project.version>${migration.project.version}</migration.project.version>