KEYCLOAK-4368 Switch default WebDriver impl to htmlUnit
This commit is contained in:
parent
ec32acec27
commit
f6bc0806d5
22 changed files with 691 additions and 224 deletions
|
@ -53,6 +53,9 @@ import java.util.regex.Pattern;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class KeycloakOIDCFilter implements Filter {
|
public class KeycloakOIDCFilter implements Filter {
|
||||||
|
|
||||||
|
public static final String SKIP_PATTERN_PARAM = "keycloak.config.skipPattern";
|
||||||
|
|
||||||
protected AdapterDeploymentContext deploymentContext;
|
protected AdapterDeploymentContext deploymentContext;
|
||||||
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
|
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
|
||||||
protected NodesRegistrationManagement nodesRegistrationManagement;
|
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||||
|
@ -63,7 +66,7 @@ public class KeycloakOIDCFilter implements Filter {
|
||||||
@Override
|
@Override
|
||||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
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) {
|
if (skipPatternDefinition != null) {
|
||||||
skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
|
skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,67 +5,101 @@ How To Run various testsuite configurations
|
||||||
|
|
||||||
It's recomended to build the workspace including distribution.
|
It's recomended to build the workspace including distribution.
|
||||||
|
|
||||||
````
|
|
||||||
cd $KEYCLOAK_SOURCES
|
cd $KEYCLOAK_SOURCES
|
||||||
mvn clean install -DskipTests=true
|
mvn clean install -DskipTests=true
|
||||||
cd distribution
|
cd distribution
|
||||||
mvn clean install
|
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
|
## Run adapter tests
|
||||||
|
|
||||||
### Wildfly
|
### Wildfly
|
||||||
|
|
||||||
````
|
|
||||||
# Prepare servers
|
# Prepare servers
|
||||||
mvn -f testsuite/integration-arquillian/servers/pom.xml clean install \
|
mvn -f testsuite/integration-arquillian/servers/pom.xml clean install \
|
||||||
-Pauth-server-wildfly \
|
-Pauth-server-wildfly \
|
||||||
-Papp-server-wildfly
|
-Papp-server-wildfly
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml \
|
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml \
|
||||||
clean install \
|
clean install \
|
||||||
-Pauth-server-wildfly \
|
-Pauth-server-wildfly \
|
||||||
-Papp-server-wildfly
|
-Papp-server-wildfly
|
||||||
````
|
|
||||||
|
|
||||||
### JBoss Fuse 6.3
|
### 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
|
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`
|
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):
|
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 \
|
mvn install:install-file \
|
||||||
-DgroupId=org.jboss.fuse \
|
-DgroupId=org.jboss.fuse \
|
||||||
-DartifactId=jboss-fuse-karaf \
|
-DartifactId=jboss-fuse-karaf \
|
||||||
-Dversion=6.3.0.redhat-229 \
|
-Dversion=6.3.0.redhat-229 \
|
||||||
-Dpackaging=zip \
|
-Dpackaging=zip \
|
||||||
-Dfile=/mydownloads/jboss-fuse-karaf-6.3.0.redhat-229.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):
|
3) Prepare Fuse and run the tests (change props according to your environment, versions etc):
|
||||||
|
|
||||||
````
|
|
||||||
# Prepare Fuse server
|
# Prepare Fuse server
|
||||||
mvn -f testsuite/integration-arquillian/servers \
|
mvn -f testsuite/integration-arquillian/servers \
|
||||||
clean install \
|
clean install \
|
||||||
-Pauth-server-wildfly \
|
-Pauth-server-wildfly \
|
||||||
-Papp-server-fuse63 \
|
-Papp-server-fuse63 \
|
||||||
-Dfuse63.version=6.3.0.redhat-229 \
|
-Dfuse63.version=6.3.0.redhat-229 \
|
||||||
-Dapp.server.karaf.update.config=true \
|
-Dapp.server.karaf.update.config=true \
|
||||||
-Dmaven.local.settings=$HOME/.m2/settings.xml \
|
-Dmaven.local.settings=$HOME/.m2/settings.xml \
|
||||||
-Drepositories=,http://download.eng.bos.redhat.com/brewroot/repos/sso-7.1-build/latest/maven/ \
|
-Drepositories=,http://download.eng.bos.redhat.com/brewroot/repos/sso-7.1-build/latest/maven/ \
|
||||||
-Dmaven.repo.local=$HOME/.m2/repository
|
-Dmaven.repo.local=$HOME/.m2/repository
|
||||||
|
|
||||||
# Run the Fuse adapter tests
|
# Run the Fuse adapter tests
|
||||||
mvn -f testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml \
|
mvn -f testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml \
|
||||||
clean install \
|
clean install \
|
||||||
-Pauth-server-wildfly \
|
-Pauth-server-wildfly \
|
||||||
-Papp-server-fuse63 \
|
-Papp-server-fuse63 \
|
||||||
-Dfuse63.version=6.3.0.redhat-229
|
-Dfuse63.version=6.3.0.redhat-229
|
||||||
````
|
|
||||||
|
|
||||||
### EAP6 with Hawtio
|
### 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):
|
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 \
|
mvn install:install-file \
|
||||||
-DgroupId=org.jboss.as \
|
-DgroupId=org.jboss.as \
|
||||||
-DartifactId=jboss-as-dist \
|
-DartifactId=jboss-as-dist \
|
||||||
-Dversion=7.5.0.Final-redhat-21 \
|
-Dversion=7.5.0.Final-redhat-21 \
|
||||||
-Dpackaging=zip \
|
-Dpackaging=zip \
|
||||||
-Dfile=/mydownloads/jboss-eap-6.4.0.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/ )
|
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
|
4) Install previously downloaded file manually
|
||||||
|
|
||||||
````
|
|
||||||
mvn install:install-file \
|
mvn install:install-file \
|
||||||
-DgroupId=com.redhat.fuse.eap \
|
-DgroupId=com.redhat.fuse.eap \
|
||||||
-DartifactId=fuse-eap-installer \
|
-DartifactId=fuse-eap-installer \
|
||||||
-Dversion=6.3.0.redhat-220 \
|
-Dversion=6.3.0.redhat-220 \
|
||||||
-Dpackaging=jar \
|
-Dpackaging=jar \
|
||||||
-Dfile=/fuse-eap-installer-6.3.0.redhat-220.jar
|
-Dfile=/fuse-eap-installer-6.3.0.redhat-220.jar
|
||||||
````
|
|
||||||
|
|
||||||
5) Prepare EAP6 with Hawtio and run the test
|
5) Prepare EAP6 with Hawtio and run the test
|
||||||
|
|
||||||
````
|
|
||||||
# Prepare EAP6 and deploy hawtio
|
# Prepare EAP6 and deploy hawtio
|
||||||
mvn -f testsuite/integration-arquillian/servers \
|
mvn -f testsuite/integration-arquillian/servers \
|
||||||
clean install \
|
clean install \
|
||||||
-Pauth-server-wildfly \
|
-Pauth-server-wildfly \
|
||||||
-Papp-server-eap6-fuse \
|
-Papp-server-eap6-fuse \
|
||||||
-Dapp.server.jboss.version=7.5.0.Final-redhat-21 \
|
-Dapp.server.jboss.version=7.5.0.Final-redhat-21 \
|
||||||
-Dfuse.installer.version=6.3.0.redhat-220
|
-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
|
## Migration test
|
||||||
|
|
||||||
|
@ -129,34 +163,34 @@ This test will:
|
||||||
|
|
||||||
2) Run the test (Update according to your DB connection, versions etc):
|
2) Run the test (Update according to your DB connection, versions etc):
|
||||||
|
|
||||||
````
|
|
||||||
export DB_HOST=localhost
|
|
||||||
|
|
||||||
mvn -f testsuite/integration-arquillian/pom.xml \
|
export DB_HOST=localhost
|
||||||
clean install \
|
|
||||||
-Pauth-server-wildfly,jpa,clean-jpa,auth-server-migration \
|
mvn -f testsuite/integration-arquillian/pom.xml \
|
||||||
-Dtest=MigrationTest \
|
clean install \
|
||||||
-Dmigration.mode=auto \
|
-Pauth-server-wildfly,jpa,clean-jpa,auth-server-migration \
|
||||||
-Dmigrated.auth.server.version=1.9.8.Final \
|
-Dtest=MigrationTest \
|
||||||
-Djdbc.mvn.groupId=mysql \
|
-Dmigration.mode=auto \
|
||||||
-Djdbc.mvn.version=5.1.29 \
|
-Dmigrated.auth.server.version=1.9.8.Final \
|
||||||
-Djdbc.mvn.artifactId=mysql-connector-java \
|
-Djdbc.mvn.groupId=mysql \
|
||||||
-Dkeycloak.connectionsJpa.url=jdbc:mysql://$DB_HOST/keycloak \
|
-Djdbc.mvn.version=5.1.29 \
|
||||||
-Dkeycloak.connectionsJpa.user=keycloak \
|
-Djdbc.mvn.artifactId=mysql-connector-java \
|
||||||
-Dkeycloak.connectionsJpa.password=keycloak
|
-Dkeycloak.connectionsJpa.url=jdbc:mysql://$DB_HOST/keycloak \
|
||||||
````
|
-Dkeycloak.connectionsJpa.user=keycloak \
|
||||||
|
-Dkeycloak.connectionsJpa.password=keycloak
|
||||||
|
|
||||||
|
|
||||||
### JSON export/import migration test
|
### 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
|
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 \
|
mvn -f testsuite/integration-arquillian/pom.xml \
|
||||||
clean install \
|
clean install \
|
||||||
-Pauth-server-wildfly,migration-import \
|
-Pauth-server-wildfly,migration-import \
|
||||||
-Dtest=MigrationTest \
|
-Dtest=MigrationTest \
|
||||||
-Dmigration.mode=import \
|
-Dmigration.mode=import \
|
||||||
-Dmigrated.auth.server.version=1.9.8.Final
|
-Dmigrated.auth.server.version=1.9.8.Final
|
||||||
````
|
|
||||||
|
|
||||||
|
|
||||||
## Social Login
|
## Social Login
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.rest;
|
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.HttpRequest;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
|
@ -35,6 +37,7 @@ import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -166,6 +169,33 @@ public class TestApplicationResourceProvider implements RealmResourceProvider {
|
||||||
return sb.toString();
|
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")
|
@Path("/oidc-client-endpoints")
|
||||||
public TestingOIDCEndpointsApplicationResource getTestingOIDCClientEndpoints() {
|
public TestingOIDCEndpointsApplicationResource getTestingOIDCClientEndpoints() {
|
||||||
return new TestingOIDCEndpointsApplicationResource(oidcClientData);
|
return new TestingOIDCEndpointsApplicationResource(oidcClientData);
|
||||||
|
|
|
@ -95,6 +95,14 @@ class SimpleWebXmlParser {
|
||||||
|
|
||||||
Class<? extends Filter> filterClazz = (Class<? extends Filter>) Class.forName(filterClass);
|
Class<? extends Filter> filterClazz = (Class<? extends Filter>) Class.forName(filterClass);
|
||||||
FilterInfo undertowFilter = new FilterInfo(filterName, filterClazz);
|
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);
|
di.addFilter(undertowFilter);
|
||||||
|
|
||||||
if (filterMappings.containsKey(filterName)) {
|
if (filterMappings.containsKey(filterName)) {
|
||||||
|
|
|
@ -75,9 +75,11 @@ public class InputServlet extends HttpServlet {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.setContentType("text/plain");
|
resp.setContentType("text/html");
|
||||||
PrintWriter pw = resp.getWriter();
|
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();
|
pw.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.jboss.logging.Logger.Level;
|
||||||
import org.jboss.shrinkwrap.api.Archive;
|
import org.jboss.shrinkwrap.api.Archive;
|
||||||
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
||||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
import org.keycloak.adapters.servlet.KeycloakOIDCFilter;
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
|
import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
|
||||||
import org.keycloak.testsuite.util.IOUtil;
|
import org.keycloak.testsuite.util.IOUtil;
|
||||||
|
@ -207,6 +208,28 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
|
||||||
filter.appendChild(filterClass);
|
filter.appendChild(filterClass);
|
||||||
appendChildInDocument(webXmlDoc, "web-app", filter);
|
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");
|
Element filterMapping = webXmlDoc.createElement("filter-mapping");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.ApplicationArchiveProcessor;
|
||||||
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
|
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
|
||||||
import org.jboss.arquillian.core.spi.LoadableExtension;
|
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.ContainerCustomizableURLResourceProvider;
|
||||||
import org.jboss.arquillian.graphene.location.CustomizableURLResourceProvider;
|
import org.jboss.arquillian.graphene.location.CustomizableURLResourceProvider;
|
||||||
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
|
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.SuiteContextProvider;
|
||||||
import org.keycloak.testsuite.arquillian.provider.TestContextProvider;
|
import org.keycloak.testsuite.arquillian.provider.TestContextProvider;
|
||||||
import org.keycloak.testsuite.arquillian.provider.URLProvider;
|
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(ResourceProvider.class, ContainerCustomizableURLResourceProvider.class, URLProvider.class)
|
||||||
.override(ApplicationArchiveProcessor.class, OSGiApplicationArchiveProcessor.class, KeycloakOSGiApplicationArchiveProcessor.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);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,5 @@ public @interface UseServletFilter {
|
||||||
String filterClass();
|
String filterClass();
|
||||||
String filterPattern() default "/*";
|
String filterPattern() default "/*";
|
||||||
String dispatcherType() default "";
|
String dispatcherType() default "";
|
||||||
|
String skipPattern() default "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.client.resources;
|
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.LogoutAction;
|
||||||
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
|
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
|
||||||
import org.keycloak.representations.adapters.action.TestAvailabilityAction;
|
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.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
@ -53,6 +55,11 @@ public interface TestApplicationResource {
|
||||||
@Path("/clear-admin-actions")
|
@Path("/clear-admin-actions")
|
||||||
Response clearAdminActions();
|
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")
|
@Path("/oidc-client-endpoints")
|
||||||
TestOIDCEndpointsApplicationResource oidcClientEndpoints();
|
TestOIDCEndpointsApplicationResource oidcClientEndpoints();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,6 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.NotFoundException;
|
||||||
import org.jboss.arquillian.container.test.api.RunAsClient;
|
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.client.KeycloakTestingClient;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
import org.keycloak.testsuite.util.TestEventsLogger;
|
import org.keycloak.testsuite.util.TestEventsLogger;
|
||||||
import org.keycloak.testsuite.util.WaitUtils;
|
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
||||||
|
@ -155,8 +153,6 @@ public abstract class AbstractKeycloakTest {
|
||||||
|
|
||||||
setDefaultPageUriParameters();
|
setDefaultPageUriParameters();
|
||||||
|
|
||||||
driverSettings();
|
|
||||||
|
|
||||||
TestEventsLogger.setDriver(driver);
|
TestEventsLogger.setDriver(driver);
|
||||||
|
|
||||||
if (!suiteContext.isAdminPasswordUpdated()) {
|
if (!suiteContext.isAdminPasswordUpdated()) {
|
||||||
|
@ -198,12 +194,6 @@ public abstract class AbstractKeycloakTest {
|
||||||
driver.manage().deleteAllCookies();
|
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() {
|
public void setDefaultPageUriParameters() {
|
||||||
masterRealmPage.setAuthRealm(MASTER);
|
masterRealmPage.setAuthRealm(MASTER);
|
||||||
loginPage.setAuthRealm(MASTER);
|
loginPage.setAuthRealm(MASTER);
|
||||||
|
|
|
@ -23,11 +23,14 @@ import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
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.jboss.arquillian.graphene.page.Page;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
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.RoleMappingResource;
|
||||||
import org.keycloak.admin.client.resource.RoleScopeResource;
|
import org.keycloak.admin.client.resource.RoleScopeResource;
|
||||||
import org.keycloak.models.AccountRoles;
|
import org.keycloak.models.AccountRoles;
|
||||||
|
@ -37,15 +40,25 @@ import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
import org.keycloak.testsuite.admin.ApiUtil;
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
|
import org.keycloak.testsuite.client.resources.TestApplicationResource;
|
||||||
import org.keycloak.testsuite.pages.AccountApplicationsPage;
|
import org.keycloak.testsuite.pages.AccountApplicationsPage;
|
||||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||||
import org.keycloak.testsuite.util.ClientBuilder;
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
import org.keycloak.testsuite.util.RealmBuilder;
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
import org.keycloak.testsuite.util.RealmRepUtil;
|
import org.keycloak.testsuite.util.RealmRepUtil;
|
||||||
import org.keycloak.testsuite.util.UserBuilder;
|
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.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.JSONArray;
|
||||||
import twitter4j.JSONObject;
|
import twitter4j.JSONObject;
|
||||||
|
|
||||||
|
@ -79,6 +92,7 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
.password("password")
|
.password("password")
|
||||||
.build();
|
.build();
|
||||||
RealmBuilder.edit(testRealm)
|
RealmBuilder.edit(testRealm)
|
||||||
|
.accessTokenLifespan(1000)
|
||||||
.user(user2);
|
.user(user2);
|
||||||
|
|
||||||
ClientBuilder.edit(RealmRepUtil.findClientByClientId(testRealm, "test-app"))
|
ClientBuilder.edit(RealmRepUtil.findClientByClientId(testRealm, "test-app"))
|
||||||
|
@ -155,12 +169,15 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||||
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
|
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]);
|
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
|
@Test
|
||||||
public void getProfileCorsInvalidOrigin() throws Exception {
|
public void getProfileCorsInvalidOrigin() throws Exception {
|
||||||
oauth.doLogin("test-user@localhost", "password");
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
@ -168,12 +185,16 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||||
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
|
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
|
||||||
|
|
||||||
driver.navigate().to("http://invalid.localtest.me:8180");
|
String[] response = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
doGetProfileJs(token);
|
response = doGetProfileJs("http://invalid.localtest.me:8180/auth", token);
|
||||||
fail("Expected failure");
|
} catch (WebDriverException ex) {
|
||||||
} catch (Throwable t) {
|
// 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();
|
profilePage.open();
|
||||||
loginPage.login("test-user@localhost", "password");
|
loginPage.login("test-user@localhost", "password");
|
||||||
|
|
||||||
String[] response = doGetProfileJs(null);
|
String[] response = doGetProfileJs(OAuthClient.AUTH_SERVER_ROOT, null);
|
||||||
assertEquals("200", response[0]);
|
assertEquals("200", response[0]);
|
||||||
|
|
||||||
JSONObject profile = new JSONObject(response[1]);
|
JSONObject profile = new JSONObject(response[1]);
|
||||||
|
@ -253,19 +274,36 @@ public class ProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
return client.execute(get);
|
return client.execute(get);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] doGetProfileJs(String token) {
|
private String[] doGetProfileJs(String authServerRoot, String token) {
|
||||||
StringBuilder sb = new StringBuilder();
|
UriBuilder uriBuilder = UriBuilder.fromUri(authServerRoot)
|
||||||
sb.append("var req = new XMLHttpRequest();\n");
|
.path(TestApplicationResource.class)
|
||||||
sb.append("req.open('GET', '" + getAccountURI().toString() + "', false);\n");
|
.path(TestApplicationResource.class, "getAccountProfile")
|
||||||
if (token != null) {
|
.queryParam("account-uri", getAccountURI().toString());
|
||||||
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");
|
|
||||||
|
|
||||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
if (token != null) {
|
||||||
String response = (String) js.executeScript(sb.toString());
|
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("///");
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@UseServletFilter(filterName = "oidc-filter", filterClass = "org.keycloak.adapters.servlet.KeycloakOIDCFilter",
|
@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 {
|
public abstract class AbstractDemoFilterServletAdapterTest extends AbstractDemoServletsAdapterTest {
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,17 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.common.Version;
|
import org.keycloak.common.Version;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
import org.keycloak.common.util.UriUtils;
|
||||||
import org.keycloak.constants.AdapterConstants;
|
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.OIDCLoginProtocol;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||||
import org.keycloak.representations.AccessToken;
|
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.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
||||||
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
|
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
|
||||||
import org.keycloak.testsuite.adapter.page.*;
|
import org.keycloak.testsuite.adapter.page.*;
|
||||||
|
@ -49,7 +54,6 @@ import org.keycloak.testsuite.util.URLUtils;
|
||||||
import org.keycloak.util.BasicAuthHelper;
|
import org.keycloak.util.BasicAuthHelper;
|
||||||
|
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
import org.openqa.selenium.WebElement;
|
|
||||||
|
|
||||||
import javax.ws.rs.client.Client;
|
import javax.ws.rs.client.Client;
|
||||||
import javax.ws.rs.client.ClientBuilder;
|
import javax.ws.rs.client.ClientBuilder;
|
||||||
|
@ -116,6 +120,9 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
@Page
|
@Page
|
||||||
private Config configPage;
|
private Config configPage;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public AssertEvents assertEvents = new AssertEvents(this);
|
||||||
|
|
||||||
@Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
|
@Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
|
||||||
protected static WebArchive customerPortal() {
|
protected static WebArchive customerPortal() {
|
||||||
return servletDeployment(CustomerPortal.DEPLOYMENT_NAME, CustomerServlet.class, ErrorServlet.class, ServletTestUtils.class);
|
return servletDeployment(CustomerPortal.DEPLOYMENT_NAME, CustomerServlet.class, ErrorServlet.class, ServletTestUtils.class);
|
||||||
|
@ -192,8 +199,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
|
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
|
||||||
testRealmLoginPage.form().login("bburke@redhat.com", "password");
|
testRealmLoginPage.form().login("bburke@redhat.com", "password");
|
||||||
assertCurrentUrlEquals(driver, inputPortal + "/secured/post");
|
assertCurrentUrlEquals(driver, inputPortal + "/secured/post");
|
||||||
String pageSource = driver.getPageSource();
|
waitUntilElement(By.xpath("//body")).text().contains("parameter=hello");
|
||||||
assertTrue(pageSource.contains("parameter=hello"));
|
|
||||||
|
|
||||||
String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
|
String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
|
||||||
.queryParam(OAuth2Constants.REDIRECT_URI, customerPortal.toString())
|
.queryParam(OAuth2Constants.REDIRECT_URI, customerPortal.toString())
|
||||||
|
@ -353,6 +359,10 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoginSSOMax() throws InterruptedException {
|
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
|
// test login to customer-portal which does a bearer request to customer-db
|
||||||
customerPortal.navigateTo();
|
customerPortal.navigateTo();
|
||||||
testRealmLoginPage.form().waitForUsernameInputPresent();
|
testRealmLoginPage.form().waitForUsernameInputPresent();
|
||||||
|
@ -600,6 +610,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
RealmRepresentation realm = testRealmResource().toRepresentation();
|
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||||
realm.setEventsEnabled(true);
|
realm.setEventsEnabled(true);
|
||||||
realm.setEnabledEventTypes(Arrays.asList("REVOKE_GRANT", "LOGIN"));
|
realm.setEnabledEventTypes(Arrays.asList("REVOKE_GRANT", "LOGIN"));
|
||||||
|
realm.setEventsListeners(Arrays.asList("jboss-logging", "event-queue"));
|
||||||
testRealmResource().update(realm);
|
testRealmResource().update(realm);
|
||||||
|
|
||||||
customerPortal.navigateTo();
|
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("Bill Burke");
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("Stian Thorgersen");
|
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.navigateTo();
|
||||||
applicationsPage.revokeGrantForApplication("customer-portal");
|
applicationsPage.revokeGrantForApplication("customer-portal");
|
||||||
|
|
||||||
|
@ -620,42 +651,14 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
|
|
||||||
assertTrue(oAuthGrantPage.isCurrent());
|
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()) {
|
assertEvents.assertEmpty();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -663,6 +666,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
RealmRepresentation realm = testRealmResource().toRepresentation();
|
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||||
realm.setEventsEnabled(true);
|
realm.setEventsEnabled(true);
|
||||||
realm.setEnabledEventTypes(Arrays.asList("LOGIN", "LOGIN_ERROR", "LOGOUT", "CODE_TO_TOKEN"));
|
realm.setEnabledEventTypes(Arrays.asList("LOGIN", "LOGIN_ERROR", "LOGOUT", "CODE_TO_TOKEN"));
|
||||||
|
realm.setEventsListeners(Arrays.asList("jboss-logging", "event-queue"));
|
||||||
testRealmResource().update(realm);
|
testRealmResource().update(realm);
|
||||||
|
|
||||||
customerPortal.navigateTo();
|
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("Bill Burke");
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("Stian Thorgersen");
|
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);
|
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()) {
|
assertEvents.assertEmpty();
|
||||||
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();
|
|
||||||
|
|
||||||
String serverLogPath = null;
|
String serverLogPath = null;
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.support.ui.ExpectedCondition;
|
import org.openqa.selenium.support.ui.ExpectedCondition;
|
||||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
@ -84,7 +85,7 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProviderIdpInitiatedLogin() {
|
public void testProviderIdpInitiatedLogin() throws Exception {
|
||||||
driver.navigate().to(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker"));
|
driver.navigate().to(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker"));
|
||||||
|
|
||||||
waitForPage("log in to");
|
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"));
|
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.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) {
|
private String getSamlIdpInitiatedUrl(String realmName, String samlIdpInitiatedSsoUrlName) {
|
||||||
|
|
|
@ -24,8 +24,9 @@
|
||||||
|
|
||||||
<extension qualifier="webdriver">
|
<extension qualifier="webdriver">
|
||||||
<property name="browser">${browser}</property>
|
<property name="browser">${browser}</property>
|
||||||
|
<property name="htmlUnit.version">${htmlUnitBrowserVersion}</property>
|
||||||
<property name="firefox_binary">${firefox_binary}</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>
|
||||||
|
|
||||||
<extension qualifier="graphene">
|
<extension qualifier="graphene">
|
||||||
|
|
|
@ -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.authentication.authenticators.browser.IdentityProviderAuthenticator=trace
|
||||||
# log4j.logger.org.keycloak.keys.infinispan=trace
|
# log4j.logger.org.keycloak.keys.infinispan=trace
|
||||||
log4j.logger.org.keycloak.services.clientregistration.policy=debug
|
log4j.logger.org.keycloak.services.clientregistration.policy=debug
|
||||||
|
|
|
@ -5,18 +5,18 @@
|
||||||
"sslRequired" : "external",
|
"sslRequired" : "external",
|
||||||
"roles" : {
|
"roles" : {
|
||||||
"client" : {
|
"client" : {
|
||||||
"http://localhost:18080/sales-post-enc/" : [ {
|
"http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth" : [ {
|
||||||
"name" : "manager"
|
"name" : "manager"
|
||||||
} ]
|
} ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"clients" : [ {
|
"clients" : [ {
|
||||||
"clientId": "http://localhost:18080/sales-post-enc/",
|
"clientId": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"protocol": "saml",
|
"protocol": "saml",
|
||||||
"fullScopeAllowed": true,
|
"fullScopeAllowed": true,
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"http://localhost:18080/sales-post-enc/*"
|
"http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth/*"
|
||||||
],
|
],
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"saml.authnstatement": "true",
|
"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.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"
|
"saml_idp_initiated_sso_url_name" : "sales"
|
||||||
},
|
},
|
||||||
"baseUrl": "http://localhost:18080/sales-post-enc/",
|
"baseUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth",
|
||||||
"adminUrl": "http://localhost:18080/sales-post-enc/saml"
|
"adminUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth"
|
||||||
} ],
|
} ],
|
||||||
"identityProviders" : [ {
|
"identityProviders" : [ {
|
||||||
"alias" : "saml-leaf",
|
"alias" : "saml-leaf",
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
"identityProviderMapper" : "saml-role-idp-mapper",
|
"identityProviderMapper" : "saml-role-idp-mapper",
|
||||||
"config" : {
|
"config" : {
|
||||||
"attribute.value" : "manager",
|
"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"
|
"attribute.name" : "Role"
|
||||||
}
|
}
|
||||||
} ]
|
} ]
|
||||||
|
|
|
@ -70,8 +70,10 @@
|
||||||
<migration.import.properties/>
|
<migration.import.properties/>
|
||||||
<examples.home>${project.build.directory}/examples</examples.home>
|
<examples.home>${project.build.directory}/examples</examples.home>
|
||||||
|
|
||||||
<browser>phantomjs</browser>
|
<browser>htmlUnit</browser>
|
||||||
|
<htmlUnitBrowserVersion>chrome</htmlUnitBrowserVersion>
|
||||||
<firefox_binary>/usr/bin/firefox</firefox_binary>
|
<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>
|
<frontend.console.output>true</frontend.console.output>
|
||||||
<backends.console.output>true</backends.console.output>
|
<backends.console.output>true</backends.console.output>
|
||||||
|
@ -181,7 +183,9 @@
|
||||||
<test.intermittent>${test.intermittent}</test.intermittent>
|
<test.intermittent>${test.intermittent}</test.intermittent>
|
||||||
|
|
||||||
<browser>${browser}</browser>
|
<browser>${browser}</browser>
|
||||||
|
<htmlUnitBrowserVersion>${htmlUnitBrowserVersion}</htmlUnitBrowserVersion>
|
||||||
<firefox_binary>${firefox_binary}</firefox_binary>
|
<firefox_binary>${firefox_binary}</firefox_binary>
|
||||||
|
<phantomjs.cli.args>${phantomjs.cli.args}</phantomjs.cli.args>
|
||||||
|
|
||||||
<project.version>${project.version}</project.version>
|
<project.version>${project.version}</project.version>
|
||||||
<migration.project.version>${migration.project.version}</migration.project.version>
|
<migration.project.version>${migration.project.version}</migration.project.version>
|
||||||
|
|
Loading…
Reference in a new issue