keycloak-aplcache
Changes
pom.xml 10(+8 -2)
testsuite/integration-arquillian/pom.xml 216(+35 -181)
testsuite/integration-arquillian/README.md 66(+53 -13)
testsuite/integration-arquillian/README_old.md 189(+189 -0)
testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/add-dialect-logger.xsl 28(+28 -0)
testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/add-dialect-logger.xsl 28(+28 -0)
testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/add-dialect-logger.xsl 28(+28 -0)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/account/AccountManagementTest.java 121(+0 -121)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/AbstractTest.java 91(+0 -91)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/fragment/Navigation.java 162(+0 -162)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/Account.java 93(+0 -93)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/Client.java 104(+0 -104)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/Role.java 72(+0 -72)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/model/User.java 146(+0 -146)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/account/PasswordPage.java 82(+0 -82)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/RegisterPage.java 99(+0 -99)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/ClientPage.java 134(+0 -134)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/DefaultRolesPage.java 55(+0 -55)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/PasswordPolicyPage.java 71(+0 -71)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/RolesPage.java 118(+0 -118)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/SecurityPage.java 109(+0 -109)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/user/RoleMappingsPage.java 71(+0 -71)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/page/settings/user/UserPage.java 204(+0 -204)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/client/AddNewClientTest.java 109(+0 -109)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/role/AddNewRoleTest.java 92(+0 -92)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/settings/ThemesSettingsTest.java 56(+0 -56)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/user/AddNewUserTest.java 119(+0 -119)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/admin/test/user/RoleMappingsTest.java 72(+0 -72)
testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/login/RegisterNewUserTest.java 136(+0 -136)
testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7DemoServletsAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7SessionServletAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/karaf/src/test/java/org/keycloak/testsuite/adapter/example/KarafFuseExampleAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatBasicAuthExampleAdapterTest.java 15(+15 -0)
testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatDemoExampleAdapterTest.java 16(+16 -0)
testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatDemoServletsAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatSessionServletAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java 14(+14 -0)
testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyDemoServletsAdapterTest.java 14(+14 -0)
testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflySessionServletAdapterTest.java 14(+14 -0)
testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java 14(+14 -0)
testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8DemoServletsAdapterTest.java 14(+14 -0)
testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8SessionServletAdapterTest.java 14(+14 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/arquillian.xsl 16(+16 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/standalone.xsl 51(+51 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeBasicAuthExampleAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeCorsExampleAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeDemoExampleAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeJSConsoleExampleAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeDemoServletsAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeSessionServletAdapterTest.java 12(+12 -0)
testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/resources/web.xml 9(+9 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/AdapterLibsMode.java 30(+30 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AngularCorsProductExample.java 77(+77 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AppServerContextRoot.java 23(+23 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BasicAuthExample.java 41(+41 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CorsDatabaseServiceExample.java 26(+26 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDb.java 25(+25 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDbErrorPage.java 25(+25 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortal.java 28(+28 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortalExample.java 80(+80 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/DatabaseServiceExample.java 25(+25 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AbstractFuseExample.java 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AdminInterface.java 17(+17 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerListing.java 36(+36 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerPortalFuseExample.java 34(+34 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/ProductPortalFuseExample.java 50(+50 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleExample.java 70(+70 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant.java 46(+46 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenantExample.java 46(+46 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortal.java 25(+25 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortalExample.java 59(+59 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SecurePortal.java 25(+25 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SessionPortal.java 25(+25 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CallAuthenticatedServlet.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerDatabaseServlet.java 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerServlet.java 59(+59 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ErrorServlet.java 27(+27 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java 43(+43 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantResolver.java 46(+46 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantServlet.java 48(+48 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ProductServlet.java 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SessionServlet.java 40(+40 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java 111(+111 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/Users.java 67(+67 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AdapterLibsLocationProperty.java 19(+19 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java 20(+20 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContext.java 18(+18 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AuthServerContext.java 18(+18 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java 61(+61 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/Registry.java 148(+148 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/RegistryCreator.java 186(+186 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/SecurityActions.java 307(+307 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java 187(+187 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java 140(+140 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java 40(+40 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JBossJiraParser.java 43(+43 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Jira.java 28(+28 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JiraTestExecutionDecider.java 61(+61 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Status.java 36(+36 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java 49(+49 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/AdminClientProvider.java 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/SuiteContextProvider.java 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/TestContextProvider.java 30(+30 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java 79(+79 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java 34(+34 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java 50(+50 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainer.java 144(+144 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainerConfiguration.java 35(+35 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java 75(+75 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java 59(+59 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java 83(+38 -45)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Applications.java 52(+34 -18)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Autheticator.java 19(+11 -8)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ChangePassword.java 39(+17 -22)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ContactInfoFields.java 24(+24 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/PasswordFields.java 38(+38 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Sessions.java 63(+27 -36)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthRealm.java 58(+58 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java 34(+34 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServerContextRoot.java 26(+26 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Authenticate.java 24(+24 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Login.java 72(+72 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java 43(+43 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java 83(+83 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/OIDCLogin.java 13(+13 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/PageWithLoginUrl.java 15(+15 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java 77(+77 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/ResetCredentials.java 46(+35 -11)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdateAccount.java 27(+27 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdatePassword.java 21(+21 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java 9(+9 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsole.java 88(+88 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleCreate.java 47(+47 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java 121(+121 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java 49(+49 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Authentication.java 57(+57 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Bindings.java 147(+147 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Flows.java 212(+212 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/OTPPolicy.java 85(+85 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java 100(+100 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/RequiredActions.java 55(+55 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java 107(+107 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientClustering.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientCredentials.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientInstallation.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientMappers.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRevocation.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java 36(+36 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRoles.java 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java 138(+138 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientScopeMappings.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSessions.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettings.java 18(+18 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettingsForm.java 91(+91 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClient.java 23(+23 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java 230(+230 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java 25(+25 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java 104(+104 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Config.java 99(+99 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Events.java 35(+35 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java 80(+80 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/CreateLdapUserProvider.java 20(+20 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/LdapUserProviderForm.java 130(+130 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/UserFederation.java 28(+28 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Breadcrumb.java 34(+34 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java 76(+76 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/FlashMessage.java 37(+18 -19)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/InputList.java 28(+28 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Menu.java 77(+42 -35)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java 36(+36 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/OnOffSwitch.java 75(+42 -33)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/PickList.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/RealmSelector.java 11(+11 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/idp/IdentityProviderSettings.java 103(+57 -46)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CacheSettings.java 42(+42 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CreateRealm.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/EmailSettings.java 70(+70 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/GeneralSettings.java 7(+3 -4)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/KeysSettings.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/LoginSettings.java 101(+63 -38)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/RealmSettings.java 72(+72 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/SecurityDefenses.java 197(+197 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java 36(+13 -23)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/TokenSettings.java 81(+48 -33)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/CreateRole.java 23(+23 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/DefaultRoles.java 25(+13 -12)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RealmRoles.java 27(+16 -11)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Role.java 33(+33 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java 182(+182 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java 101(+101 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java 42(+42 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java 85(+85 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/RealmSessions.java 21(+12 -9)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Revocation.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Sessions.java 32(+32 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/CreateUser.java 23(+23 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/User.java 83(+83 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributes.java 22(+22 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java 139(+139 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserConsents.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java 57(+57 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java 28(+28 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappingsForm.java 46(+46 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/Users.java 142(+142 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserSessions.java 14(+14 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/Provider.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/RequiredUserAction.java 30(+16 -14)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/SocialProvider.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/Theme.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java 83(+83 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java 23(+23 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java 57(+57 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/servlet/ApplicationServlet.java 61(+61 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java 43(+43 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPTestConfiguration.java 128(+128 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java 11(+11 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SecondBrowser.java 21(+11 -10)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Timer.java 57(+57 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java 61(+28 -33)
testsuite/integration-arquillian/tests/base/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java 104(+104 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java 176(+176 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AbstractAccountManagementTest.java 31(+31 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java 80(+80 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ChangePasswordTest.java 67(+67 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/RegistrationTest.java 132(+132 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResetCredentialsTest.java 101(+101 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/VerifyEmailTest.java 88(+88 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java 139(+139 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java 62(+62 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java 45(+45 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractBasicAuthExampleAdapterTest.java 68(+68 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java 105(+105 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java 157(+157 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java 131(+131 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java 133(+133 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java 386(+386 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java 184(+184 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java 111(+111 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java 164(+164 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/RequiredActionsTest.java 137(+137 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java 74(+74 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java 273(+273 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java 163(+163 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java 84(+84 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java 85(+85 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/federation/LdapUserFederationTest.java 71(+71 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/idp/IdentityProviderTest.java 73(+36 -37)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/AbstractRealmTest.java 27(+27 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java 78(+78 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java 255(+255 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/ThemeSettingsTest.java 57(+38 -19)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/TokensTest.java 94(+52 -42)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java 26(+26 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java 61(+61 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/RealmRolesTest.java 229(+229 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/sessions/SessionsTest.java 47(+28 -19)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java 39(+39 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/RequiredUserActionsTest.java 147(+147 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UserAttributesTest.java 90(+90 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UsersTest.java 52(+52 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AttributesAssert.java 42(+42 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java 54(+54 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java 77(+77 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/TestEventsLogger.java 44(+44 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java 95(+95 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/META-INF/context.xml 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak-relative.json 9(+9 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml 41(+41 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml 59(+59 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/META-INF/context.xml 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak.json 11(+11 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-cookie.json 12(+12 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-relative.json 9(+9 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml 59(+59 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json 161(+161 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/META-INF/context.xml 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml 40(+40 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml 16(+16 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant1-keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant2-keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/web.xml 42(+42 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/META-INF/context.xml 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak-relative.json 9(+9 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml 40(+40 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/META-INF/context.xml 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml 30(+30 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/META-INF/context.xml 3(+3 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml 29(+29 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json 10(+10 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml 40(+40 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant1-realm.json 82(+82 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant2-realm.json 72(+72 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json 99(+99 -0)
testsuite/integration-arquillian/tests/pom.xml 597(+597 -0)
Details
pom.xml 10(+8 -2)
diff --git a/pom.xml b/pom.xml
index 24e5785..054a034 100755
--- a/pom.xml
+++ b/pom.xml
@@ -1332,7 +1332,6 @@
<id>distribution</id>
<modules>
<module>distribution</module>
- <module>testsuite/integration-arquillian</module>
</modules>
</profile>
@@ -1341,7 +1340,6 @@
<modules>
<module>docbook</module>
<module>distribution</module>
- <module>testsuite/integration-arquillian</module>
</modules>
</profile>
@@ -1364,6 +1362,14 @@
</build>
</profile>
+ <profile>
+ <id>arquillian-integration-tests</id>
+ <modules>
+ <module>distribution</module>
+ <module>testsuite/integration-arquillian</module>
+ </modules>
+ </profile>
+
<!-- Configure the JBoss Early Access Maven repository -->
<profile>
<id>jboss-earlyaccess-repository</id>
testsuite/integration-arquillian/pom.xml 216(+35 -181)
diff --git a/testsuite/integration-arquillian/pom.xml b/testsuite/integration-arquillian/pom.xml
index 2ef2ac3..064e065 100644
--- a/testsuite/integration-arquillian/pom.xml
+++ b/testsuite/integration-arquillian/pom.xml
@@ -2,190 +2,44 @@
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parent>
- <artifactId>keycloak-testsuite-pom</artifactId>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-testsuite-pom</artifactId>
<version>1.6.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
-
- <artifactId>keycloak-testsuite-integration-arquillian</artifactId>
- <name>KeyCloak Arquillian TestSuite</name>
-
- <properties>
- <browser>phantomjs</browser>
-
- <arquillian-core.version>1.1.5.Final</arquillian-core.version>
- <selenium.version>2.45.0</selenium.version>
- <arquillian-drone.version>1.3.1.Final</arquillian-drone.version>
- <arquillian-phantomjs.version>1.1.4.Final</arquillian-phantomjs.version>
- <arquillian-graphene.version>2.0.3.Final</arquillian-graphene.version>
- <arquillian-wildfly-container.version>8.1.0.Final</arquillian-wildfly-container.version>
-
- <!-- Used in profile "wildfly-8-remote".
- Set to "false" if admin password has already been updated after first login. -->
- <firstAdminLogin>true</firstAdminLogin>
- </properties>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.jboss.arquillian.selenium</groupId>
- <artifactId>selenium-bom</artifactId>
- <version>${selenium.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian</groupId>
- <artifactId>arquillian-bom</artifactId>
- <version>${arquillian-core.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.extension</groupId>
- <artifactId>arquillian-drone-bom</artifactId>
- <version>${arquillian-drone.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- <dependency>
- <groupId>org.wildfly</groupId>
- <artifactId>wildfly-arquillian-container-remote</artifactId>
- <version>${arquillian-wildfly-container.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wildfly</groupId>
- <artifactId>wildfly-arquillian-container-managed</artifactId>
- <version>${arquillian-wildfly-container.version}</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.junit</groupId>
- <artifactId>arquillian-junit-container</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.graphene</groupId>
- <artifactId>graphene-webdriver</artifactId>
- <version>${arquillian-graphene.version}</version>
- <type>pom</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.extension</groupId>
- <artifactId>arquillian-phantom-driver</artifactId>
- <version>${arquillian-phantomjs.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-server-dist</artifactId>
- <scope>test</scope>
- <type>zip</type>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- </dependency>
- </dependencies>
-
- <profiles>
- <profile>
- <id>wildfly-8-remote</id>
- <dependencies>
- <dependency>
- <groupId>org.wildfly</groupId>
- <artifactId>wildfly-arquillian-container-remote</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemPropertyVariables>
- <shouldDeploy>false</shouldDeploy>
- <arquillian.launch>wildfly-8-remote</arquillian.launch>
- <browser>${browser}</browser>
- <firstAdminLogin>${first.login}</firstAdminLogin>
- </systemPropertyVariables>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
-
- <profile>
- <id>wildfly-8-managed</id>
- <activation>
- <activeByDefault>true</activeByDefault>
- </activation>
- <dependencies>
- <dependency>
- <groupId>org.wildfly</groupId>
- <artifactId>wildfly-arquillian-container-managed</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <properties>
- <install.directory>${project.build.directory}/install</install.directory>
- <jbossHome>${install.directory}/keycloak-${project.version}</jbossHome>
- </properties>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <version>2.10</version>
- <executions>
- <execution>
- <id>unpack</id>
- <phase>process-test-resources</phase>
- <goals>
- <goal>unpack</goal>
- </goals>
- <configuration>
- <artifactItems>
- <artifactItem>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-server-dist</artifactId>
- <type>zip</type>
- <overWrite>false</overWrite>
- </artifactItem>
- </artifactItems>
- <outputDirectory>${install.directory}</outputDirectory>
- <overWriteReleases>false</overWriteReleases>
- <overWriteSnapshots>true</overWriteSnapshots>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <systemPropertyVariables>
- <shouldDeploy>false</shouldDeploy>
- <arquillian.launch>wildfly-8-managed</arquillian.launch>
- <browser>${browser}</browser>
- <jbossHome>${jbossHome}</jbossHome>
- </systemPropertyVariables>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
- </profiles>
+
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian</artifactId>
+ <packaging>pom</packaging>
+ <name>Keycloak Integration TestSuite with Arquillian</name>
+
+ <modules>
+ <module>servers</module>
+ <module>tests</module>
+ </modules>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.18.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <version>1.0</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+
</project>
testsuite/integration-arquillian/README.md 66(+53 -13)
diff --git a/testsuite/integration-arquillian/README.md b/testsuite/integration-arquillian/README.md
index a81701d..7620d98 100644
--- a/testsuite/integration-arquillian/README.md
+++ b/testsuite/integration-arquillian/README.md
@@ -1,21 +1,61 @@
-Testing admin console with Arquillian
-=====================================
+# Keycloak Integration Testsuite with Arquillian
-There are currently two ways of running the tests with help of Arquillian.
+## Structure
-Remote mode
-----------
+```
+integration-arquillian
+│
+├──servers (submodules enabled via profiles)
+│ ├──wildfly
+│ └──eap6
+│
+└──tests
+ ├──base
+ └──adapters (submodules enabled via profiles, all depend on base)
+ ├──wildfly
+ ├──wildfly-relative (needs servers/wildfly)
+ ├──wildfly8
+ ├──as7
+ ├──tomcat
+ └──karaf
-Just simply typle `mvn verify` and you are all set. This requires the instance of Wildfly with embedded Keycloak to be already running.
+```
-Managed mode
-------------
+## General Concepts
-You need to pass two arguments to Maven, first is location of your Wildfly server with embedded Keycloak and the other is name of the profile.
+The testsuite supports **multiple server runtimes** for the Keycloak server.
+The **default is Undertow** which is the fastest and easiest option, and runs in the same JVM as the tests.
- mvn verify -Pwildfly-8-managed -DjbossHome=/your/server/location
+Other options are **Wildfly 9** and **EAP 6**. These have some additional requirements and limitations:
+1. The selected server module must be built before any tests can be run.
+All server-side configuration is done during this build (e.g. datasource configuration).
+Once server artifact is built the tests modules can unpack it via `maven-dependency-plugin` into their working directory before running.
+2. Before the selected server module can be built the `keycloak/distribution` module also needs to be built.
-Browser
--------
+### Server Runtimes
-There are currently two supported browsers - PhantomJS and Firefox. PhantomJS is the default one, in order to use Firefox just specify `-Dbrowser=firefox` parameter in the Maven command.
+TODO: explain why separate module, list config options, note on migration modules
+
+### Base Testsuite
+
+login flows + account management
+
+admin ui
+
+abstract adapter tests
+
+### Adapter Tests
+
+test servlets: demo, session
+
+examples
+
+## Running the Tests
+
+### Undertow
+
+### Wildfly or EAP 6
+
+### Adapters
+
+### Supported Browsers
\ No newline at end of file
testsuite/integration-arquillian/README_old.md 189(+189 -0)
diff --git a/testsuite/integration-arquillian/README_old.md b/testsuite/integration-arquillian/README_old.md
new file mode 100644
index 0000000..76357ce
--- /dev/null
+++ b/testsuite/integration-arquillian/README_old.md
@@ -0,0 +1,189 @@
+# Keycloak Integration Testsuite with Arquillian
+
+*OUT OF DATE - NEEDS REWRITE*
+
+## Usage
+
+Running the tests: `mvn test` or `mvn clean test`
+
+## Test suite
+
+### Selecting container for Keycloak Server
+
+The testsuite requires a container for Keycloak Server to be selected.
+This container is used by all tests in the suite during a single test execution.
+
+*By default* the tests run with server on embedded *Undertow*.
+A different container can be selected with profile, e.g. `-Pauth-server-wildfly`.
+
+### Containers Supported for Keycloak Server
+
+| Container | Arquillian Qualifier | Maven | Dependencies |
+| --- | --- | --- | --- |
+| **Undertow** | `auth-server-undertow` | **default** | `undertow-core`, `resteasy-undertow` |
+| **Wildfly 9** | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay` |
+| **EAP 6.4** | `auth-server-eap6` | `-Pauth-server-eap6` | `keycloak-server-dist` or `eap6-dist`+`keycloak-server-overlay` |
+
+See the relevant container definitions in `arquillian.xml` located in the **test resources** folder.
+
+### Test Class Hierarchy
+```
+AbstractKeycloakTest
+├── AbstractAdminConsoleTest
+└── AbstractAdapterTest
+```
+
+### AbstractKeycloakTest
+
+Handles test realms. Provides Admin Client for REST operations.
+
+* **@BeforeClass**
+ 1. Updates the admin password to enable the admin user.
+* **@Before**
+ 1. Initiates admin client
+ 2. Imports test realms. (Loading test realms is overriden in subclasses.)
+* **@After**
+ 1. Removes test realms.
+ 2. Closes admin client.
+
+### ContainersTestEnricher
+
+Manages *container lifecycles*.
+
+`ContainersTestEnricher` is a custom Arquillian observer that handles lifecycles of auth server and app server containers for each test class.
+Containers are started during `@BeforeClass` and shut down during `@AfterClass` event.
+
+*Optionally* each test class can be annotated with `@AuthServerContainer("qualifier")` and `@AppServerConatiner("qualifier")` annotations
+to indicate containers required for the test.
+
+* In case `@AuthServerContainer` is not present the *auth server qualifier* is loaded from `auth.server.container` property.
+* In case `@AppServerContainer` is not present or it's value is the same as *auth server qualifier*, the app server isn't started for the test class.
+
+## Admin Console Tests
+
+Tests for admin console are located in `org/keycloak/testsuite/console`.
+Related non-test classes are located on the same path in the **main sources**.
+
+Admin console tests are **ENABLED by default**. They can be disabled by `-P no-console`.
+
+
+## Adapter Tests
+
+Adapter tests are located in `org/keycloak/testsuite/adapter`.
+Related non-test classes can be found on the same path in the **main sources**.
+
+Adapter tests are **DISABLED by default**. They can be enabled by profiles.
+Multiple profiles can be enabled for a single test execution.
+
+*Note:* When testing adapter with multiple containers in a single run it is better
+to use the `--fail-at-end` (`-fae`) strategy instead of the default `--fail-fast` one.
+This will allow Maven to continue building other modules even if some of them have test failures.
+
+### Containers Supported for Adapter Tests
+
+| Container | Arquillian Qualifier | Maven | Dependencies |
+| --- | --- | --- | --- |
+| **Wildfly 9** Relative | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay`, `keycloak-adapter-dist-wf9` |
+| **Wildfly 9** | `app-server-wildfly` | `-Papp-server-wildfly` | `wildfly-dist`, `keycloak-adapter-dist-wf9` |
+| **Wildfly 8** | `app-server-wildfly` | `-Papp-server-wildfly8` | `wildfly-dist:8.2.1.Final`, `keycloak-adapter-dist-wf8` |
+| **JBoss AS 7** | `app-server-as7` | `-Papp-server-as7` | `jboss-as-dist`, `keycloak-adapter-dist-as7` |
+| **Tomcat 8** | `app-server-tomcat` | `-Papp-server-tomcat` | `tomcat`, `keycloak-tomcat8-adapter-dist` |
+| **Karaf 3** | `app-server-karaf` | `-Papp-server-karaf` | `apache-camel`, `apache-cxf`, `keycloak-osgi-features`, `keycloak-fuse-example-features` |
+
+See the relevant container definitions in `tests/adapter/<container>/src/main/xslt/arquillian.xsl`.
+
+***Important:*** Arquillian cannot load multiple controllers for JBossAS/Wildfly containers in a single run (because same class name)
+but a different controller is required for JBossAS7/EAP6 than for WF8/9. Because of this:
+
+ - Adapter tests for *Wildfly 8/9* cannot be run against server on *EAP 6*. `-Papp-server-wildfly*` ⇒ `!auth-server-eap6`
+ - Adapter tests for *JBossAS 7* can only be run against server on *EAP 6*. `-Papp-server-as7,auth-server-eap6`
+
+### Adapter Test Types
+
+1. Using **test servlets**.
+2. Using **example/demo wars**.
+
+```
+AbstractKeycloakTest
+└── AbstractAdapterTest
+ ├── AbstractServletsAdapterTest
+ | ├── Relative…
+ | ├── Wildfly…
+ | ├── Tomcat…
+ | …
+ └── AbstractExampleAdapterTest
+ ├── AbstractDemoExampleAdapterTest
+ | ├── Relative…
+ | ├── Wildfly…
+ | ├── Tomcat…
+ | …
+ ├── AbstractBasicAuthExampleAdapterTest
+ | ├── Relative…
+ | ├── Wildfly…
+ | ├── Tomcat…
+ | …
+ …
+```
+
+### Relative vs Non-relative scenario
+
+The test suite can handle both types.
+It automatically modifies imported test realms and deployments' adapter configs based on scenario type.
+
+| Scenario | Description | Realm config (server side) | Adapter config (client side) |
+| --- | --- | --- | --- |
+| **Relative** | Both Keycloak Server and test apps running in the same container. | client `baseUrl`, `adminUrl` and `redirect-uris` can be relative | `auth-server-url` can be relative |
+| **Non-relative** | Test apps run in a different container than Keycloak Server. | client `baseUrl`, `adminUrl` and `redirect-uris` need to include FQDN of the app server | `auth-server-url` needs to include FQDN of the auth server|
+
+### Adapter Libraries Mode
+
+1. **Provided.** By container, e.g. as a subsystem. *Default.*
+2. **Bundled.** In the deployed war in `/WEB-INF/libs`. Enable with `-Dadapter.libs.bundled`. *Wildfly only*.
+
+### Adapter Config Mode
+
+1. ~~**Provided.** In `standalone.xml` using `secure-deployment`. *Wildfly only.*~~ WIP
+2. **Bundled.** In the deployed war in `/WEB-INF/keycloak.json`. *Default.*
+
+### Adapters Test Coverage
+
+| Module | Coverage | Supported Containers |
+| --- | --- | --- |
+| ***Test Servlets*** | Good | All |
+| **Demo** | Minimal, WIP | `auth-server-wildfly` (relative) |
+| **Admin Client** | |
+| **Cordova** | |
+| **CORS** | |
+| **JS Console** | Good | `auth-server-wildfly` (relative) |
+| **Providers** | |
+| Themes | |
+| Multitenancy | WIP | |
+| **Basic Auth** | Good | All |
+| **Fuse** | Good | `app-server-karaf` |
+| SAML | |
+| LDAP | |
+| Kerberos | |
+
+## Supported Browsers
+
+| Browser | Maven |
+| --- | --- |
+| **PhantomJS** | `-Dbrowser=phantomjs` **default** |
+| **Firefox** | `-Dbrowser=firefox` |
+
+
+## Custom Arquillian Extensions
+
+Custom extensions are registered in `META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension`.
+
+* Multiple containers extension
+ * Replaces Arquillian's default container handling.
+ * Allows to manage multiple container instances of different types within a single test run.
+ * Allows to skip loading disabled containers based on `enabled` config property in `arquillian.xml`.
+* Custom extension
+ * `ContainersTestEnricher` - Handles lifecycles of auth-server and app-server.
+ * `CustomUndertowContainer` - A custom container controller for JAX-RS-enabled Undertow with Keycloak Server.
+ * `DeploymentArchiveProcessor` - Modifies adapter config before deployment on app server based on relative/non-relative scenario.
+ * `URLProvider` - Fixes URLs injected by Arquillian which contain 127.0.0.1 instead of localhost.
+ * `JiraTestExecutionDecider` - Skipping tests for unresolved JIRAs.
+
diff --git a/testsuite/integration-arquillian/servers/eap6/assembly.xml b/testsuite/integration-arquillian/servers/eap6/assembly.xml
new file mode 100644
index 0000000..537dd4e
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+
+ <id>auth-server-eap6</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-${project.version}</outputDirectory>
+ <excludes>
+ <exclude>**/*.sh</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-${project.version}</outputDirectory>
+ <includes>
+ <include>**/*.sh</include>
+ </includes>
+ <fileMode>0755</fileMode>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/eap6/pom.xml b/testsuite/integration-arquillian/servers/eap6/pom.xml
new file mode 100644
index 0000000..4bab815
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/pom.xml
@@ -0,0 +1,184 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-servers</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-server-eap6</artifactId>
+ <packaging>pom</packaging>
+ <name>Server on EAP 6</name>
+
+ <properties>
+ <keycloak.server.home>${project.build.directory}/unpacked/jboss-eap-6.4</keycloak.server.home>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-dist</artifactId>
+ <version>${jboss.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-overlay-eap6</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-eap6-adapter-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-eap6-and-server-overlay</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-dist</artifactId>
+ <version>${jboss.version}</version>
+ <type>zip</type>
+ <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-overlay-eap6</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${keycloak.server.home}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>move-standalone-keycloak-xml</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <tasks>
+ <move file="${keycloak.server.home}/standalone/configuration/standalone-keycloak.xml"
+ tofile="${keycloak.server.home}/standalone/configuration/standalone.xml"/>
+ </tasks>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-zip</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>adapter-libs-provided</id>
+ <activation>
+ <property>
+ <name>!adapter.libs.bundled</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-adapter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-eap6-adapter-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${keycloak.server.home}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-adapter-subsystem</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/testsuite/integration-arquillian/servers/eap6/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+
+ <!-- Remove keycloak datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+ </xsl:template>
+
+ <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+ <xsl:param name="driver" select="'h2'"/>
+
+ <xsl:param name="username" select="'sa'"/>
+ <xsl:param name="password" select="'sa'"/>
+
+ <xsl:param name="min.poolsize" select="'10'"/>
+ <xsl:param name="max.poolsize" select="'50'"/>
+ <xsl:param name="pool.prefill" select="'true'"/>
+
+ <xsl:variable name="newDatasourceDefinition">
+ <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+ <connection-url>
+ <xsl:value-of select="$jdbc.url"/>
+ </connection-url>
+ <driver>
+ <xsl:value-of select="$driver"/>
+ </driver>
+ <security>
+ <user-name>
+ <xsl:value-of select="$username"/>
+ </user-name>
+ <password>
+ <xsl:value-of select="$password"/>
+ </password>
+ </security>
+ <pool>
+ <min-pool-size>
+ <xsl:value-of select="$min.poolsize"/>
+ </min-pool-size>
+ <max-pool-size>
+ <xsl:value-of select="$max.poolsize"/>
+ </max-pool-size>
+ <prefill>
+ <xsl:value-of select="$pool.prefill"/>
+ </prefill>
+ </pool>
+ </datasource>
+ </xsl:variable>
+
+ <xsl:variable name="newDriverDefinition">
+ <xsl:if test="$driver != 'h2'">
+ <driver name="{$driver}" module="com.{$driver}" />
+ </xsl:if>
+ </xsl:variable>
+
+ <!-- Add new datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDatasourceDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Add new driver definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDriverDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/eap6/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:m="urn:jboss:module:1.3"
+ version="2.0"
+ exclude-result-prefixes="xalan m">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+
+
+ <xsl:param name="database" select="''"/>
+ <xsl:param name="version" select="''"/>
+
+ <xsl:variable name="newModuleDefinition">
+ <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+ <resources>
+ <resource-root path="{$database}-{$version}.jar"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="javax.transaction.api"/>
+ </dependencies>
+ </module>
+ </xsl:variable>
+
+ <!-- clear whole document -->
+ <xsl:template match="/*" />
+
+ <!-- Copy new module definition. -->
+ <xsl:template match="/*">
+ <xsl:copy-of select="$newModuleDefinition"/>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/eap6/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..4ffc2c6
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/eap6/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:1.7"
+ xmlns:ds="urn:jboss:domain:datasources:1.2"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.1"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:param name="config"/>
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="//j:extensions">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//j:profile">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//sec:security-domains">
+ <xsl:copy>
+ <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ <security-domain name="sp" cache-type="default">
+ <authentication>
+ <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/pom.xml b/testsuite/integration-arquillian/servers/pom.xml
new file mode 100644
index 0000000..254e40e
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-servers</artifactId>
+ <packaging>pom</packaging>
+ <name>Servers</name>
+
+ <profiles>
+ <profile>
+ <id>auth-server-wildfly</id>
+ <modules>
+ <module>wildfly</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>auth-server-eap6</id>
+ <modules>
+ <!--doesn't work yet, WIP-->
+ <module>eap6</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>migration-kc14</id>
+ <modules>
+ <module>wildfly_kc14</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>migration-kc13</id>
+ <modules>
+ <module>wildfly_kc13</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>migration-kc12</id>
+ <modules>
+ <module>wildfly_kc12</module>
+ </modules>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly/assembly.xml b/testsuite/integration-arquillian/servers/wildfly/assembly.xml
new file mode 100644
index 0000000..bfcad35
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+
+ <id>auth-server-wildfly</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-${project.version}</outputDirectory>
+ <excludes>
+ <exclude>**/*.sh</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-${project.version}</outputDirectory>
+ <includes>
+ <include>**/*.sh</include>
+ </includes>
+ <fileMode>0755</fileMode>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly/pom.xml b/testsuite/integration-arquillian/servers/wildfly/pom.xml
new file mode 100644
index 0000000..e2b91e7
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/pom.xml
@@ -0,0 +1,372 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-servers</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-server-wildfly</artifactId>
+ <packaging>pom</packaging>
+ <name>Server on Wildfly</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-zip</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>server-overlay</id>
+ <activation>
+ <property>
+ <name>server-overlay</name>
+ </property>
+ </activation>
+ <properties>
+ <keycloak.server.home>${project.build.directory}/unpacked/wildfly-${wildfly.version}</keycloak.server.home>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-wildfly-and-server-overlay</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-dist</artifactId>
+ <version>${wildfly.version}</version>
+ <type>zip</type>
+ <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-overlay</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${keycloak.server.home}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>move-standalone-keycloak-xml</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <tasks>
+ <move file="${keycloak.server.home}/standalone/configuration/standalone-keycloak.xml"
+ tofile="${keycloak.server.home}/standalone/configuration/standalone.xml"/>
+ </tasks>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>server-dist</id>
+ <activation>
+ <property>
+ <name>!server-overlay</name>
+ </property>
+ </activation>
+ <properties>
+ <keycloak.server.home>${project.build.directory}/unpacked/keycloak-${project.version}</keycloak.server.home>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-server</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>adapter-libs-provided</id>
+ <activation>
+ <property>
+ <name>!adapter.libs.bundled</name>
+ </property>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf9-adapter-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-adapter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf9-adapter-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${keycloak.server.home}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-adapter-subsystem</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>jpa</id>
+ <properties>
+ <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <id>enforce-properties</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireProperty>
+ <property>jdbc.mvn.groupId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.artifactId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.version</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.url</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.user</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.password</property>
+ </requireProperty>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>jdbc-driver</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${jdbc.mvn.groupId}</groupId>
+ <artifactId>${jdbc.mvn.artifactId}</artifactId>
+ <version>${jdbc.mvn.version}</version>
+ <type>jar</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-wildfly-datasource</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <!-- create module.xml in modules -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+ <stylesheet>src/main/xslt/module.xsl</stylesheet>
+ <includes>
+ <include>module.xml</include>
+ </includes>
+ <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+ <parameters>
+ <parameter>
+ <name>database</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>version</name>
+ <value>${jdbc.mvn.version}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add datasource to standalone.xml -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ <parameters>
+ <parameter>
+ <name>jdbc.url</name>
+ <value>${keycloak.connectionsJpa.url}</value>
+ </parameter>
+ <parameter>
+ <name>driver</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>username</name>
+ <value>${keycloak.connectionsJpa.user}</value>
+ </parameter>
+ <parameter>
+ <name>password</name>
+ <value>${keycloak.connectionsJpa.password}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add logger for org.hibernate.dialect.Dialect -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ version="2.0"
+ exclude-result-prefixes="xalan">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+ <logger category="org.hibernate.dialect.Dialect">
+ <level name="ALL"/>
+ </logger>
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@* | node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+
+ <!-- Remove keycloak datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+ </xsl:template>
+
+ <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+ <xsl:param name="driver" select="'h2'"/>
+
+ <xsl:param name="username" select="'sa'"/>
+ <xsl:param name="password" select="'sa'"/>
+
+ <xsl:param name="min.poolsize" select="'10'"/>
+ <xsl:param name="max.poolsize" select="'50'"/>
+ <xsl:param name="pool.prefill" select="'true'"/>
+
+ <xsl:variable name="newDatasourceDefinition">
+ <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+ <connection-url>
+ <xsl:value-of select="$jdbc.url"/>
+ </connection-url>
+ <driver>
+ <xsl:value-of select="$driver"/>
+ </driver>
+ <security>
+ <user-name>
+ <xsl:value-of select="$username"/>
+ </user-name>
+ <password>
+ <xsl:value-of select="$password"/>
+ </password>
+ </security>
+ <pool>
+ <min-pool-size>
+ <xsl:value-of select="$min.poolsize"/>
+ </min-pool-size>
+ <max-pool-size>
+ <xsl:value-of select="$max.poolsize"/>
+ </max-pool-size>
+ <prefill>
+ <xsl:value-of select="$pool.prefill"/>
+ </prefill>
+ </pool>
+ </datasource>
+ </xsl:variable>
+
+ <xsl:variable name="newDriverDefinition">
+ <xsl:if test="$driver != 'h2'">
+ <driver name="{$driver}" module="com.{$driver}" />
+ </xsl:if>
+ </xsl:variable>
+
+ <!-- Add new datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDatasourceDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Add new driver definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDriverDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:m="urn:jboss:module:1.3"
+ version="2.0"
+ exclude-result-prefixes="xalan m">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+
+
+ <xsl:param name="database" select="''"/>
+ <xsl:param name="version" select="''"/>
+
+ <xsl:variable name="newModuleDefinition">
+ <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+ <resources>
+ <resource-root path="{$database}-{$version}.jar"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="javax.transaction.api"/>
+ </dependencies>
+ </module>
+ </xsl:variable>
+
+ <!-- clear whole document -->
+ <xsl:template match="/*" />
+
+ <!-- Copy new module definition. -->
+ <xsl:template match="/*">
+ <xsl:copy-of select="$newModuleDefinition"/>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..a483717
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:param name="config"/>
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="//j:extensions">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//j:profile">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//sec:security-domains">
+ <xsl:copy>
+ <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ <security-domain name="sp" cache-type="default">
+ <authentication>
+ <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/assembly.xml b/testsuite/integration-arquillian/servers/wildfly_kc12/assembly.xml
new file mode 100644
index 0000000..b3e9e20
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+
+ <id>auth-server-wildfly-kc14</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-1.2.0.Final</outputDirectory>
+ <excludes>
+ <exclude>**/*.sh</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-1.2.0.Final</outputDirectory>
+ <includes>
+ <include>**/*.sh</include>
+ </includes>
+ <fileMode>0755</fileMode>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/pom.xml b/testsuite/integration-arquillian/servers/wildfly_kc12/pom.xml
new file mode 100644
index 0000000..2d98af1
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-servers</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-server-wildfly-kc12 </artifactId>
+ <packaging>pom</packaging>
+ <name>Keycloak 1.2.0.Final on Wildfly</name>
+
+ <properties>
+ <keycloak.server.home>${project.build.directory}/unpacked/keycloak-1.2.0.Final</keycloak.server.home>
+ <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <id>enforce-properties</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireProperty>
+ <property>jdbc.mvn.groupId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.artifactId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.version</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.url</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.user</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.password</property>
+ </requireProperty>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-server</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-dist</artifactId>
+ <version>1.2.0.Final</version>
+ <type>zip</type>
+ <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ <execution>
+ <id>jdbc-driver</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${jdbc.mvn.groupId}</groupId>
+ <artifactId>${jdbc.mvn.artifactId}</artifactId>
+ <version>${jdbc.mvn.version}</version>
+ <type>jar</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-wildfly-datasource</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <!-- create module.xml in modules -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+ <stylesheet>src/main/xslt/module.xsl</stylesheet>
+ <includes>
+ <include>module.xml</include>
+ </includes>
+ <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+ <parameters>
+ <parameter>
+ <name>database</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>version</name>
+ <value>${jdbc.mvn.version}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add datasource to standalone.xml -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ <parameters>
+ <parameter>
+ <name>jdbc.url</name>
+ <value>${keycloak.connectionsJpa.url}</value>
+ </parameter>
+ <parameter>
+ <name>driver</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>username</name>
+ <value>${keycloak.connectionsJpa.user}</value>
+ </parameter>
+ <parameter>
+ <name>password</name>
+ <value>${keycloak.connectionsJpa.password}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add logger for org.hibernate.dialect.Dialect to standalone.xml-->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-zip</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ version="2.0"
+ exclude-result-prefixes="xalan">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+ <logger category="org.hibernate.dialect.Dialect">
+ <level name="ALL"/>
+ </logger>
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@* | node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+
+ <!-- Remove keycloak datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+ </xsl:template>
+
+ <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+ <xsl:param name="driver" select="'h2'"/>
+
+ <xsl:param name="username" select="'sa'"/>
+ <xsl:param name="password" select="'sa'"/>
+
+ <xsl:param name="min.poolsize" select="'10'"/>
+ <xsl:param name="max.poolsize" select="'50'"/>
+ <xsl:param name="pool.prefill" select="'true'"/>
+
+ <xsl:variable name="newDatasourceDefinition">
+ <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+ <connection-url>
+ <xsl:value-of select="$jdbc.url"/>
+ </connection-url>
+ <driver>
+ <xsl:value-of select="$driver"/>
+ </driver>
+ <security>
+ <user-name>
+ <xsl:value-of select="$username"/>
+ </user-name>
+ <password>
+ <xsl:value-of select="$password"/>
+ </password>
+ </security>
+ <pool>
+ <min-pool-size>
+ <xsl:value-of select="$min.poolsize"/>
+ </min-pool-size>
+ <max-pool-size>
+ <xsl:value-of select="$max.poolsize"/>
+ </max-pool-size>
+ <prefill>
+ <xsl:value-of select="$pool.prefill"/>
+ </prefill>
+ </pool>
+ </datasource>
+ </xsl:variable>
+
+ <xsl:variable name="newDriverDefinition">
+ <xsl:if test="$driver != 'h2'">
+ <driver name="{$driver}" module="com.{$driver}" />
+ </xsl:if>
+ </xsl:variable>
+
+ <!-- Add new datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDatasourceDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Add new driver definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDriverDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc12/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:m="urn:jboss:module:1.3"
+ version="2.0"
+ exclude-result-prefixes="xalan m">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+
+
+ <xsl:param name="database" select="''"/>
+ <xsl:param name="version" select="''"/>
+
+ <xsl:variable name="newModuleDefinition">
+ <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+ <resources>
+ <resource-root path="{$database}-{$version}.jar"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="javax.transaction.api"/>
+ </dependencies>
+ </module>
+ </xsl:variable>
+
+ <!-- clear whole document -->
+ <xsl:template match="/*" />
+
+ <!-- Copy new module definition. -->
+ <xsl:template match="/*">
+ <xsl:copy-of select="$newModuleDefinition"/>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/assembly.xml b/testsuite/integration-arquillian/servers/wildfly_kc13/assembly.xml
new file mode 100644
index 0000000..08e3ebf
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+
+ <id>auth-server-wildfly-kc14</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-1.3.1.Final</outputDirectory>
+ <excludes>
+ <exclude>**/*.sh</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-1.3.1.Final</outputDirectory>
+ <includes>
+ <include>**/*.sh</include>
+ </includes>
+ <fileMode>0755</fileMode>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/pom.xml b/testsuite/integration-arquillian/servers/wildfly_kc13/pom.xml
new file mode 100644
index 0000000..58be6cc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-servers</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-server-wildfly-kc13</artifactId>
+ <packaging>pom</packaging>
+ <name>Keycloak 1.3.1.Final on Wildfly</name>
+
+ <properties>
+ <keycloak.server.home>${project.build.directory}/unpacked/keycloak-1.3.1.Final</keycloak.server.home>
+ <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <id>enforce-properties</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireProperty>
+ <property>jdbc.mvn.groupId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.artifactId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.version</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.url</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.user</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.password</property>
+ </requireProperty>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-server</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-dist</artifactId>
+ <version>1.3.1.Final</version>
+ <type>zip</type>
+ <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ <execution>
+ <id>jdbc-driver</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${jdbc.mvn.groupId}</groupId>
+ <artifactId>${jdbc.mvn.artifactId}</artifactId>
+ <version>${jdbc.mvn.version}</version>
+ <type>jar</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-wildfly-datasource</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <!-- create module.xml in modules -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+ <stylesheet>src/main/xslt/module.xsl</stylesheet>
+ <includes>
+ <include>module.xml</include>
+ </includes>
+ <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+ <parameters>
+ <parameter>
+ <name>database</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>version</name>
+ <value>${jdbc.mvn.version}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add datasource to standalone.xml -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ <parameters>
+ <parameter>
+ <name>jdbc.url</name>
+ <value>${keycloak.connectionsJpa.url}</value>
+ </parameter>
+ <parameter>
+ <name>driver</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>username</name>
+ <value>${keycloak.connectionsJpa.user}</value>
+ </parameter>
+ <parameter>
+ <name>password</name>
+ <value>${keycloak.connectionsJpa.password}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add logger for org.hibernate.dialect.Dialect to standalone.xml-->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-zip</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ version="2.0"
+ exclude-result-prefixes="xalan">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+ <logger category="org.hibernate.dialect.Dialect">
+ <level name="ALL"/>
+ </logger>
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@* | node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+
+ <!-- Remove keycloak datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+ </xsl:template>
+
+ <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+ <xsl:param name="driver" select="'h2'"/>
+
+ <xsl:param name="username" select="'sa'"/>
+ <xsl:param name="password" select="'sa'"/>
+
+ <xsl:param name="min.poolsize" select="'10'"/>
+ <xsl:param name="max.poolsize" select="'50'"/>
+ <xsl:param name="pool.prefill" select="'true'"/>
+
+ <xsl:variable name="newDatasourceDefinition">
+ <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+ <connection-url>
+ <xsl:value-of select="$jdbc.url"/>
+ </connection-url>
+ <driver>
+ <xsl:value-of select="$driver"/>
+ </driver>
+ <security>
+ <user-name>
+ <xsl:value-of select="$username"/>
+ </user-name>
+ <password>
+ <xsl:value-of select="$password"/>
+ </password>
+ </security>
+ <pool>
+ <min-pool-size>
+ <xsl:value-of select="$min.poolsize"/>
+ </min-pool-size>
+ <max-pool-size>
+ <xsl:value-of select="$max.poolsize"/>
+ </max-pool-size>
+ <prefill>
+ <xsl:value-of select="$pool.prefill"/>
+ </prefill>
+ </pool>
+ </datasource>
+ </xsl:variable>
+
+ <xsl:variable name="newDriverDefinition">
+ <xsl:if test="$driver != 'h2'">
+ <driver name="{$driver}" module="com.{$driver}" />
+ </xsl:if>
+ </xsl:variable>
+
+ <!-- Add new datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDatasourceDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Add new driver definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDriverDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc13/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:m="urn:jboss:module:1.3"
+ version="2.0"
+ exclude-result-prefixes="xalan m">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+
+
+ <xsl:param name="database" select="''"/>
+ <xsl:param name="version" select="''"/>
+
+ <xsl:variable name="newModuleDefinition">
+ <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+ <resources>
+ <resource-root path="{$database}-{$version}.jar"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="javax.transaction.api"/>
+ </dependencies>
+ </module>
+ </xsl:variable>
+
+ <!-- clear whole document -->
+ <xsl:template match="/*" />
+
+ <!-- Copy new module definition. -->
+ <xsl:template match="/*">
+ <xsl:copy-of select="$newModuleDefinition"/>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/assembly.xml b/testsuite/integration-arquillian/servers/wildfly_kc14/assembly.xml
new file mode 100644
index 0000000..da4b459
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/assembly.xml
@@ -0,0 +1,29 @@
+<assembly>
+
+ <id>auth-server-wildfly-kc14</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-1.4.0.Final</outputDirectory>
+ <excludes>
+ <exclude>**/*.sh</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>${keycloak.server.home}</directory>
+ <outputDirectory>keycloak-1.4.0.Final</outputDirectory>
+ <includes>
+ <include>**/*.sh</include>
+ </includes>
+ <fileMode>0755</fileMode>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/pom.xml b/testsuite/integration-arquillian/servers/wildfly_kc14/pom.xml
new file mode 100644
index 0000000..ba4ff50
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-servers</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-server-wildfly-kc14</artifactId>
+ <packaging>pom</packaging>
+ <name>Keycloak 1.4.0.Final on Wildfly</name>
+
+ <properties>
+ <keycloak.server.home>${project.build.directory}/unpacked/keycloak-1.4.0.Final</keycloak.server.home>
+ <jdbc.mvn.driver.deployment.dir>${keycloak.server.home}/modules/system/layers/base/com/${jdbc.mvn.artifactId}/main</jdbc.mvn.driver.deployment.dir>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <id>enforce-properties</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireProperty>
+ <property>jdbc.mvn.groupId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.artifactId</property>
+ </requireProperty>
+ <requireProperty>
+ <property>jdbc.mvn.version</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.url</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.user</property>
+ </requireProperty>
+ <requireProperty>
+ <property>keycloak.connectionsJpa.password</property>
+ </requireProperty>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-server</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-dist</artifactId>
+ <version>1.4.0.Final</version>
+ <type>zip</type>
+ <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ <execution>
+ <id>jdbc-driver</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${jdbc.mvn.groupId}</groupId>
+ <artifactId>${jdbc.mvn.artifactId}</artifactId>
+ <version>${jdbc.mvn.version}</version>
+ <type>jar</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${jdbc.mvn.driver.deployment.dir}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-wildfly-datasource</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <!-- create module.xml in modules -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/modules/system/layers/base/com/h2database/h2/main</dir>
+ <stylesheet>src/main/xslt/module.xsl</stylesheet>
+ <includes>
+ <include>module.xml</include>
+ </includes>
+ <outputDir>${jdbc.mvn.driver.deployment.dir}</outputDir>
+ <parameters>
+ <parameter>
+ <name>database</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>version</name>
+ <value>${jdbc.mvn.version}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add datasource to standalone.xml -->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/datasource.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ <parameters>
+ <parameter>
+ <name>jdbc.url</name>
+ <value>${keycloak.connectionsJpa.url}</value>
+ </parameter>
+ <parameter>
+ <name>driver</name>
+ <value>${jdbc.mvn.artifactId}</value>
+ </parameter>
+ <parameter>
+ <name>username</name>
+ <value>${keycloak.connectionsJpa.user}</value>
+ </parameter>
+ <parameter>
+ <name>password</name>
+ <value>${keycloak.connectionsJpa.password}</value>
+ </parameter>
+ </parameters>
+ </transformationSet>
+ <!-- add logger for org.hibernate.dialect.Dialect to standalone.xml-->
+ <transformationSet>
+ <dir>${keycloak.server.home}/standalone/configuration</dir>
+ <stylesheet>src/main/xslt/add-dialect-logger.xsl</stylesheet>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <outputDir>${keycloak.server.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-zip</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/add-dialect-logger.xsl b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/add-dialect-logger.xsl
new file mode 100644
index 0000000..b5dc8c4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/add-dialect-logger.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ version="2.0"
+ exclude-result-prefixes="xalan">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:logging:'"/>
+
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='root-logger' and starts-with(namespace-uri(), $nsDS)]">
+ <logger category="org.hibernate.dialect.Dialect">
+ <level name="ALL"/>
+ </logger>
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@* | node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/datasource.xsl b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/datasource.xsl
new file mode 100644
index 0000000..c06899f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/datasource.xsl
@@ -0,0 +1,94 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+
+ <xsl:variable name="nsDS" select="'urn:jboss:domain:datasources:'"/>
+
+ <!-- Remove keycloak datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasource' and starts-with(namespace-uri(), $nsDS) and @pool-name='KeycloakDS']">
+ </xsl:template>
+
+ <xsl:param name="jdbc.url" select="'jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE'"/>
+ <xsl:param name="driver" select="'h2'"/>
+
+ <xsl:param name="username" select="'sa'"/>
+ <xsl:param name="password" select="'sa'"/>
+
+ <xsl:param name="min.poolsize" select="'10'"/>
+ <xsl:param name="max.poolsize" select="'50'"/>
+ <xsl:param name="pool.prefill" select="'true'"/>
+
+ <xsl:variable name="newDatasourceDefinition">
+ <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+ <connection-url>
+ <xsl:value-of select="$jdbc.url"/>
+ </connection-url>
+ <driver>
+ <xsl:value-of select="$driver"/>
+ </driver>
+ <security>
+ <user-name>
+ <xsl:value-of select="$username"/>
+ </user-name>
+ <password>
+ <xsl:value-of select="$password"/>
+ </password>
+ </security>
+ <pool>
+ <min-pool-size>
+ <xsl:value-of select="$min.poolsize"/>
+ </min-pool-size>
+ <max-pool-size>
+ <xsl:value-of select="$max.poolsize"/>
+ </max-pool-size>
+ <prefill>
+ <xsl:value-of select="$pool.prefill"/>
+ </prefill>
+ </pool>
+ </datasource>
+ </xsl:variable>
+
+ <xsl:variable name="newDriverDefinition">
+ <xsl:if test="$driver != 'h2'">
+ <driver name="{$driver}" module="com.{$driver}" />
+ </xsl:if>
+ </xsl:variable>
+
+ <!-- Add new datasource definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDatasourceDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Add new driver definition. -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='datasources' and starts-with(namespace-uri(), $nsDS)]
+ /*[local-name()='drivers' and starts-with(namespace-uri(), $nsDS)]">
+ <xsl:copy>
+ <xsl:copy-of select="$newDriverDefinition"/>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Copy everything else. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/module.xsl b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/module.xsl
new file mode 100644
index 0000000..88ac56b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/wildfly_kc14/src/main/xslt/module.xsl
@@ -0,0 +1,33 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:m="urn:jboss:module:1.3"
+ version="2.0"
+ exclude-result-prefixes="xalan m">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" />
+
+
+ <xsl:param name="database" select="''"/>
+ <xsl:param name="version" select="''"/>
+
+ <xsl:variable name="newModuleDefinition">
+ <module xmlns="urn:jboss:module:1.3" name="com.{$database}">
+ <resources>
+ <resource-root path="{$database}-{$version}.jar"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="javax.transaction.api"/>
+ </dependencies>
+ </module>
+ </xsl:variable>
+
+ <!-- clear whole document -->
+ <xsl:template match="/*" />
+
+ <!-- Copy new module definition. -->
+ <xsl:template match="/*">
+ <xsl:copy-of select="$newModuleDefinition"/>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/pom.xml b/testsuite/integration-arquillian/tests/adapters/as7/pom.xml
new file mode 100644
index 0000000..701a6ef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/pom.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-adapters</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-adapters-as7</artifactId>
+ <name>Adapter Tests on JBossAS 7</name>
+
+ <properties>
+ <as7.version>7.1.1.Final</as7.version>
+ <app.server.as7.home>${containers.home}/jboss-as-${as7.version}</app.server.as7.home>
+ <adapter.libs.as7>${containers.home}/keycloak-as7-adapter-dist</adapter.libs.as7>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-dist</artifactId>
+ <version>${as7.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-as7-adapter-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-arquillian-container-managed</artifactId>
+ <version>7.2.0.Final</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-as7-and-adapter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-dist</artifactId>
+ <version>${as7.version}</version>
+ <type>zip</type>
+ <outputDirectory>${containers.home}</outputDirectory>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-as7-adapter-dist</artifactId>
+ <type>zip</type>
+ <outputDirectory>${adapter.libs.as7}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <app.server.as7>true</app.server.as7>
+ <app.server.as7.home>${app.server.as7.home}</app.server.as7.home>
+ <adapter.libs.as7>${adapter.libs.as7}</adapter.libs.as7>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <profiles>
+ <profile>
+ <id>adapter-libs-provided</id>
+ <activation>
+ <property>
+ <name>!adapter.libs.bundled</name>
+ </property>
+ </activation>
+ <properties>
+ <adapter.libs.as7>${app.server.as7.home}</adapter.libs.as7>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-adapter-subsystem</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${app.server.as7.home}/standalone/configuration</dir>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+ <outputDir>${app.server.as7.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..8970850
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/arquillian.xsl
@@ -0,0 +1,36 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:a="http://jboss.org/schema/arquillian"
+ version="2.0"
+ exclude-result-prefixes="xalan a">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/a:arquillian">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+
+ <container qualifier="app-server-as7" mode="manual" >
+ <configuration>
+ <property name="enabled">${app.server.as7}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${app.server.as7.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${app.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+ <property name="managementAddress">localhost</property>
+ <property name="managementPort">${app.server.management.port.jmx}</property>
+ </configuration>
+ </container>
+
+ </xsl:copy>
+ </xsl:template>
+
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..5aac0f0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:1.2"
+ xmlns:ds="urn:jboss:domain:datasources:1.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.1"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:param name="config"/>
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="//j:extensions">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//j:profile">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//sec:security-domains">
+ <xsl:copy>
+ <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ <security-domain name="sp" cache-type="default">
+ <authentication>
+ <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7DemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7DemoServletsAdapterTest.java
new file mode 100644
index 0000000..f0258b2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7DemoServletsAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-as7")
+public class AS7DemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7SessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7SessionServletAdapterTest.java
new file mode 100644
index 0000000..9362ecd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/as7/src/test/java/org/keycloak/testsuite/adapter/servlet/AS7SessionServletAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-as7")
+public class AS7SessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/karaf/pom.xml b/testsuite/integration-arquillian/tests/adapters/karaf/pom.xml
new file mode 100644
index 0000000..06328fc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/karaf/pom.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-adapters</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-adapters-karaf</artifactId>
+ <name>Adapter Tests on Karaf</name>
+
+ <properties>
+ <karaf.version>3.0.3</karaf.version>
+ <karaf.home>${project.build.directory}/assembly</karaf.home>
+
+ <!--fuse examples expect auth server on 8080-->
+ <auth.server.port.offset>0</auth.server.port.offset>
+ <auth.server.http.port>8080</auth.server.http.port>
+ <auth.server.management.port>9990</auth.server.management.port>
+ <!--fuse examples expect default karaf http port 8181-->
+ <app.server.http.port>8181</app.server.http.port>
+
+ </properties>
+
+ <dependencies>
+ <!-- for karaf-maven-plugin -->
+ <dependency>
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>framework</artifactId>
+ <version>${karaf.version}</version>
+ <type>kar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.karaf</groupId>
+ <artifactId>apache-camel</artifactId>
+ <version>2.12.5</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf.karaf</groupId>
+ <artifactId>apache-cxf</artifactId>
+ <version>2.7.14</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-osgi-features</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>keycloak-fuse-example-features</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <!-- for arquillian -->
+ <dependency>
+ <groupId>org.jboss.arquillian.container</groupId>
+ <artifactId>arquillian-container-karaf-managed</artifactId>
+ <version>2.1.0.CR18</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.jmx</groupId>
+ <artifactId>org.apache.aries.jmx</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <version>${karaf.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>prepare-karaf-with-examples</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <!-- creates custom karaf distro in ${project.build.directory}/assembly -->
+ <goal>install-kars</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <bootFeatures>
+ <!-- this installs all fuse examples -->
+ <feature>keycloak-fuse-example</feature>
+ </bootFeatures>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <app.server.karaf>true</app.server.karaf>
+ <karaf.home>${karaf.home}</karaf.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/karaf/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/karaf/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..fabd47b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/karaf/src/main/xslt/arquillian.xsl
@@ -0,0 +1,38 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:a="http://jboss.org/schema/arquillian"
+ version="2.0"
+ exclude-result-prefixes="xalan a">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/a:arquillian">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+
+ <container qualifier="app-server-karaf" mode="manual" >
+ <configuration>
+ <property name="enabled">${app.server.karaf}</property>
+ <property name="adapterImplClass">org.jboss.arquillian.container.osgi.karaf.managed.KarafManagedDeployableContainer</property>
+ <property name="autostartBundle">false</property>
+ <property name="karafHome">${karaf.home}</property>
+ <property name="javaVmArguments">-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n ${adapter.test.props}</property>
+ <property name="jmxServiceURL">service:jmx:rmi://127.0.0.1:44444/jndi/rmi://127.0.0.1:1099/karaf-root</property>
+ <property name="jmxUsername">karaf</property>
+ <property name="jmxPassword">karaf</property>
+ </configuration>
+ </container>
+
+ </xsl:copy>
+ </xsl:template>
+
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/karaf/src/test/java/org/keycloak/testsuite/adapter/example/KarafFuseExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/karaf/src/test/java/org/keycloak/testsuite/adapter/example/KarafFuseExampleAdapterTest.java
new file mode 100644
index 0000000..eaf5f19
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/karaf/src/test/java/org/keycloak/testsuite/adapter/example/KarafFuseExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-karaf")
+public class KarafFuseExampleAdapterTest extends AbstractFuseExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/pom.xml b/testsuite/integration-arquillian/tests/adapters/pom.xml
new file mode 100644
index 0000000..bcdf397
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/pom.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-tests-adapters</artifactId>
+ <packaging>pom</packaging>
+ <name>Adapter Tests</name>
+
+ <properties>
+ <app.server.port.offset>200</app.server.port.offset>
+ <app.server.http.port>8280</app.server.http.port>
+ <app.server.management.port>10190</app.server.management.port>
+ <app.server.management.port.jmx>10199</app.server.management.port.jmx>
+ <adapter.test.props>-Dapp.server.base.url=http://localhost:${app.server.http.port} -Dmy.host.name=localhost</adapter.test.props>
+ <exclude.adapters>-</exclude.adapters>
+ </properties>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-common-arquillian-xml</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-base</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <includes>**/arquillian.xml</includes>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <id>add-app-server-to-arquillian-xml</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${project.build.directory}/dependency</dir>
+ <includes>
+ <include>arquillian.xml</include>
+ </includes>
+ <stylesheet>src/main/xslt/arquillian.xsl</stylesheet>
+ <outputDir>${project.build.directory}/dependency</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <arquillian.xml>${project.build.directory}/dependency/arquillian.xml</arquillian.xml>
+
+ <app.server.port.offset>${app.server.port.offset}</app.server.port.offset>
+ <app.server.http.port>${app.server.http.port}</app.server.http.port>
+ <app.server.management.port>${app.server.management.port}</app.server.management.port>
+ <app.server.management.port.jmx>${app.server.management.port.jmx}</app.server.management.port.jmx>
+
+ <adapter.test.props>${adapter.test.props}</adapter.test.props>
+
+ <adapter.libs.mode>bundled</adapter.libs.mode>
+ <adapter.config.mode>provided</adapter.config.mode>
+
+ </systemPropertyVariables>
+ <excludes>
+ <exclude>${exclude.adapters}</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <profiles>
+
+ <profile>
+ <id>common-for-adapter-tests</id>
+ <activation>
+ <file>
+ <exists>src</exists>
+ </file>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-base</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-base</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>adapter-libs-provided</id>
+ <activation>
+ <property>
+ <name>!adapter.libs.bundled</name>
+ </property>
+ </activation>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <adapter.libs.mode>provided</adapter.libs.mode>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>examples</id>
+ <activation>
+ <property>
+ <name>!skipTests</name>
+ </property>
+ </activation>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>example-wars</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>product-portal-example</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>customer-portal-example</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>database-service</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>js-console</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>examples-multitenant</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>examples-basicauth</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>cors-angular-product-example</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>cors-database-service</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${examples.home}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ <execution>
+ <id>example-realms</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-examples-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <includes>**/*realm.json</includes>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${examples.home}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <examples.home>${examples.home}</examples.home>
+ <examples.version.suffix>${project.version}</examples.version.suffix>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resources</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${examples.home}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/test/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>auth-server-wildfly</id>
+ <modules>
+ <module>wildfly-relative</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>app-server-wildfly</id>
+ <modules>
+ <module>wildfly</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>app-server-wildfly8</id>
+ <modules>
+ <module>wildfly8</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>app-server-as7</id>
+ <modules>
+ <module>as7</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>app-server-tomcat</id>
+ <modules>
+ <module>tomcat</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>app-server-karaf</id>
+ <modules>
+ <module>karaf</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>no-adapter-tests</id>
+ <properties>
+ <!-- Exclude all adapters tests. -->
+ <exclude.adapters>**/adapter/**/*Test.java</exclude.adapters>
+ </properties>
+ </profile>
+
+ </profiles>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/pom.xml b/testsuite/integration-arquillian/tests/adapters/tomcat/pom.xml
new file mode 100644
index 0000000..3d29d9f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/pom.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-adapters</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-adapters-tomcat</artifactId>
+ <name>Adapter Tests on Tomcat</name>
+
+ <properties>
+ <tomcat.version>8.0.23</tomcat.version>
+ <tomcat.home>${containers.home}/apache-tomcat-${tomcat.version}</tomcat.home>
+ <!-- FIXME disabled port-offset because tomcat doesn't support it -->
+ <app.server.port.offset>0</app.server.port.offset>
+ <app.server.http.port>8080</app.server.http.port>
+ <app.server.management.port>9990</app.server.management.port>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.arquillian.container</groupId>
+ <artifactId>arquillian-tomcat-managed-7</artifactId>
+ <version>1.0.0.CR7</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>unpack-tomcat-and-adapter</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>tomcat</artifactId>
+ <version>${tomcat.version}</version>
+ <type>zip</type>
+ <outputDirectory>${containers.home}</outputDirectory>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-tomcat8-adapter-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${tomcat.home}/lib</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ <execution>
+ <id>libs-for-tomcat</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-client</artifactId>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>jaxrs-api</artifactId>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ </artifactItem>
+ <artifactItem>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>1.4</version>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${tomcat.home}/lib</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-tomcat-manager-user</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${tomcat.home}/conf</dir>
+ <stylesheet>src/main/xslt/tomcat-users.xsl</stylesheet>
+ <includes>
+ <include>tomcat-users.xml</include>
+ </includes>
+ <outputDir>${tomcat.home}/conf</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <app.server.tomcat>true</app.server.tomcat>
+ <tomcat.home>${tomcat.home}</tomcat.home>
+ <!-- TODO: implement port-offset for tomcat server.xml so we can shift from 8080 -->
+ <app.server.management.port.tomcat>8089</app.server.management.port.tomcat>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..cd61687
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/arquillian.xsl
@@ -0,0 +1,39 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:a="http://jboss.org/schema/arquillian"
+ version="2.0"
+ exclude-result-prefixes="xalan a">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/a:arquillian">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+
+ <container qualifier="app-server-tomcat" mode="manual" >
+ <configuration>
+ <property name="enabled">${app.server.tomcat}</property>
+ <property name="adapterImplClass">org.jboss.arquillian.container.tomcat.managed_7.TomcatManagedContainer</property>
+ <property name="catalinaHome">${tomcat.home}</property>
+ <property name="catalinaBase">${tomcat.home}</property>
+ <property name="bindHttpPort">${app.server.http.port}</property>
+ <property name="jmxPort">${app.server.management.port.tomcat}</property>
+ <property name="user">manager</property>
+ <property name="pass">arquillian</property>
+ <property name="javaVmArguments">${adapter.test.props}</property>
+ </configuration>
+ </container>
+
+ </xsl:copy>
+ </xsl:template>
+
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/tomcat-users.xsl b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/tomcat-users.xsl
new file mode 100644
index 0000000..59b61b3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/main/xslt/tomcat-users.xsl
@@ -0,0 +1,23 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:tu="http://tomcat.apache.org/xml"
+ version="2.0"
+ exclude-result-prefixes="xalan tu">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no" />
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="//tu:tomcat-users">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <user username="manager" password="arquillian" roles="manager-script"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..95cfac0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatBasicAuthExampleAdapterTest.java
@@ -0,0 +1,15 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.junit.Ignore;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+@Ignore
+public class TomcatBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+ // TODO find out how to add context.xml dependent on app context (web.xml/module-name)
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatDemoExampleAdapterTest.java
new file mode 100644
index 0000000..99b219d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/example/TomcatDemoExampleAdapterTest.java
@@ -0,0 +1,16 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.junit.Ignore;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+@Ignore
+public class TomcatDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
+
+ // TODO find out how to add context.xml dependent on app context (web.xml/module-name)
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatDemoServletsAdapterTest.java
new file mode 100644
index 0000000..822a4db
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatDemoServletsAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+public class TomcatDemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatSessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatSessionServletAdapterTest.java
new file mode 100644
index 0000000..7dae041
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/tomcat/src/test/java/org/keycloak/testsuite/adapter/servlet/TomcatSessionServletAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat")
+public class TomcatSessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/pom.xml b/testsuite/integration-arquillian/tests/adapters/wildfly/pom.xml
new file mode 100644
index 0000000..776ae8a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/pom.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-adapters</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-adapters-wildfly</artifactId>
+ <name>Adapter Tests on Wildfly</name>
+
+ <properties>
+ <app.server.wildfly.home>${containers.home}/wildfly-${wildfly.version}</app.server.wildfly.home>
+ <adapter.libs.wildfly>${containers.home}/keycloak-wf9-adapter-dist</adapter.libs.wildfly>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-arquillian-container-managed</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf9-adapter-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-wildfly-and-adapter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-dist</artifactId>
+ <version>${wildfly.version}</version>
+ <type>zip</type>
+ <outputDirectory>${containers.home}</outputDirectory>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf9-adapter-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${adapter.libs.wildfly}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <app.server.wildfly>true</app.server.wildfly>
+ <app.server.wildfly.home>${app.server.wildfly.home}</app.server.wildfly.home>
+ <adapter.libs.wildfly>${adapter.libs.wildfly}</adapter.libs.wildfly>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>adapter-libs-provided</id>
+ <activation>
+ <property>
+ <name>!adapter.libs.bundled</name>
+ </property>
+ </activation>
+ <properties>
+ <adapter.libs.wildfly>${app.server.wildfly.home}</adapter.libs.wildfly>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-adapter-subsystem</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${app.server.wildfly.home}/standalone/configuration</dir>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+ <outputDir>${app.server.wildfly.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..32017cb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/arquillian.xsl
@@ -0,0 +1,35 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:a="http://jboss.org/schema/arquillian"
+ version="2.0"
+ exclude-result-prefixes="xalan a">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/a:arquillian">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+
+ <container qualifier="app-server-wildfly" mode="manual" >
+ <configuration>
+ <property name="enabled">${app.server.wildfly}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${app.server.wildfly.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${app.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+ <property name="managementPort">${app.server.management.port}</property>
+ </configuration>
+ </container>
+
+ </xsl:copy>
+ </xsl:template>
+
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..a483717
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:param name="config"/>
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="//j:extensions">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//j:profile">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//sec:security-domains">
+ <xsl:copy>
+ <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ <security-domain name="sp" cache-type="default">
+ <authentication>
+ <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..e16c864
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyDemoServletsAdapterTest.java
new file mode 100644
index 0000000..eaa24fc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyDemoServletsAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyDemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflySessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflySessionServletAdapterTest.java
new file mode 100644
index 0000000..0b2b489
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflySessionServletAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflySessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/pom.xml b/testsuite/integration-arquillian/tests/adapters/wildfly8/pom.xml
new file mode 100644
index 0000000..7c0a0dd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/pom.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-adapters</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-adapters-wildfly8</artifactId>
+ <name>Adapter Tests on Wildfly 8</name>
+
+ <properties>
+ <wildfly.version>8.2.1.Final</wildfly.version>
+
+ <app.server.wildfly.home>${containers.home}/wildfly-${wildfly.version}</app.server.wildfly.home>
+ <adapter.libs.wildfly>${containers.home}/keycloak-wf8-adapter-dist</adapter.libs.wildfly>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-arquillian-container-managed</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf8-adapter-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-wildfly-and-adapter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-dist</artifactId>
+ <version>${wildfly.version}</version>
+ <type>zip</type>
+ <outputDirectory>${containers.home}</outputDirectory>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf8-adapter-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${adapter.libs.wildfly}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <app.server.wildfly>true</app.server.wildfly>
+ <app.server.wildfly.home>${app.server.wildfly.home}</app.server.wildfly.home>
+ <adapter.libs.wildfly>${adapter.libs.wildfly}</adapter.libs.wildfly>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>adapter-libs-provided</id>
+ <activation>
+ <property>
+ <name>!adapter.libs.bundled</name>
+ </property>
+ </activation>
+ <properties>
+ <adapter.libs.wildfly>${app.server.wildfly.home}</adapter.libs.wildfly>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>configure-adapter-subsystem</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${app.server.wildfly.home}/standalone/configuration</dir>
+ <includes>
+ <include>standalone.xml</include>
+ </includes>
+ <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
+ <outputDir>${app.server.wildfly.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..32017cb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/arquillian.xsl
@@ -0,0 +1,35 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:a="http://jboss.org/schema/arquillian"
+ version="2.0"
+ exclude-result-prefixes="xalan a">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/a:arquillian">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+
+ <container qualifier="app-server-wildfly" mode="manual" >
+ <configuration>
+ <property name="enabled">${app.server.wildfly}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${app.server.wildfly.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${app.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+ <property name="managementPort">${app.server.management.port}</property>
+ </configuration>
+ </container>
+
+ </xsl:copy>
+ </xsl:template>
+
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..364d803
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:2.2"
+ xmlns:ds="urn:jboss:domain:datasources:2.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:param name="config"/>
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="//j:extensions">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//j:profile">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//sec:security-domains">
+ <xsl:copy>
+ <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ <security-domain name="sp" cache-type="default">
+ <authentication>
+ <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..e746dd0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8BasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8DemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8DemoServletsAdapterTest.java
new file mode 100644
index 0000000..469c6ca
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8DemoServletsAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8DemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8SessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8SessionServletAdapterTest.java
new file mode 100644
index 0000000..a342403
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly8/src/test/java/org/keycloak/testsuite/adapter/servlet/Wildfly8SessionServletAdapterTest.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8SessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/pom.xml b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/pom.xml
new file mode 100644
index 0000000..7d3ef2d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/pom.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests-adapters</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-adapters-wildfly-relative</artifactId>
+ <name>Adapter Tests on Wildfly Relative</name>
+
+ <properties>
+
+ <adapter.libs.wildfly>${containers.home}/keycloak-wf9-adapter-dist</adapter.libs.wildfly>
+
+ <!--this is needed for adapter tests that load system properties in adapter config-->
+ <app.server.http.port>${auth.server.http.port}</app.server.http.port>
+
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-arquillian-container-managed</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf9-adapter-dist</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>adapter-libs-bundled</id>
+ <activation>
+ <property>
+ <name>adapter.libs.bundled</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-adapter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wf9-adapter-dist</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ <outputDirectory>${adapter.libs.wildfly}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <adapter.libs.wildfly>${adapter.libs.wildfly}</adapter.libs.wildfly>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/arquillian.xsl
new file mode 100644
index 0000000..ce09796
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/arquillian.xsl
@@ -0,0 +1,16 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:a="http://jboss.org/schema/arquillian"
+ version="2.0"
+ exclude-result-prefixes="xalan a">
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/standalone.xsl b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/standalone.xsl
new file mode 100644
index 0000000..a483717
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/main/xslt/standalone.xsl
@@ -0,0 +1,51 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:j="urn:jboss:domain:3.0"
+ xmlns:ds="urn:jboss:domain:datasources:3.0"
+ xmlns:k="urn:jboss:domain:keycloak:1.1"
+ xmlns:sec="urn:jboss:domain:security:1.2"
+ version="2.0"
+ exclude-result-prefixes="xalan j ds k sec">
+
+ <xsl:param name="config"/>
+
+ <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="//j:extensions">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <extension module="org.keycloak.keycloak-adapter-subsystem"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//j:profile">
+ <xsl:copy>
+ <xsl:apply-templates select="node()|@*"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="//sec:security-domains">
+ <xsl:copy>
+ <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ <security-domain name="sp" cache-type="default">
+ <authentication>
+ <login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..5f45ebe
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeBasicAuthExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeCorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeCorsExampleAdapterTest.java
new file mode 100644
index 0000000..42ad346
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeCorsExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author fkiss
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeCorsExampleAdapterTest extends AbstractCorsExampleAdapterTest {
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeDemoExampleAdapterTest.java
new file mode 100644
index 0000000..afae885
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeDemoExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeJSConsoleExampleAdapterTest.java
new file mode 100644
index 0000000..c0026d0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/example/WildflyRelativeJSConsoleExampleAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeJSConsoleExampleAdapterTest extends AbstractJSConsoleExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeDemoServletsAdapterTest.java
new file mode 100644
index 0000000..b23cfc5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeDemoServletsAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeDemoServletsAdapterTest extends AbstractDemoServletsAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeSessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeSessionServletAdapterTest.java
new file mode 100644
index 0000000..17a3ae5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/java/org/keycloak/testsuite/adapter/servlet/WildflyRelativeSessionServletAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyRelativeSessionServletAdapterTest extends AbstractSessionServletAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/resources/web.xml b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/resources/web.xml
new file mode 100644
index 0000000..1b6dc5e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/adapters/wildfly-relative/src/test/resources/web.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>%CONTEXT_PATH%</module-name>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
new file mode 100644
index 0000000..4ee4118
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-tests</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-tests-base</artifactId>
+ <name>Base Test Suite</name>
+
+ <properties>
+ <exclude.console>-</exclude.console>
+ <exclude.account>-</exclude.account>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>${exclude.console}</exclude>
+ <exclude>${exclude.account}</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>no-console</id>
+ <properties>
+ <!-- Exclude all admin console tests. -->
+ <exclude.console>**/console/**/*Test.java</exclude.console>
+ </properties>
+ </profile>
+ <profile>
+ <id>no-account</id>
+ <properties>
+ <!-- Exclude all account management tests. -->
+ <exclude.account>**/account/**/*Test.java</exclude.account>
+ </properties>
+ </profile>
+ <profile>
+ <id>adapters-only</id>
+ <properties>
+ <exclude.console>**/console/**/*Test.java</exclude.console>
+ <exclude.account>**/account/**/*Test.java</exclude.account>
+ </properties>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/AdapterLibsMode.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/AdapterLibsMode.java
new file mode 100644
index 0000000..148a8d2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/AdapterLibsMode.java
@@ -0,0 +1,30 @@
+package org.keycloak.testsuite.adapter;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public enum AdapterLibsMode {
+
+ PROVIDED("provided"),
+ BUNDLED("bundled");
+
+ private final String type;
+
+ private AdapterLibsMode(String type) {
+ this.type = type;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public static AdapterLibsMode getByType(String type) {
+ for (AdapterLibsMode s : AdapterLibsMode.values()) {
+ if (s.getType().equals(type)) {
+ return s;
+ }
+ }
+ return null;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AngularCorsProductExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AngularCorsProductExample.java
new file mode 100644
index 0000000..3520a3e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AngularCorsProductExample.java
@@ -0,0 +1,77 @@
+package org.keycloak.testsuite.adapter.page;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.openqa.selenium.WebElement;
+
+import java.net.URL;
+
+/**
+ * Created by fkiss.
+ */
+public class AngularCorsProductExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "cors-angular-product-example";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @FindByJQuery("button:contains('Reload')")
+ private WebElement reloadDataButton;
+
+ @FindByJQuery("button:contains('load Roles')")
+ private WebElement loadRolesButton;
+
+ @FindByJQuery("button:contains('Add Role')")
+ private WebElement addRoleButton;
+
+ @FindByJQuery("button:contains('Delete Role')")
+ private WebElement deleteRoleButton;
+
+ @FindByJQuery("button:contains('load available social providers')")
+ private WebElement loadAvailableSocialProvidersButton;
+
+ @FindByJQuery("button:contains('Load public realm info')")
+ private WebElement loadPublicRealmInfoButton;
+
+ @FindByJQuery("button:contains('Load version')")
+ private WebElement loadVersionButton;
+
+ public void reloadData() {
+ reloadDataButton.click();
+ }
+
+ public void loadRoles() {
+ loadRolesButton.click();
+ }
+
+ public void addRole() {
+ addRoleButton.click();
+ }
+
+ public void deleteRole() {
+ deleteRoleButton.click();
+ }
+
+ public void loadAvailableSocialProviders() {
+ loadAvailableSocialProvidersButton.click();
+ }
+
+ public void loadPublicRealmInfo() {
+ loadPublicRealmInfoButton.click();
+ }
+
+ public void loadVersion() {
+ loadVersionButton.click();
+ }
+
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AppServerContextRoot.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AppServerContextRoot.java
new file mode 100644
index 0000000..0b68e05
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AppServerContextRoot.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.adapter.page;
+
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import java.net.URL;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContext;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AppServerContextRoot extends AbstractPageWithInjectedUrl {
+
+ @ArquillianResource
+ @AppServerContext
+ private URL appServerContextRoot;
+
+ @Override
+ public URL getInjectedUrl() {
+ return appServerContextRoot;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BasicAuthExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BasicAuthExample.java
new file mode 100644
index 0000000..f5cbcfb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BasicAuthExample.java
@@ -0,0 +1,41 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class BasicAuthExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "basic-auth-example";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder()
+ .userInfo("{user}:{password}")
+ .path("service/echo")
+ .queryParam("value", "{value}");
+ }
+
+ public BasicAuthExample setTemplateValues(String user, String password, String value) {
+ setUriParameter("user", user);
+ setUriParameter("password", password);
+ setUriParameter("value", value);
+ return this;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CorsDatabaseServiceExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CorsDatabaseServiceExample.java
new file mode 100644
index 0000000..4b72d6a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CorsDatabaseServiceExample.java
@@ -0,0 +1,26 @@
+package org.keycloak.testsuite.adapter.page;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+import java.net.URL;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CorsDatabaseServiceExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "cors-database-service";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDb.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDb.java
new file mode 100644
index 0000000..0e9c387
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDb.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerDb extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "customer-db";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDbErrorPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDbErrorPage.java
new file mode 100644
index 0000000..82d72e1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerDbErrorPage.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerDbErrorPage extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "customer-db-error-page";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortal.java
new file mode 100644
index 0000000..b3dcdf0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortal.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerPortal extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "customer-portal";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortalExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortalExample.java
new file mode 100644
index 0000000..beaa8fa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/CustomerPortalExample.java
@@ -0,0 +1,80 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerPortalExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "customer-portal-example";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @FindByJQuery("h1:contains('Customer Portal')")
+ private WebElement title;
+
+ @FindByJQuery("a:contains('Customer Listing')")
+ private WebElement customerListingLink;
+ @FindByJQuery("h1:contains('Customer Listing')")
+ private WebElement customerListingHeader;
+
+ @FindByJQuery("h1:contains('Customer Session')")
+ private WebElement customerSessionHeader;
+
+ @FindByJQuery("a:contains('Customer Admin Interface')")
+ private WebElement customerAdminInterfaceLink;
+
+ @FindByJQuery("a:contains('Customer Session')")
+ private WebElement customerSessionLink;
+
+ @FindByJQuery("a:contains('products')")
+ private WebElement productsLink;
+
+ @FindByJQuery("a:contains('logout')")
+ private WebElement logOutButton;
+
+ public void goToProducts() {
+ productsLink.click();
+ }
+
+ public void customerListing() {
+ customerListingLink.click();
+ }
+
+ public void customerAdminInterface() {
+ customerAdminInterfaceLink.click();
+ }
+
+ public void customerSession() {
+ WaitUtils.waitGuiForElement(customerSessionLink);
+ customerSessionLink.click();
+ }
+
+ public void logOut() {
+ logOutButton.click();
+ }
+
+ public void waitForCustomerListingHeader() {
+ WaitUtils.waitGuiForElementNotPresent(customerListingHeader);
+ }
+
+ public void waitForCustomerSessionHeader() {
+ WaitUtils.waitGuiForElementNotPresent(customerSessionHeader);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/DatabaseServiceExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/DatabaseServiceExample.java
new file mode 100644
index 0000000..1bbc4c7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/DatabaseServiceExample.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class DatabaseServiceExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "database-service-example";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AbstractFuseExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AbstractFuseExample.java
new file mode 100644
index 0000000..18e821a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AbstractFuseExample.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.keycloak.testsuite.adapter.page.AppServerContextRoot;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractFuseExample extends AppServerContextRoot {
+
+ public abstract String getContext();
+
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ if (url == null) {
+ try {
+ url = new URL(super.getInjectedUrl().toExternalForm() + "/" + getContext());
+ } catch (MalformedURLException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AdminInterface.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AdminInterface.java
new file mode 100644
index 0000000..2921a5b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/AdminInterface.java
@@ -0,0 +1,17 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminInterface extends CustomerPortalFuseExample {
+
+ @Override
+ public String getContext() {
+ return super.getContext() + "/customers/camel.jsp";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerListing.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerListing.java
new file mode 100644
index 0000000..01f3f3d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerListing.java
@@ -0,0 +1,36 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerListing extends CustomerPortalFuseExample {
+
+ @Override
+ public String getContext() {
+ return super.getContext() + "/customers/cxf-rs.jsp";
+ }
+
+ @FindBy(linkText = "products")
+ protected WebElement productsLink;
+ @FindBy(linkText = "logout")
+ protected WebElement logOutLink;
+ @FindBy(linkText = "manage acct")
+ protected WebElement accountManagementLink;
+
+ public void clickProducts() {
+ productsLink.click();
+ }
+
+ public void clickLogOut() {
+ logOutLink.click();
+ }
+
+ public void clickAccountManagement() {
+ accountManagementLink.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerPortalFuseExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerPortalFuseExample.java
new file mode 100644
index 0000000..6d1f656
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/CustomerPortalFuseExample.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CustomerPortalFuseExample extends AbstractFuseExample {
+
+ public static final String DEPLOYMENT_NAME = "customer-portal-fuse-example";
+ public static final String DEPLOYMENT_CONTEXT = "customer-portal";
+
+ @Override
+ public String getContext() {
+ return DEPLOYMENT_CONTEXT;
+ }
+
+ @FindBy(linkText = "Customer Listing - CXF RS endpoint")
+ protected WebElement customerListingLink;
+
+ @FindBy(linkText = "Admin Interface - Apache Camel endpoint")
+ protected WebElement adminInterfaceLink;
+
+ public void clickCustomerListingLink() {
+ customerListingLink.click();
+ }
+
+ public void clickAdminInterfaceLink() {
+ adminInterfaceLink.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/ProductPortalFuseExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/ProductPortalFuseExample.java
new file mode 100644
index 0000000..b61222e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/fuse/ProductPortalFuseExample.java
@@ -0,0 +1,50 @@
+package org.keycloak.testsuite.adapter.page.fuse;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ProductPortalFuseExample extends AbstractFuseExample {
+
+ public static final String DEPLOYMENT_NAME = "product-portal-fuse-example";
+ public static final String DEPLOYMENT_CONTEXT = "product-portal";
+
+ @Override
+ public String getContext() {
+ return DEPLOYMENT_CONTEXT;
+ }
+
+ @FindBy(linkText = "products")
+ protected WebElement productsLink;
+ @FindBy(linkText = "logout")
+ protected WebElement logOutLink;
+ @FindBy(linkText = "manage acct")
+ protected WebElement accountManagementLink;
+
+ @FindBy(xpath = "//p[contains(text(),'Product with ID 1 - unsecured request')]")
+ protected WebElement product1Unsecured;
+ @FindBy(xpath = "//p[contains(text(),'Product with ID 1 - secured request')]")
+ protected WebElement product1Secured;
+ @FindBy(xpath = "//p[contains(text(),'Product with ID 2 - secured request')]")
+ protected WebElement product2Secured;
+
+ public String getProduct1UnsecuredText() {
+ return product1Unsecured.getText();
+ }
+
+ public String getProduct1SecuredText() {
+ return product1Secured.getText();
+ }
+
+ public String getProduct2SecuredText() {
+ return product2Secured.getText();
+ }
+
+ public void clickLogOutLink() {
+ logOutLink.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java
new file mode 100644
index 0000000..564272f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/InputPortal.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class InputPortal extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "input-portal";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @FindBy(id = "parameter")
+ private WebElement parameter;
+
+ @FindBy(name = "submit")
+ private WebElement submit;
+
+ public void execute(String param) {
+ parameter.clear();
+ parameter.sendKeys(param);
+ submit.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleExample.java
new file mode 100644
index 0000000..787be4d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleExample.java
@@ -0,0 +1,70 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class JSConsoleExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "js-console-example";
+ public static final String CLIENT_ID = "js-console";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @FindBy(xpath = "//button[text() = 'Login']")
+ private WebElement logInButton;
+ @FindBy(xpath = "//button[text() = 'Logout']")
+ private WebElement logOutButton;
+ @FindBy(xpath = "//button[text() = 'Refresh Token']")
+ private WebElement refreshTokenButton;
+ @FindBy(xpath = "//button[contains(text(),'Refresh Token (if <30s')]")
+ private WebElement refreshTokenIfUnder30sButton;
+ @FindBy(xpath = "//button[text() = 'Get Profile']")
+ private WebElement getProfileButton;
+
+ @FindBy(xpath = "//button[text() = 'Show Token']")
+ private WebElement showTokenButton;
+ @FindBy(xpath = "//button[text() = 'Show Refresh Token']")
+ private WebElement showRefreshTokenButton;
+ @FindBy(xpath = "//button[text() = 'Show ID Token']")
+ private WebElement showIdTokenButton;
+ @FindBy(xpath = "//button[text() = 'Show Expires']")
+ private WebElement showExpiresButton;
+ @FindBy(xpath = "//button[text() = 'Show Details']")
+ private WebElement showDetailsButton;
+
+ public void logIn() {
+ logInButton.click();
+ }
+
+ public void logOut() {
+ logOutButton.click();
+ }
+
+ public void refreshToken() {
+ refreshTokenButton.click();
+ }
+
+ public void refreshTokenIfUnder30s() {
+ refreshTokenIfUnder30sButton.click();
+ }
+
+ public void getProfile() {
+ getProfileButton.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant.java
new file mode 100644
index 0000000..3cb7fb6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenant.java
@@ -0,0 +1,46 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class MultiTenant extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "multi-tenant";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder().path("/").queryParam("realm", "{tenantRealm}");
+ }
+
+ public URL getTenantRealmUrl(String realm) {
+ try {
+ return getUriBuilder().build(realm).toURL();
+ } catch (MalformedURLException ex) {
+ throw new IllegalStateException("Page URL is malformed.");
+ }
+ }
+
+ public void navigateToRealm(String realm) {
+ URL u = getTenantRealmUrl(realm);
+ log.info("navigate to "+u.toExternalForm());
+ driver.navigate().to(u.toExternalForm());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenantExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenantExample.java
new file mode 100644
index 0000000..a8e582d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/MultiTenantExample.java
@@ -0,0 +1,46 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class MultiTenantExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "multi-tenant-example";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder().path("{tenantRealm}");
+ }
+
+ public URL getTenantRealmUrl(String realm) {
+ try {
+ return getUriBuilder().build(realm).toURL();
+ } catch (MalformedURLException ex) {
+ throw new IllegalStateException("Page URL is malformed.");
+ }
+ }
+
+ public void navigateToRealm(String realm) {
+ URL u = getTenantRealmUrl(realm);
+ log.info("navigate to "+u.toExternalForm());
+ driver.navigate().to(u.toExternalForm());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortal.java
new file mode 100644
index 0000000..96cd1b1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortal.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ProductPortal extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "product-portal";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortalExample.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortalExample.java
new file mode 100644
index 0000000..fd80e5d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/ProductPortalExample.java
@@ -0,0 +1,59 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ProductPortalExample extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "product-portal-example";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+ @FindByJQuery("h1:contains('Product Portal')")
+ private WebElement title;
+
+ @FindByJQuery("a:contains('Product Listing')")
+ private WebElement productListingLink;
+ @FindByJQuery("h1:contains('Product Listing')")
+ private WebElement productListingHeader;
+
+ @FindByJQuery("a:contains('customers')")
+ private WebElement customersLink;
+
+ @FindByJQuery("a:contains('logout')")
+ private WebElement logOutButton;
+
+ public void productListing() {
+ productListingLink.click();
+ }
+
+ public void goToCustomers() {
+ customersLink.click();
+ }
+
+ public void waitForProductListingHeader() {
+ WaitUtils.waitGuiForElementNotPresent(productListingHeader);
+ }
+
+ public void logOut() {
+ logOutButton.click();
+ }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SecurePortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SecurePortal.java
new file mode 100644
index 0000000..4825fef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SecurePortal.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class SecurePortal extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "secure-portal";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SessionPortal.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SessionPortal.java
new file mode 100644
index 0000000..0e597c6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SessionPortal.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class SessionPortal extends AbstractPageWithInjectedUrl {
+
+ public static final String DEPLOYMENT_NAME = "session-portal";
+
+ @ArquillianResource
+ @OperateOnDeployment(DEPLOYMENT_NAME)
+ private URL url;
+
+ @Override
+ public URL getInjectedUrl() {
+ return url;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CallAuthenticatedServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CallAuthenticatedServlet.java
new file mode 100644
index 0000000..b5f7f7c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CallAuthenticatedServlet.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.KeycloakSecurityContext;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CallAuthenticatedServlet extends HttpServlet {
+
+ private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ if (!req.authenticate(resp)) {
+ return;
+ }
+
+ KeycloakSecurityContext sc = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+ if (sc == null) { // assert sc not null
+ throw new AssertionError("Keycloak security context is null.");
+ }
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>%s</title></head><body>", "Customer Portal");
+ pw.println("Stian Thorgersen");
+ pw.println("Bill Burke");
+ pw.print("</body></html>");
+ pw.flush();
+
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerDatabaseServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerDatabaseServlet.java
new file mode 100644
index 0000000..0e581cd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerDatabaseServlet.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CustomerDatabaseServlet extends HttpServlet {
+ private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>%s</title></head><body>", "Customer Portal");
+ pw.println("Stian Thorgersen");
+ pw.println("Bill Burke");
+ pw.print("</body></html>");
+ pw.flush();
+
+
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerServlet.java
new file mode 100644
index 0000000..9d03c1f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/CustomerServlet.java
@@ -0,0 +1,59 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.KeycloakSecurityContext;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.annotation.WebServlet;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@WebServlet("/customer-portal")
+public class CustomerServlet extends HttpServlet {
+ private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ PrintWriter pw = resp.getWriter();
+ if (req.getRequestURI().endsWith("logout")) {
+ resp.setStatus(200);
+ pw.println("servlet logout ok");
+
+ // Call logout before pw.flush
+ req.logout();
+ pw.flush();
+ return;
+ }
+ KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
+ Client client = ClientBuilder.newClient();
+
+ try {
+ String appBase = System.getProperty("app.server.base.url", "http://localhost:8280");
+ WebTarget target = client.target(appBase + "/customer-db/");
+ Response response = target.request().get();
+ if (response.getStatus() != 401) { // assert response status == 401
+ throw new AssertionError("Response status code is not 401.");
+ }
+ response.close();
+ String html = target.request()
+ .header(HttpHeaders.AUTHORIZATION, "Bearer " + context.getTokenString())
+ .get(String.class);
+ resp.setContentType("text/html");
+ pw.println(html);
+ pw.flush();
+ } finally {
+ client.close();
+ }
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ErrorServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ErrorServlet.java
new file mode 100644
index 0000000..55cac40
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ErrorServlet.java
@@ -0,0 +1,27 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ErrorServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>%s</title></head><body>", "Error Page");
+ pw.print("<h1>There was an error</h1></body></html>");
+ pw.flush();
+
+
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java
new file mode 100644
index 0000000..0834d95
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/InputServlet.java
@@ -0,0 +1,43 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.annotation.WebServlet;
+
+/**
+ * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
+ */
+@WebServlet("/input-portal")
+public class InputServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String appBase = System.getProperty("app.server.base.url", "http://localhost:8280");
+ String actionUrl = appBase + "/input-portal/secured/post";
+
+
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>%s</title></head><body>", "Input Page");
+ pw.printf("<form action=\"%s\" method=\"POST\">", actionUrl);
+ pw.println("<input id=\"parameter\" type=\"text\" name=\"parameter\">");
+ pw.println("<input name=\"submit\" type=\"submit\" value=\"Submit\"></form>");
+ pw.print("</body></html>");
+ pw.flush();
+
+
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setContentType("text/plain");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("parameter="+req.getParameter("parameter"));
+ pw.flush();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantResolver.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantResolver.java
new file mode 100644
index 0000000..765e291
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantResolver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.adapter.servlet;
+
+import java.io.InputStream;
+import org.keycloak.adapters.HttpFacade;
+import org.keycloak.adapters.KeycloakConfigResolver;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.KeycloakDeploymentBuilder;
+
+/**
+ *
+ * @author Juraci Paixão Kröhling <juraci at kroehling.de>
+ */
+public class MultiTenantResolver implements KeycloakConfigResolver {
+
+ @Override
+ public KeycloakDeployment resolve(HttpFacade.Request request) {
+ String realm = request.getQueryParamValue("realm");
+
+ // FIXME doesn't work - need to load resources from WEB-INF
+ InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak.json");
+
+ if (is == null) {
+ throw new IllegalStateException("Not able to find the file /" + realm + "-keycloak.json");
+ }
+
+ KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(is);
+ return deployment;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantServlet.java
new file mode 100644
index 0000000..ccbf97a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/MultiTenantServlet.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.adapter.servlet;
+
+import org.keycloak.KeycloakSecurityContext;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ *
+ * @author Juraci Paixão Kröhling <juraci at kroehling.de>
+ */
+public class MultiTenantServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
+
+ pw.print("Username: ");
+ pw.println(context.getIdToken().getPreferredUsername());
+
+ pw.print("<br/>Realm: ");
+ pw.println(context.getRealm());
+
+ pw.flush();
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ProductServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ProductServlet.java
new file mode 100644
index 0000000..ce89986
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/ProductServlet.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProductServlet extends HttpServlet {
+ private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>%s</title></head><body>", "Product Portal");
+ pw.println("iPhone");
+ pw.println("iPad");
+ pw.print("</body></html>");
+ pw.flush();
+
+
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SessionServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SessionServlet.java
new file mode 100644
index 0000000..584408e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SessionServlet.java
@@ -0,0 +1,40 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@WebServlet("/SessionServlet")
+public class SessionServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String counter = increaseAndGetCounter(req);
+
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>%s</title></head><body>", "Session Test");
+ pw.printf("Counter=%s", counter);
+ pw.print("</body></html>");
+ pw.flush();
+
+
+ }
+
+ private String increaseAndGetCounter(HttpServletRequest req) {
+ HttpSession session = req.getSession();
+ Integer counter = (Integer)session.getAttribute("counter");
+ counter = (counter == null) ? 1 : counter + 1;
+ session.setAttribute("counter", counter);
+ return String.valueOf(counter);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
new file mode 100644
index 0000000..eb202e5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
@@ -0,0 +1,111 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.admin;
+
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.RoleScopeResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ * Created by st on 28.05.15.
+ */
+public class ApiUtil {
+
+ public static String getCreatedId(Response response) {
+ URI location = response.getLocation();
+ if (location == null) {
+ return null;
+ }
+ String path = location.getPath();
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+
+ public static ClientResource findClientResourceByClientId(RealmResource realm, String clientId) {
+ for (ClientRepresentation c : realm.clients().findAll()) {
+ if (c.getClientId().equals(clientId)) {
+ return realm.clients().get(c.getId());
+ }
+ }
+ return null;
+ }
+
+ public static ClientRepresentation findClientByClientId(RealmResource realm, String clientId) {
+ ClientRepresentation client = null;
+ for (ClientRepresentation c : realm.clients().findAll()) {
+ if (clientId.equals(c.getClientId())) {
+ client = c;
+ }
+ }
+ return client;
+ }
+
+ public static UserRepresentation findUserByUsername(RealmResource realm, String username) {
+ UserRepresentation user = null;
+ List<UserRepresentation> ur = realm.users().search(username, null, null);
+ if (ur.size() == 1) {
+ user = ur.get(0);
+ }
+ return user;
+ }
+
+ public static String createUserWithAdminClient(RealmResource realm, UserRepresentation user) {
+ Response response = realm.users().create(user);
+ String createdId = getCreatedId(response);
+ response.close();
+ return createdId;
+ }
+
+ public static String createUserAndResetPasswordWithAdminClient(RealmResource realm, UserRepresentation user, String password) {
+ String id = createUserWithAdminClient(realm, user);
+ resetUserPassword(realm.users().get(id), password, false);
+ return id;
+ }
+
+ public static void resetUserPassword(UserResource userResource, String newPassword, boolean temporary) {
+ CredentialRepresentation newCredential = new CredentialRepresentation();
+ newCredential.setType(PASSWORD);
+ newCredential.setValue(newPassword);
+ newCredential.setTemporary(temporary);
+ userResource.resetPassword(newCredential);
+ }
+
+ public static void assignClientRoles(UserResource userResource, String clientId, String... roles) {
+ RoleScopeResource rsr = userResource.roles().clientLevel(clientId);
+ List<String> rolesList = Arrays.asList(roles);
+ List<RoleRepresentation> realmMgmtRoles = new ArrayList<>();
+ for (RoleRepresentation rr : rsr.listAvailable()) {
+ if (rolesList.contains(rr.getName())) {
+ realmMgmtRoles.add(rr);
+ }
+ }
+ rsr.add(realmMgmtRoles);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/Users.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/Users.java
new file mode 100644
index 0000000..c2a2f7a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/Users.java
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.admin;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class Users {
+
+ public static String getPasswordOf(UserRepresentation user) {
+ String value = null;
+ CredentialRepresentation password = getPasswordCredentialOf(user);
+ if (password != null) {
+ value = password.getValue();
+ }
+ return value;
+ }
+
+ public static CredentialRepresentation getPasswordCredentialOf(UserRepresentation user) {
+ CredentialRepresentation password = null;
+ if (user.getCredentials() != null) {
+ for (CredentialRepresentation c : user.getCredentials()) {
+ if (CredentialRepresentation.PASSWORD.equals(c.getType())) {
+ password = c;
+ }
+ }
+ }
+ return password;
+ }
+
+ public static void setPasswordFor(UserRepresentation user, String password) {
+ setPasswordFor(user, password, false);
+ }
+ public static void setPasswordFor(UserRepresentation user, String password, boolean temporary) {
+ List<CredentialRepresentation> credentials = new ArrayList<>();
+ CredentialRepresentation pass = new CredentialRepresentation();
+ pass.setType(PASSWORD);
+ pass.setValue(password);
+ pass.setTemporary(temporary);
+ credentials.add(pass);
+ user.setCredentials(credentials);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AdapterLibsLocationProperty.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AdapterLibsLocationProperty.java
new file mode 100644
index 0000000..ec0fe1d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AdapterLibsLocationProperty.java
@@ -0,0 +1,19 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.TYPE})
+public @interface AdapterLibsLocationProperty
+{
+ String value();
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java
new file mode 100644
index 0000000..b8169f8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java
@@ -0,0 +1,20 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.TYPE})
+public @interface AppServerContainer
+{
+ String value() default "";
+ String adapterLibsLocationProperty() default "";
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContext.java
new file mode 100644
index 0000000..203ac65
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContext.java
@@ -0,0 +1,18 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.FIELD})
+public @interface AppServerContext
+{
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AuthServerContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AuthServerContext.java
new file mode 100644
index 0000000..a35bbde
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AuthServerContext.java
@@ -0,0 +1,18 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.FIELD})
+public @interface AuthServerContext
+{
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java
new file mode 100644
index 0000000..c4476ef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.arquillian.containers;
+
+import java.util.logging.Logger;
+
+import org.jboss.arquillian.container.impl.client.ContainerDeploymentContextHandler;
+import org.jboss.arquillian.container.impl.client.container.ContainerDeployController;
+import org.jboss.arquillian.container.impl.client.container.ContainerLifecycleController;
+import org.jboss.arquillian.container.impl.client.container.DeploymentExceptionHandler;
+import org.jboss.arquillian.container.impl.client.deployment.ArchiveDeploymentExporter;
+import org.jboss.arquillian.container.impl.context.ContainerContextImpl;
+import org.jboss.arquillian.container.impl.context.DeploymentContextImpl;
+import org.jboss.arquillian.core.spi.LoadableExtension;
+
+/**
+ * Enables multiple container adapters on classpath.
+ *
+ * @author Dominik Pospisil <dpospisi@redhat.com>
+ * @author Stefan Miklosovic <smikloso@redhat.com>
+ * @author Tomas Kyjovsky <tkyjovsk@redhat.com>
+ */
+public class MultipleContainersExtension implements LoadableExtension {
+
+ private static final Logger logger = Logger.getLogger(MultipleContainersExtension.class.getName());
+
+ @Override
+ public void register(ExtensionBuilder builder) {
+
+ logger.info("Multiple containers extension registering.");
+
+ builder.context(ContainerContextImpl.class).context(DeploymentContextImpl.class);
+
+ builder.observer(RegistryCreator.class)
+ .observer(ContainerDeploymentContextHandler.class)
+ .observer(ContainerLifecycleController.class)
+ .observer(ContainerDeployController.class)
+ .observer(ArchiveDeploymentExporter.class)
+ .observer(DeploymentExceptionHandler.class);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/Registry.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/Registry.java
new file mode 100644
index 0000000..2564b7a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/Registry.java
@@ -0,0 +1,148 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.arquillian.containers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.jboss.arquillian.config.descriptor.api.ContainerDef;
+import org.jboss.arquillian.container.impl.ContainerCreationException;
+import org.jboss.arquillian.container.impl.ContainerImpl;
+import org.jboss.arquillian.container.spi.ConfigurationException;
+import org.jboss.arquillian.container.spi.Container;
+import org.jboss.arquillian.container.spi.ContainerRegistry;
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.spi.client.deployment.TargetDescription;
+import org.jboss.arquillian.core.api.Injector;
+import org.jboss.arquillian.core.spi.ServiceLoader;
+import org.jboss.arquillian.core.spi.Validate;
+import static org.keycloak.testsuite.arquillian.containers.RegistryCreator.getAdapterImplClassValue;
+import static org.keycloak.testsuite.arquillian.containers.RegistryCreator.getContainerAdapter;
+
+/**
+ * This class registers all adapters which are specified in the arquillian.xml.
+ *
+ * In the case there is only one adapter implementation on the classpath, it is
+ * not necessary to specify it in the container configuration since it will be
+ * used automatically. You have to specify it only in the case you are going to
+ * use more than one container.
+ *
+ * @author Dominik Pospisil <dpospisi@redhat.com>
+ * @author Stefan Miklosovic <smikloso@redhat.com>
+ * @author Tomas Kyjovsky <tkyjovsk@redhat.com>
+ */
+public class Registry implements ContainerRegistry {
+
+ private final List<Container> containers;
+
+ private Injector injector;
+
+ private static final Logger logger = Logger.getLogger(RegistryCreator.class.getName());
+
+ public Registry(Injector injector) {
+ this.containers = new ArrayList<>();
+ this.injector = injector;
+ }
+
+ @Override
+ public Container create(ContainerDef definition, ServiceLoader loader) {
+ Validate.notNull(definition, "Definition must be specified");
+
+ try {
+ logger.log(Level.INFO, "Registering container: {0}", definition.getContainerName());
+
+ @SuppressWarnings("rawtypes")
+ Collection<DeployableContainer> containerAdapters = loader.all(DeployableContainer.class);
+
+ DeployableContainer<?> dcService = null;
+
+ if (containerAdapters.size() == 1) {
+ // just one container on cp
+ dcService = containerAdapters.iterator().next();
+ } else {
+ if (dcService == null) {
+ dcService = getContainerAdapter(getAdapterImplClassValue(definition), containerAdapters);
+ }
+ if (dcService == null) {
+ throw new ConfigurationException("Unable to get container adapter from Arquillian configuration.");
+ }
+ }
+
+ // before a Container is added to a collection of containers, inject into its injection point
+ return addContainer(injector.inject(
+ new ContainerImpl(definition.getContainerName(), dcService, definition)));
+
+ } catch (Exception e) {
+ throw new ContainerCreationException("Could not create Container " + definition.getContainerName(), e);
+ }
+ }
+
+ @Override
+ public List<Container> getContainers() {
+ return Collections.unmodifiableList(new ArrayList<>(containers));
+ }
+
+ @Override
+ public Container getContainer(TargetDescription target) {
+ Validate.notNull(target, "Target must be specified");
+ if (TargetDescription.DEFAULT.equals(target)) {
+ return findDefaultContainer();
+ }
+ return findMatchingContainer(target.getName());
+ }
+
+ private Container addContainer(Container container) {
+ containers.add(container);
+ return container;
+ }
+
+ private Container findDefaultContainer() {
+ if (containers.size() == 1) {
+ return containers.get(0);
+ }
+ for (Container container : containers) {
+ if (container.getContainerConfiguration().isDefault()) {
+ return container;
+ }
+ }
+ return null;
+ }
+
+ private Container findMatchingContainer(String name) {
+ for (Container container : containers) {
+ if (container.getName().equals(name)) {
+ return container;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Container getContainer(String name) {
+ return findMatchingContainer(name);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/RegistryCreator.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/RegistryCreator.java
new file mode 100644
index 0000000..ffcccd5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/RegistryCreator.java
@@ -0,0 +1,186 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.arquillian.containers;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
+import org.jboss.arquillian.config.descriptor.api.ContainerDef;
+import org.jboss.arquillian.config.descriptor.api.GroupDef;
+import org.jboss.arquillian.container.spi.ContainerRegistry;
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.core.api.Injector;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.InstanceProducer;
+import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.core.api.annotation.Observes;
+import org.jboss.arquillian.core.spi.ServiceLoader;
+import org.jboss.arquillian.core.spi.Validate;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.arquillian.containers.SecurityActions.isClassPresent;
+import static org.keycloak.testsuite.arquillian.containers.SecurityActions.loadClass;
+
+/**
+ * Registers all container adapters.
+ *
+ * @author Dominik Pospisil <dpospisi@redhat.com>
+ * @author Stefan Miklosovic <smikloso@redhat.com>
+ * @author Tomas Kyjovsky <tkyjovsk@redhat.com>
+ * @author Vlasta Ramik <vramik@redhat.com>
+ */
+public class RegistryCreator {
+
+ protected final Logger log = Logger.getLogger(this.getClass());
+
+ @Inject
+ @ApplicationScoped
+ private InstanceProducer<ContainerRegistry> registry;
+
+ @Inject
+ private Instance<Injector> injector;
+
+ @Inject
+ private Instance<ServiceLoader> loader;
+
+ private String authContainer;
+ private String migrationContainer;
+
+ public void createRegistry(@Observes ArquillianDescriptor event) {
+ ContainerRegistry reg = new Registry(injector.get());
+ ServiceLoader serviceLoader = loader.get();
+
+ @SuppressWarnings("rawtypes")
+ Collection<DeployableContainer> containers = serviceLoader.all(DeployableContainer.class);
+
+ if (containers.isEmpty()) {
+ throw new IllegalStateException("There are not any container adapters on the classpath");
+ }
+
+ for (ContainerDef container : event.getContainers()) {
+ if (isCreatingContainer(container, containers)) {
+ if (isEnabled(container)) {
+ checkMultipleEnabledContainers(container);
+ reg.create(container, serviceLoader);
+ } else {
+ log.info("Container is disabled: " + container.getContainerName());
+ }
+ }
+ }
+
+ for (GroupDef group : event.getGroups()) {
+ for (ContainerDef container : group.getGroupContainers()) {
+ if (isCreatingContainer(container, containers)) {
+ if (isEnabled(container)) {
+ //TODO add checkMultipleEnabledContainers according to groups
+ reg.create(container, serviceLoader);
+ } else {
+ log.info("Container is disabled: " + container.getContainerName());
+ }
+ }
+ }
+ }
+
+ registry.set(reg);
+ }
+
+ private static final String ENABLED = "enabled";
+
+ private boolean isEnabled(ContainerDef containerDef) {
+ Map<String, String> props = containerDef.getContainerProperties();
+ return !props.containsKey(ENABLED)
+ || (props.containsKey(ENABLED) && props.get(ENABLED).equals("true"));
+ }
+
+ private void checkMultipleEnabledContainers(ContainerDef containerDef) {
+ String containerName = containerDef.getContainerName();
+
+ if (containerName.startsWith("keycloak")) {
+ if (migrationContainer == null) {
+ migrationContainer = containerName;
+ } else {
+ throw new RuntimeException("There is more than one migration container "
+ + "enabled in arquillian.xml. It has to be enabled at most one. "
+ + "Do not activate more than one migration profile.");
+ }
+ } else if (containerName.startsWith("auth-server")) {
+ if (authContainer == null) {
+ authContainer = containerName;
+ } else {
+ throw new RuntimeException("There is more than one auth containec enabled "
+ + "in arquillian.xml. It has to be enabled exactly one. Do not "
+ + "activate more than one auth profile.");
+ }
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private boolean isCreatingContainer(ContainerDef containerDef, Collection<DeployableContainer> containers) {
+
+ if (hasAdapterImplClassProperty(containerDef)) {
+ if (isClassPresent(getAdapterImplClassValue(containerDef))) {
+ return DeployableContainer.class.isAssignableFrom(
+ loadClass(getAdapterImplClassValue(containerDef)));
+ }
+ }
+
+ return false;
+ }
+
+ public static boolean hasAdapterImplClassProperty(ContainerDef containerDef) {
+ for (Map.Entry<String, String> entry : containerDef.getContainerProperties().entrySet()) {
+ if (entry.getKey().equals(ADAPTER_IMPL_CONFIG_STRING)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static String getAdapterImplClassValue(ContainerDef containerDef) {
+ return containerDef.getContainerProperties().get(ADAPTER_IMPL_CONFIG_STRING).trim();
+ }
+ public static final String ADAPTER_IMPL_CONFIG_STRING = "adapterImplClass";
+
+ @SuppressWarnings("rawtypes")
+ public static DeployableContainer<?> getContainerAdapter(String adapterImplClass, Collection<DeployableContainer> containers) {
+ Validate.notNullOrEmpty(adapterImplClass, "The value of " + ADAPTER_IMPL_CONFIG_STRING + " can not be a null object "
+ + "nor an empty string!");
+
+ Class<?> foundAdapter = null;
+
+ if (isClassPresent(adapterImplClass)) {
+ foundAdapter = loadClass(adapterImplClass);
+ } else {
+ return null;
+ }
+
+ for (DeployableContainer<?> container : containers) {
+ if (foundAdapter.isInstance(container)) {
+ return container;
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/SecurityActions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/SecurityActions.java
new file mode 100644
index 0000000..941c10a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/SecurityActions.java
@@ -0,0 +1,307 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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.arquillian.containers;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A set of privileged actions that are not to leak out of this package
+ *
+ * @version $Revision: $
+ */
+final class SecurityActions {
+
+ // -------------------------------------------------------------------------------||
+ // Constructor -------------------------------------------------------------------||
+ // -------------------------------------------------------------------------------||
+ /**
+ * No instantiation
+ */
+ private SecurityActions() {
+ throw new UnsupportedOperationException("No instantiation");
+ }
+
+ // -------------------------------------------------------------------------------||
+ // Utility Methods ---------------------------------------------------------------||
+ // -------------------------------------------------------------------------------||
+ /**
+ * Obtains the Thread Context ClassLoader
+ */
+ static ClassLoader getThreadContextClassLoader() {
+ return AccessController.doPrivileged(GetTcclAction.INSTANCE);
+ }
+
+ static boolean isClassPresent(String name) {
+ try {
+ loadClass(name);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ static Class<?> loadClass(String className) {
+ try {
+ return Class.forName(className, true, getThreadContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ try {
+ return Class.forName(className, true, SecurityActions.class.getClassLoader());
+ } catch (ClassNotFoundException e2) {
+ throw new RuntimeException("Could not load class " + className, e2);
+ }
+ }
+ }
+
+ static <T> T newInstance(final String className, final Class<?>[] argumentTypes, final Object[] arguments,
+ final Class<T> expectedType) {
+ return newInstance(className, argumentTypes, arguments, expectedType, getThreadContextClassLoader());
+ }
+
+ static <T> T newInstance(final String className, final Class<?>[] argumentTypes, final Object[] arguments,
+ final Class<T> expectedType, ClassLoader classLoader) {
+ Class<?> clazz = null;
+ try {
+ clazz = Class.forName(className, false, classLoader);
+ } catch (Exception e) {
+ throw new RuntimeException("Could not load class " + className, e);
+ }
+ Object obj = newInstance(clazz, argumentTypes, arguments);
+ try {
+ return expectedType.cast(obj);
+ } catch (Exception e) {
+ throw new RuntimeException("Loaded class " + className + " is not of expected type " + expectedType, e);
+ }
+ }
+
+ /**
+ * Create a new instance by finding a constructor that matches the
+ * argumentTypes signature using the arguments for instantiation.
+ *
+ * @param className Full classname of class to create
+ * @param argumentTypes The constructor argument types
+ * @param arguments The constructor arguments
+ * @return a new instance
+ * @throws IllegalArgumentException if className, argumentTypes, or
+ * arguments are null
+ * @throws RuntimeException if any exceptions during creation
+ * @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a>
+ * @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a>
+ */
+ static <T> T newInstance(final Class<T> implClass, final Class<?>[] argumentTypes, final Object[] arguments) {
+ if (implClass == null) {
+ throw new IllegalArgumentException("ImplClass must be specified");
+ }
+ if (argumentTypes == null) {
+ throw new IllegalArgumentException("ArgumentTypes must be specified. Use empty array if no arguments");
+ }
+ if (arguments == null) {
+ throw new IllegalArgumentException("Arguments must be specified. Use empty array if no arguments");
+ }
+ final T obj;
+ try {
+ Constructor<T> constructor = getConstructor(implClass, argumentTypes);
+ if (!constructor.isAccessible()) {
+ constructor.setAccessible(true);
+ }
+ obj = constructor.newInstance(arguments);
+ } catch (Exception e) {
+ throw new RuntimeException("Could not create new instance of " + implClass, e);
+ }
+
+ return obj;
+ }
+
+ /**
+ * Obtains the Constructor specified from the given Class and argument types
+ *
+ * @param clazz
+ * @param argumentTypes
+ * @return
+ * @throws NoSuchMethodException
+ */
+ static <T> Constructor<T> getConstructor(final Class<T> clazz, final Class<?>... argumentTypes)
+ throws NoSuchMethodException {
+ try {
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<T>>() {
+ @Override
+ public Constructor<T> run() throws NoSuchMethodException {
+ return clazz.getDeclaredConstructor(argumentTypes);
+ }
+ });
+ } // Unwrap
+ catch (final PrivilegedActionException pae) {
+ final Throwable t = pae.getCause();
+ // Rethrow
+ if (t instanceof NoSuchMethodException) {
+ throw (NoSuchMethodException) t;
+ } else {
+ // No other checked Exception thrown by Class.getConstructor
+ try {
+ throw (RuntimeException) t;
+ } // Just in case we've really messed up
+ catch (final ClassCastException cce) {
+ throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set a single Field value
+ *
+ * @param target The object to set it on
+ * @param fieldName The field name
+ * @param value The new value
+ */
+ public static void setFieldValue(final Class<?> source, final Object target, final String fieldName,
+ final Object value) throws NoSuchFieldException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+ @Override
+ public Void run() throws Exception {
+ Field field = source.getDeclaredField(fieldName);
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ field.set(target, value);
+ return null;
+ }
+ });
+ } // Unwrap
+ catch (final PrivilegedActionException pae) {
+ final Throwable t = pae.getCause();
+ // Rethrow
+ if (t instanceof NoSuchFieldException) {
+ throw (NoSuchFieldException) t;
+ } else {
+ // No other checked Exception thrown by Class.getConstructor
+ try {
+ throw (RuntimeException) t;
+ } // Just in case we've really messed up
+ catch (final ClassCastException cce) {
+ throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t);
+ }
+ }
+ }
+ }
+
+ public static List<Field> getFieldsWithAnnotation(final Class<?> source,
+ final Class<? extends Annotation> annotationClass) {
+ List<Field> declaredAccessableFields = AccessController.doPrivileged(new PrivilegedAction<List<Field>>() {
+ @Override
+ public List<Field> run() {
+ List<Field> foundFields = new ArrayList<Field>();
+ Class<?> nextSource = source;
+ while (nextSource != Object.class) {
+ for (Field field : nextSource.getDeclaredFields()) {
+ if (field.isAnnotationPresent(annotationClass)) {
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ foundFields.add(field);
+ }
+ }
+ nextSource = nextSource.getSuperclass();
+ }
+ return foundFields;
+ }
+ });
+ return declaredAccessableFields;
+ }
+
+ public static List<Method> getMethodsWithAnnotation(final Class<?> source,
+ final Class<? extends Annotation> annotationClass) {
+ List<Method> declaredAccessableMethods = AccessController.doPrivileged(new PrivilegedAction<List<Method>>() {
+ @Override
+ public List<Method> run() {
+ List<Method> foundMethods = new ArrayList<Method>();
+ Class<?> nextSource = source;
+ while (nextSource != Object.class) {
+ for (Method method : nextSource.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(annotationClass)) {
+ if (!method.isAccessible()) {
+ method.setAccessible(true);
+ }
+ foundMethods.add(method);
+ }
+ }
+ nextSource = nextSource.getSuperclass();
+ }
+ return foundMethods;
+ }
+ });
+ return declaredAccessableMethods;
+ }
+
+ static String getProperty(final String key) {
+ try {
+ String value = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
+ @Override
+ public String run() {
+ return System.getProperty(key);
+ }
+ });
+ return value;
+ } // Unwrap
+ catch (final PrivilegedActionException pae) {
+ final Throwable t = pae.getCause();
+ // Rethrow
+ if (t instanceof SecurityException) {
+ throw (SecurityException) t;
+ }
+ if (t instanceof NullPointerException) {
+ throw (NullPointerException) t;
+ } else if (t instanceof IllegalArgumentException) {
+ throw (IllegalArgumentException) t;
+ } else {
+ // No other checked Exception thrown by System.getProperty
+ try {
+ throw (RuntimeException) t;
+ } // Just in case we've really messed up
+ catch (final ClassCastException cce) {
+ throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t);
+ }
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------------||
+ // Inner Classes -----------------------------------------------------------------||
+ // -------------------------------------------------------------------------------||
+ /**
+ * Single instance to get the TCCL
+ */
+ private enum GetTcclAction implements PrivilegedAction<ClassLoader> {
+
+ INSTANCE;
+
+ @Override
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java
new file mode 100644
index 0000000..ffb3e0c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java
@@ -0,0 +1,187 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.jboss.arquillian.container.spi.event.StartSuiteContainers;
+import org.jboss.arquillian.container.spi.event.StopSuiteContainers;
+import org.jboss.arquillian.container.test.api.ContainerController;
+import org.jboss.arquillian.core.api.Event;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.InstanceProducer;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.core.api.annotation.Observes;
+import org.jboss.arquillian.test.spi.annotation.ClassScoped;
+import org.jboss.arquillian.test.spi.annotation.SuiteScoped;
+import org.jboss.arquillian.container.spi.event.container.AfterStart;
+import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
+import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
+import org.jboss.logging.Logger;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.models.Constants;
+import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
+import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+
+/**
+ *
+ * @author tkyjovsk
+ * @author vramik
+ */
+public class ContainersTestEnricher {
+
+ protected final Logger log = Logger.getLogger(this.getClass());
+
+ @Inject
+ private Instance<ContainerController> containerController;
+
+ @Inject
+ private Event<StopSuiteContainers> stopSuiteContainers;
+
+ private String appServerQualifier;
+
+ private static final String AUTH_SERVER_CONTAINER_PROPERTY = "auth.server.container";
+ private static final String AUTH_SERVER_CONTAINER_DEFAULT = "auth-server-undertow";
+
+ @Inject
+ @SuiteScoped
+ private InstanceProducer<SuiteContext> suiteContext;
+
+ @Inject
+ @ClassScoped
+ private InstanceProducer<TestContext> testContext;
+
+ @Inject
+ @ClassScoped
+ private InstanceProducer<Keycloak> adminClient;
+
+ private ContainerController controller;
+
+ private final boolean migrationTests = System.getProperty("migration", "false").equals("true");
+ private boolean alreadyStopped = false;
+
+ public void startSuiteContainers(@Observes(precedence = 1) StartSuiteContainers event) {
+ if (migrationTests) {
+ log.info("\n### Starting keycloak with previous version ###\n");
+ }
+ }
+
+ public void stopMigrationContainer(@Observes AfterStart event) {
+ if (migrationTests && !alreadyStopped) {
+ log.info("\n### Stopping keycloak with previous version ###\n");
+ stopSuiteContainers.fire(new StopSuiteContainers());
+ }
+ alreadyStopped = true;
+ }
+
+ public void beforeSuite(@Observes BeforeSuite event) {
+ suiteContext.set(new SuiteContext());
+ }
+
+ public void startContainers(@Observes(precedence = -1) BeforeClass event) {
+ controller = containerController.get();
+
+ Class testClass = event.getTestClass().getJavaClass();
+ appServerQualifier = getAppServerQualifier(testClass);
+
+ if (!controller.isStarted(appServerQualifier)) {
+ log.info("\nSTARTING APP SERVER: " + appServerQualifier + "\n");
+ controller.start(appServerQualifier);
+ log.info("");
+ }
+
+ initializeTestContext(testClass);
+ initializeAdminClient();
+ }
+
+ private void initializeTestContext(Class testClass) {
+ String authServerContextRootStr = getAuthServerContextRootFromSystemProperty();
+ String appServerContextRootStr = isRelative(testClass)
+ ? authServerContextRootStr
+ : getAppServerContextRootFromSystemProperty();
+ try {
+ URL authServerContextRoot = new URL(authServerContextRootStr);
+ URL appServerContextRoot = new URL(appServerContextRootStr);
+
+ testContext.set(new TestContext(authServerContextRoot, appServerContextRoot));
+
+ } catch (MalformedURLException ex) {
+ throw new IllegalStateException("Malformed url.", ex);
+ }
+ }
+
+ private void initializeAdminClient() {
+ adminClient.set(Keycloak.getInstance(
+ getAuthServerContextRootFromSystemProperty() + "/auth",
+ MASTER, ADMIN, ADMIN, Constants.ADMIN_CONSOLE_CLIENT_ID));
+ }
+
+ /**
+ *
+ * @param testClass
+ * @param annotationClass
+ * @return testClass or the nearest superclass of testClass annotated with
+ * annotationClass
+ */
+ public static Class getNearestSuperclassWithAnnotation(Class testClass, Class annotationClass) {
+ return testClass.isAnnotationPresent(annotationClass) ? testClass
+ : (testClass.getSuperclass().equals(Object.class) ? null // stop recursion
+ : getNearestSuperclassWithAnnotation(testClass.getSuperclass(), annotationClass)); // continue recursion
+ }
+
+ public static String getAuthServerQualifier() {
+ return System.getProperty(
+ AUTH_SERVER_CONTAINER_PROPERTY,
+ AUTH_SERVER_CONTAINER_DEFAULT);
+ }
+
+ public static String getAppServerQualifier(Class testClass) {
+ Class<? extends ContainersTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class);
+
+ String appServerQ = (annotatedClass == null ? null
+ : annotatedClass.getAnnotation(AppServerContainer.class).value());
+
+ return appServerQ == null || appServerQ.isEmpty()
+ ? getAuthServerQualifier() // app server == auth server
+ : appServerQ;
+ }
+
+ public static boolean hasAppServerContainerAnnotation(Class testClass) {
+ return getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class) != null;
+ }
+
+ public static boolean isRelative(Class testClass) {
+ return getAppServerQualifier(testClass).equals(getAuthServerQualifier());
+ }
+
+ public static String getAdapterLibsLocationProperty(Class testClass) {
+ Class<? extends ContainersTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AdapterLibsLocationProperty.class);
+ return (annotatedClass == null ? null
+ : annotatedClass.getAnnotation(AdapterLibsLocationProperty.class).value());
+ }
+
+ public static boolean isWildflyAppServer(Class testClass) {
+ return getAppServerQualifier(testClass).contains("wildfly");
+ }
+
+ public static boolean isTomcatAppServer(Class testClass) {
+ return getAppServerQualifier(testClass).contains("tomcat");
+ }
+
+ public static boolean isOSGiAppServer(Class testClass) {
+ String q = getAppServerQualifier(testClass);
+ return q.contains("karaf") || q.contains("fuse");
+ }
+
+ public static String getAuthServerContextRootFromSystemProperty() {
+ // TODO find if this can be extracted from ARQ metadata instead of System properties
+ return "http://localhost:" + Integer.parseInt(
+ System.getProperty("auth.server.http.port", "8180"));
+ }
+
+ public static String getAppServerContextRootFromSystemProperty() {
+ return "http://localhost:" + Integer.parseInt(
+ System.getProperty("app.server.http.port", "8280"));
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
new file mode 100644
index 0000000..0a965d8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
@@ -0,0 +1,140 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.apache.tools.ant.DirectoryScanner;
+import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
+import org.jboss.arquillian.test.spi.TestClass;
+import org.jboss.logging.Logger;
+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.representations.adapters.config.BaseAdapterConfig;
+import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*;
+import org.keycloak.testsuite.adapter.AdapterLibsMode;
+import static org.keycloak.testsuite.util.IOUtil.loadJson;;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
+
+ public static final String REALM_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
+
+ protected final Logger log = org.jboss.logging.Logger.getLogger(this.getClass());
+
+ public static final String WEBXML_PATH = "/WEB-INF/web.xml";
+ public static final String ADAPTER_CONFIG_PATH = "/WEB-INF/keycloak.json";
+ public static final String ADAPTER_CONFIG_PATH_TENANT1 = "/WEB-INF/classes/tenant1-keycloak.json";
+ public static final String ADAPTER_CONFIG_PATH_TENANT2 = "/WEB-INF/classes/tenant2-keycloak.json";
+ public static final String ADAPTER_CONFIG_PATH_JS = "/keycloak.json";
+
+ @Override
+ public void process(Archive<?> archive, TestClass testClass) {
+ log.info("Processing archive " + archive.getName());
+// if (isAdapterTest(testClass)) {
+ modifyAdapterConfigs(archive, testClass);
+ attachKeycloakLibs(archive, testClass);
+ modifyWebXml(archive, testClass);
+// } else {
+// log.info(testClass.getJavaClass().getSimpleName() + " is not an AdapterTest");
+// }
+ }
+
+ public static boolean isAdapterTest(TestClass testClass) {
+ return hasAppServerContainerAnnotation(testClass.getJavaClass());
+ }
+
+ protected void modifyAdapterConfigs(Archive<?> archive, TestClass testClass) {
+ boolean relative = isRelative(testClass.getJavaClass());
+ modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH, relative);
+ modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH_TENANT1, relative);
+ modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH_TENANT2, relative);
+ modifyAdapterConfig(archive, ADAPTER_CONFIG_PATH_JS, relative);
+ }
+
+ protected void modifyAdapterConfig(Archive<?> archive, String adapterConfigPath, boolean relative) {
+ if (archive.contains(adapterConfigPath)) {
+ log.info("Modifying adapter config " + adapterConfigPath + " in " + archive.getName());
+ try {
+ BaseAdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
+ .getAsset().openStream(), BaseAdapterConfig.class);
+
+ log.info(" setting " + (relative ? "" : "non-") + "relative auth-server-url");
+ if (relative) {
+ adapterConfig.setAuthServerUrl("/auth");
+// ac.setRealmKey(null); // TODO verify if realm key is required for relative scneario
+ } else {
+ adapterConfig.setAuthServerUrl(getAuthServerContextRootFromSystemProperty() + "/auth");
+ adapterConfig.setRealmKey(REALM_KEY);
+ }
+
+ archive.add(new StringAsset(JsonSerialization.writeValueAsPrettyString(adapterConfig)),
+ adapterConfigPath);
+
+ } catch (IOException ex) {
+ log.log(Level.FATAL, "Cannot serialize adapter config to JSON.", ex);
+ }
+ }
+ }
+
+ protected void attachKeycloakLibs(Archive<?> archive, TestClass testClass) {
+ AdapterLibsMode adapterType = AdapterLibsMode.getByType(System.getProperty("adapter.libs.mode",
+ AdapterLibsMode.PROVIDED.getType()));
+ log.info("Adapter type: " + adapterType);
+ if (adapterType.equals(AdapterLibsMode.BUNDLED)) {
+ log.info("Attaching keycloak adapter libs to " + archive.getName());
+
+ String libsLocationProperty = getAdapterLibsLocationProperty(testClass.getJavaClass());
+ assert libsLocationProperty != null;
+ File libsLocation = new File(System.getProperty(libsLocationProperty));
+ assert libsLocation.exists();
+ log.info("Libs location: " + libsLocation.getPath());
+
+ WebArchive war = (WebArchive) archive;
+
+ for (File lib : getAdapterLibs(libsLocation)) {
+ log.info(" attaching: " + lib.getName());
+ war.addAsLibrary(lib);
+ }
+ } else {
+ log.info("Expecting keycloak adapter libs to be provided by the server.");
+ }
+ }
+
+ DirectoryScanner scanner = new DirectoryScanner();
+
+ protected List<File> getAdapterLibs(File adapterLibsLocation) {
+ assert adapterLibsLocation.exists();
+ List<File> libs = new ArrayList<>();
+ scanner.setBasedir(adapterLibsLocation);
+ scanner.setIncludes(new String[]{"**/*jar"});
+ scanner.scan();
+ for (String lib : scanner.getIncludedFiles()) {
+ libs.add(new File(adapterLibsLocation, lib));
+ }
+ return libs;
+ }
+
+ protected void modifyWebXml(Archive<?> archive, TestClass testClass) {
+ if (isTomcatAppServer(testClass.getJavaClass())) {
+ try {
+ String webXmlContent = IOUtils.toString(
+ archive.get(WEBXML_PATH).getAsset().openStream());
+
+ webXmlContent = webXmlContent.replace("<auth-method>KEYCLOAK</auth-method>", "<auth-method>BASIC</auth-method>");
+
+ archive.add(new StringAsset((webXmlContent)), WEBXML_PATH);
+ } catch (IOException ex) {
+ throw new RuntimeException("Cannot load web.xml from archive.");
+ }
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java
new file mode 100644
index 0000000..faaeb81
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java
@@ -0,0 +1,40 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.util.List;
+import org.jboss.arquillian.container.spi.client.deployment.DeploymentDescription;
+import org.jboss.arquillian.container.spi.client.deployment.TargetDescription;
+import org.jboss.arquillian.container.test.impl.client.deployment.AnnotationDeploymentScenarioGenerator;
+import org.jboss.arquillian.test.spi.TestClass;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*;
+
+/**
+ * Changes target container for all Arquillian deployments based on value of
+ * @AppServerContainer.
+ *
+ * @author tkyjovsk
+ */
+public class DeploymentTargetModifier extends AnnotationDeploymentScenarioGenerator {
+
+ protected final Logger log = Logger.getLogger(this.getClass());
+
+ @Override
+ public List<DeploymentDescription> generate(TestClass testClass) {
+ List<DeploymentDescription> deployments = super.generate(testClass);
+
+ String appServerQualifier = getAppServerQualifier(
+ testClass.getJavaClass());
+
+ if (appServerQualifier != null && !appServerQualifier.isEmpty()) {
+ for (DeploymentDescription deployment : deployments) {
+ if (deployment.getTarget() == null || !deployment.getTarget().getName().equals(appServerQualifier)) {
+ log.debug("Setting target container for " + deployment.getName() + ": " + appServerQualifier);
+ deployment.setTarget(new TargetDescription(appServerQualifier));
+ }
+ }
+ }
+
+ return deployments;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JBossJiraParser.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JBossJiraParser.java
new file mode 100644
index 0000000..ea606b8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JBossJiraParser.java
@@ -0,0 +1,43 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+
+/**
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ */
+public class JBossJiraParser {
+
+ private static final String JBOSS_TRACKER_REST_URL = "https://issues.jboss.org/rest/api/latest/issue/";
+
+ public static boolean isIssueClosed(String issueId) {
+ Status issueStatus;
+ try {
+ issueStatus = getIssueStatus(issueId);
+ } catch(Exception e) {
+ issueStatus = Status.CLOSED; //let the test run in case there is no connection
+ }
+ return issueStatus == Status.CLOSED || issueStatus == Status.RESOLVED;
+ }
+
+ private static Status getIssueStatus(String issueId) throws Exception {
+ Client client = ClientBuilder.newClient();
+ WebTarget target = client.target(JBOSS_TRACKER_REST_URL);
+ String json = target.path(issueId).request().accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
+ JsonObject jsonObject = new Gson().fromJson(json, JsonElement.class).getAsJsonObject();
+ String status = jsonObject.getAsJsonObject("fields").getAsJsonObject("status").get("name").getAsString();
+ client.close();
+ return Status.getByStatus(status);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Jira.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Jira.java
new file mode 100644
index 0000000..961ae82
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Jira.java
@@ -0,0 +1,28 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Value should contain name of the issue listed in JBoss JIRA (like
+ * KEYCLOAK-1234), it can also contain multiple names separated by coma.
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Documented
+public @interface Jira {
+
+ String value();
+ boolean enabled() default true;
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JiraTestExecutionDecider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JiraTestExecutionDecider.java
new file mode 100644
index 0000000..fa3c571
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/JiraTestExecutionDecider.java
@@ -0,0 +1,61 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import org.jboss.arquillian.test.spi.execution.ExecutionDecision;
+import org.jboss.arquillian.test.spi.execution.TestExecutionDecider;
+
+import static org.keycloak.testsuite.arquillian.jira.JBossJiraParser.isIssueClosed;
+
+/**
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ */
+public class JiraTestExecutionDecider implements TestExecutionDecider {
+
+ private static Map<String, Boolean> cache = new HashMap<String, Boolean>();
+
+ @Override
+ public ExecutionDecision decide(Method method) {
+ Jira jiraAnnotation = method.getAnnotation(Jira.class);
+ if (jiraAnnotation != null && jiraAnnotation.enabled()) {
+ boolean executeTest = true;
+ String[] issueIds = getIssuesId(jiraAnnotation.value());
+ for (String issueId : issueIds) {
+ if (cache.containsKey(issueId)) {
+ executeTest = cache.get(issueId);
+ } else {
+ if (isIssueClosed(issueId)) {
+ cache.put(issueId, true);
+ } else {
+ executeTest = false;
+ cache.put(issueId, false);
+ }
+ }
+ }
+
+ if (executeTest) {
+ return ExecutionDecision.execute();
+ } else {
+ return ExecutionDecision.dontExecute("Issue is still opened, therefore skipping the test " + method.getName());
+ }
+ }
+ return ExecutionDecision.execute();
+ }
+
+ private String[] getIssuesId(String value) {
+ return value.replaceAll("\\s+", "").split(",");
+ }
+
+ @Override
+ public int precedence() {
+ return 0;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Status.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Status.java
new file mode 100644
index 0000000..47f707a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/jira/Status.java
@@ -0,0 +1,36 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.keycloak.testsuite.arquillian.jira;
+
+/**
+ *
+ * @author <a href="mailto:pmensik@redhat.com">Petr Mensik</a>
+ */
+public enum Status {
+
+ OPEN("Open"), CLOSED("Closed"), PULL_REQUEST_SENT("Pull Request Sent"), REOPENED("Reopened"),
+ RESOLVED("Resolved"), CODING_IN_PROGRESS("Coding In Progress ");
+
+ private String status;
+
+ private Status(String status) {
+ this.status = status;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public static Status getByStatus(String status) {
+ for (Status s : Status.values()) {
+ if (s.getStatus().equals(status)) {
+ return s;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java
new file mode 100644
index 0000000..cf25d05
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java
@@ -0,0 +1,49 @@
+package org.keycloak.testsuite.arquillian;
+
+import org.keycloak.testsuite.arquillian.provider.URLProvider;
+import org.keycloak.testsuite.arquillian.provider.SuiteContextProvider;
+import org.keycloak.testsuite.arquillian.provider.TestContextProvider;
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider;
+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.graphene.location.CustomizableURLResourceProvider;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+import org.jboss.arquillian.test.spi.execution.TestExecutionDecider;
+import org.keycloak.testsuite.arquillian.jira.JiraTestExecutionDecider;
+import org.keycloak.testsuite.arquillian.provider.AdminClientProvider;
+import org.keycloak.testsuite.arquillian.undertow.CustomUndertowContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class KeycloakArquillianExtension implements LoadableExtension {
+
+ @Override
+ public void register(ExtensionBuilder builder) {
+
+ builder
+ .service(ResourceProvider.class, SuiteContextProvider.class)
+ .service(ResourceProvider.class, TestContextProvider.class)
+ .service(ResourceProvider.class, AdminClientProvider.class);
+
+ builder
+ .service(DeploymentScenarioGenerator.class, DeploymentTargetModifier.class)
+ .service(ApplicationArchiveProcessor.class, DeploymentArchiveProcessor.class)
+ .observer(ContainersTestEnricher.class);
+
+ builder
+ .service(DeployableContainer.class, CustomUndertowContainer.class);
+
+ builder
+ .service(TestExecutionDecider.class, JiraTestExecutionDecider.class);
+
+ builder
+ .override(ResourceProvider.class, URLResourceProvider.class, URLProvider.class)
+ .override(ResourceProvider.class, CustomizableURLResourceProvider.class, URLProvider.class);
+
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/AdminClientProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/AdminClientProvider.java
new file mode 100644
index 0000000..8e7c3ac
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/AdminClientProvider.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import java.lang.annotation.Annotation;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+import org.keycloak.admin.client.Keycloak;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminClientProvider implements ResourceProvider {
+
+ @Inject
+ Instance<Keycloak> adminClient;
+
+ @Override
+ public boolean canProvide(Class<?> type) {
+ return Keycloak.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public Object lookup(ArquillianResource resource, Annotation... qualifiers) {
+ return adminClient.get();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/SuiteContextProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/SuiteContextProvider.java
new file mode 100644
index 0000000..2755688
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/SuiteContextProvider.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import org.keycloak.testsuite.arquillian.SuiteContext;
+import java.lang.annotation.Annotation;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class SuiteContextProvider implements ResourceProvider {
+
+ @Inject
+ Instance<SuiteContext> suiteContext;
+
+ @Override
+ public boolean canProvide(Class<?> type) {
+ return SuiteContext.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public Object lookup(ArquillianResource resource, Annotation... qualifiers) {
+ return suiteContext.get();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/TestContextProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/TestContextProvider.java
new file mode 100644
index 0000000..ebe7326
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/TestContextProvider.java
@@ -0,0 +1,30 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import org.keycloak.testsuite.arquillian.TestContext;
+import java.lang.annotation.Annotation;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class TestContextProvider implements ResourceProvider {
+
+ @Inject
+ Instance<TestContext> testContext;
+
+ @Override
+ public boolean canProvide(Class<?> type) {
+ return TestContext.class.isAssignableFrom(type);
+ }
+
+ @Override
+ @ClassInjection
+ public Object lookup(ArquillianResource resource, Annotation... qualifiers) {
+ return testContext.get();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java
new file mode 100644
index 0000000..dd31483
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java
@@ -0,0 +1,79 @@
+package org.keycloak.testsuite.arquillian.provider;
+
+import org.keycloak.testsuite.arquillian.TestContext;
+import java.lang.annotation.Annotation;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.logging.Logger;
+import org.jboss.logging.Logger.Level;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContext;
+import org.keycloak.testsuite.arquillian.annotation.AuthServerContext;
+
+public class URLProvider extends URLResourceProvider {
+
+ protected final Logger log = Logger.getLogger(this.getClass());
+
+ public static final String LOCALHOST_ADDRESS = "127.0.0.1";
+ public static final String LOCALHOST_HOSTNAME = "localhost";
+
+ @Inject
+ Instance<TestContext> testContext;
+
+ private static final Set<String> fixedUrls = new HashSet<>();
+
+ @Override
+ public Object doLookup(ArquillianResource resource, Annotation... qualifiers) {
+ URL url = (URL) super.doLookup(resource, qualifiers);
+
+ // fix injected URL
+ if (url != null) {
+ try {
+ url = fixLocalhost(url);
+ url = removeTrailingSlash(url);
+ } catch (MalformedURLException ex) {
+ log.log(Level.FATAL, null, ex);
+ }
+
+ if (!fixedUrls.contains(url.toString())) {
+ fixedUrls.add(url.toString());
+ log.debug("Fixed injected @ArquillianResource URL to: " + url);
+ }
+ }
+
+ // inject context roots if annotation present
+ for (Annotation a : qualifiers) {
+ if (AuthServerContext.class.isAssignableFrom(a.annotationType())) {
+ return testContext.get().getAuthServerContextRoot();
+ }
+ if (AppServerContext.class.isAssignableFrom(a.annotationType())) {
+ return testContext.get().getAppServerContextRoot();
+ }
+ }
+
+ return url;
+ }
+
+ public URL fixLocalhost(URL url) throws MalformedURLException {
+ URL fixedUrl = url;
+ if (url.getHost().contains(LOCALHOST_ADDRESS)) {
+ fixedUrl = new URL(fixedUrl.toExternalForm().replace(LOCALHOST_ADDRESS, LOCALHOST_HOSTNAME));
+ }
+ return fixedUrl;
+ }
+
+ public URL removeTrailingSlash(URL url) throws MalformedURLException {
+ URL urlWithoutSlash = url;
+ String urlS = url.toExternalForm();
+ if (urlS.endsWith("/")) {
+ urlWithoutSlash = new URL(urlS.substring(0, urlS.length() - 1));
+ }
+ return urlWithoutSlash;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java
new file mode 100644
index 0000000..589c316
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.util.HashMap;
+import java.util.Map;
+import static org.keycloak.testsuite.util.MailServerConfiguration.*;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public final class SuiteContext {
+
+ private boolean adminPasswordUpdated;
+ private final Map<String, String> smtpServer = new HashMap<>();
+
+ public SuiteContext() {
+ this.adminPasswordUpdated = false;
+ smtpServer.put("from", FROM);
+ smtpServer.put("host", HOST);
+ smtpServer.put("port", PORT);
+ }
+
+ public boolean isAdminPasswordUpdated() {
+ return adminPasswordUpdated;
+ }
+
+ public void setAdminPasswordUpdated(boolean adminPasswordUpdated) {
+ this.adminPasswordUpdated = adminPasswordUpdated;
+ }
+
+ public Map<String, String> getSmtpServer() {
+ return smtpServer;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java
new file mode 100644
index 0000000..850c787
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java
@@ -0,0 +1,50 @@
+package org.keycloak.testsuite.arquillian;
+
+import java.net.URL;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public final class TestContext {
+
+ private URL authServerContextRoot;
+ private URL appServerContextRoot;
+
+ private boolean adminLoggedIn;
+
+ public TestContext() {
+ this.adminLoggedIn = false;
+ }
+
+ public TestContext(URL authServerContextRoot, URL appServerContextRoot) {
+ this();
+ this.authServerContextRoot = authServerContextRoot;
+ this.appServerContextRoot = appServerContextRoot;
+ }
+
+ public URL getAuthServerContextRoot() {
+ return authServerContextRoot;
+ }
+
+ public URL getAppServerContextRoot() {
+ return appServerContextRoot;
+ }
+
+ public boolean isAdminLoggedIn() {
+ return adminLoggedIn;
+ }
+
+ public void setAdminLoggedIn(boolean adminLoggedIn) {
+ this.adminLoggedIn = adminLoggedIn;
+ }
+
+ public void setAuthServerContextRoot(URL authServerContextRoot) {
+ this.authServerContextRoot = authServerContextRoot;
+ }
+
+ public void setAppServerContextRoot(URL appServerContextRoot) {
+ this.appServerContextRoot = appServerContextRoot;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainer.java
new file mode 100644
index 0000000..e2dc4db
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainer.java
@@ -0,0 +1,144 @@
+package org.keycloak.testsuite.arquillian.undertow;
+
+import io.undertow.Undertow;
+import io.undertow.servlet.Servlets;
+import io.undertow.servlet.api.DefaultServletConfig;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.FilterInfo;
+import io.undertow.servlet.api.ServletInfo;
+
+import java.util.Collection;
+import java.util.Map;
+import javax.servlet.DispatcherType;
+
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+
+import org.jboss.arquillian.container.spi.client.container.DeploymentException;
+import org.jboss.arquillian.container.spi.client.container.LifecycleException;
+import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.Servlet;
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
+import org.jboss.resteasy.spi.ResteasyDeployment;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.descriptor.api.Descriptor;
+import org.jboss.shrinkwrap.undertow.api.UndertowWebArchive;
+import org.keycloak.services.filters.ClientConnectionFilter;
+import org.keycloak.services.filters.KeycloakSessionServletFilter;
+import org.keycloak.services.resources.KeycloakApplication;
+
+public class CustomUndertowContainer implements DeployableContainer<CustomUndertowContainerConfiguration> {
+
+ protected final Logger log = Logger.getLogger(this.getClass());
+
+ private UndertowJaxrsServer undertow;
+ private CustomUndertowContainerConfiguration configuration;
+
+ private DeploymentInfo createAuthServerDeploymentInfo() {
+ ResteasyDeployment deployment = new ResteasyDeployment();
+ deployment.setApplicationClass(KeycloakApplication.class.getName());
+
+ DeploymentInfo di = undertow.undertowDeployment(deployment);
+ di.setClassLoader(getClass().getClassLoader());
+ di.setContextPath("/auth");
+ di.setDeploymentName("Keycloak");
+
+ di.setDefaultServletConfig(new DefaultServletConfig(true));
+ di.addWelcomePage("theme/keycloak/welcome/resources/index.html");
+
+ FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
+ di.addFilter(filter);
+ di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
+
+ FilterInfo connectionFilter = Servlets.filter("ClientConnectionFilter", ClientConnectionFilter.class);
+ di.addFilter(connectionFilter);
+ di.addFilterUrlMapping("ClientConnectionFilter", "/*", DispatcherType.REQUEST);
+
+ return di;
+ }
+
+ public DeploymentInfo getDeplotymentInfoFromArchive(Archive<?> archive) {
+ if (archive instanceof UndertowWebArchive) {
+ return ((UndertowWebArchive) archive).getDeploymentInfo();
+ } else {
+ throw new IllegalArgumentException("UndertowContainer only supports UndertowWebArchive or WebArchive.");
+ }
+ }
+
+ private HTTPContext createHttpContextForDeploymentInfo(DeploymentInfo deploymentInfo) {
+ HTTPContext httpContext = new HTTPContext(configuration.getBindAddress(), configuration.getBindHttpPort());
+ final Map<String, ServletInfo> servlets = deploymentInfo.getServlets();
+ final Collection<ServletInfo> servletsInfo = servlets.values();
+ for (ServletInfo servletInfo : servletsInfo) {
+ httpContext.add(new Servlet(servletInfo.getName(), deploymentInfo.getContextPath()));
+ }
+ return httpContext;
+ }
+
+ @Override
+ public ProtocolMetaData deploy(Archive<?> archive) throws DeploymentException {
+ DeploymentInfo di = getDeplotymentInfoFromArchive(archive);
+ undertow.deploy(di);
+ return new ProtocolMetaData().addContext(
+ createHttpContextForDeploymentInfo(di));
+ }
+
+ @Override
+ public void deploy(Descriptor descriptor) throws DeploymentException {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public Class<CustomUndertowContainerConfiguration> getConfigurationClass() {
+ return CustomUndertowContainerConfiguration.class;
+ }
+
+ @Override
+ public ProtocolDescription getDefaultProtocol() {
+ return new ProtocolDescription("Servlet 3.1");
+ }
+
+ @Override
+ public void setup(
+ CustomUndertowContainerConfiguration undertowContainerConfiguration) {
+ this.configuration = undertowContainerConfiguration;
+ }
+
+ @Override
+ public void start() throws LifecycleException {
+ log.info("Starting auth server on embedded Undertow.");
+ long start = System.currentTimeMillis();
+
+ if (undertow == null) {
+ undertow = new UndertowJaxrsServer();
+ }
+ undertow.start(Undertow.builder()
+ .addHttpListener(configuration.getBindHttpPort(), configuration.getBindAddress())
+ .setWorkerThreads(configuration.getWorkerThreads())
+ .setIoThreads(configuration.getWorkerThreads() / 8)
+ );
+
+ undertow.deploy(createAuthServerDeploymentInfo());
+
+ log.info("Auth server started in " + (System.currentTimeMillis() - start) + " ms\n");
+ }
+
+ @Override
+ public void stop() throws LifecycleException {
+ log.info("Stopping auth server.");
+ undertow.stop();
+ }
+
+ @Override
+ public void undeploy(Archive<?> archive) throws DeploymentException {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public void undeploy(Descriptor descriptor) throws DeploymentException {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainerConfiguration.java
new file mode 100644
index 0000000..5d87119
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/undertow/CustomUndertowContainerConfiguration.java
@@ -0,0 +1,35 @@
+package org.keycloak.testsuite.arquillian.undertow;
+
+import org.arquillian.undertow.UndertowContainerConfiguration;
+import org.jboss.arquillian.container.spi.ConfigurationException;
+
+public class CustomUndertowContainerConfiguration extends UndertowContainerConfiguration {
+
+ private int workerThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2) * 8;
+ private String resourcesHome;
+
+ public int getWorkerThreads() {
+ return workerThreads;
+ }
+
+ public void setWorkerThreads(int workerThreads) {
+ this.workerThreads = workerThreads;
+ }
+
+ public String getResourcesHome() {
+ return resourcesHome;
+ }
+
+ public void setResourcesHome(String resourcesHome) {
+ this.resourcesHome = resourcesHome;
+ }
+
+ @Override
+ public void validate() throws ConfigurationException {
+ super.validate();
+
+ // TODO validate workerThreads
+
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java
new file mode 100644
index 0000000..10cc7e5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/Account.java
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.auth.page.account;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ */
+public class Account extends AccountManagement {
+
+ @FindBy(id = "username")
+ private WebElement username;
+
+ @FindBy(id = "email")
+ private WebElement email;
+
+ @FindBy(id = "lastName")
+ private WebElement lastName;
+
+ @FindBy(id = "firstName")
+ private WebElement firstName;
+
+ public String getUsername() {
+ return username.getAttribute("value");
+ }
+
+ public String getEmail() {
+ return email.getAttribute("value");
+ }
+
+ public String getFirstName() {
+ return firstName.getAttribute("value");
+ }
+
+ public String getLastName() {
+ return lastName.getAttribute("value");
+ }
+
+ public Account setEmail(String value) {
+ email.clear();
+ email.sendKeys(value);
+ return this;
+ }
+
+ public Account setFirstName(String value) {
+ firstName.clear();
+ firstName.sendKeys(value);
+ return this;
+ }
+
+ public Account setLastName(String value) {
+ lastName.clear();
+ lastName.sendKeys(value);
+ return this;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java
new file mode 100644
index 0000000..f78d31a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java
@@ -0,0 +1,59 @@
+package org.keycloak.testsuite.auth.page.account;
+
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElementNotPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AccountFields extends Form {
+
+ @FindBy(id = "username")
+ private WebElement usernameInput;
+ @FindBy(id = "email")
+ private WebElement emailInput;
+ @FindBy(id = "firstName")
+ private WebElement firstNameInput;
+ @FindBy(id = "lastName")
+ private WebElement lastNameInput;
+
+ public void setUsername(String username) {
+ Form.setInputValue(usernameInput, username);
+ }
+
+ public AccountFields setEmail(String email) {
+ Form.setInputValue(emailInput, email);
+ return this;
+ }
+
+ public AccountFields setFirstName(String firstName) {
+ Form.setInputValue(firstNameInput, firstName);
+ return this;
+ }
+
+ public AccountFields setLastName(String lastName) {
+ Form.setInputValue(lastNameInput, lastName);
+ return this;
+ }
+
+ public void setValues(UserRepresentation user) {
+ setUsername(user.getUsername());
+ setEmail(user.getEmail());
+ setFirstName(user.getFirstName());
+ setLastName(user.getLastName());
+ }
+
+ public void waitForUsernameInputPresent() {
+ waitAjaxForElement(usernameInput);
+ }
+
+ public void waitForUsernameInputNotPresent() {
+ waitAjaxForElementNotPresent(usernameInput);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ContactInfoFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ContactInfoFields.java
new file mode 100644
index 0000000..6d1a96c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/ContactInfoFields.java
@@ -0,0 +1,24 @@
+package org.keycloak.testsuite.auth.page.account;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ContactInfoFields extends Form {
+
+ @FindBy(id = "user.attributes.street")
+ private WebElement streetInput;
+ @FindBy(id = "user.attributes.locality")
+ private WebElement localityInput;
+ @FindBy(id = "user.attributes.region")
+ private WebElement regionInput;
+ @FindBy(id = "user.attributes.postal_code")
+ private WebElement postalCodeInput;
+ @FindBy(id = "user.attributes.country")
+ private WebElement counryInput;
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/PasswordFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/PasswordFields.java
new file mode 100644
index 0000000..1d36bf5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/PasswordFields.java
@@ -0,0 +1,38 @@
+package org.keycloak.testsuite.auth.page.account;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class PasswordFields extends Form {
+
+ @FindBy(id = "password")
+ private WebElement passwordInput;
+ @FindBy(id = "password-new")
+ private WebElement newPasswordInput;
+ @FindBy(id = "password-confirm")
+ private WebElement confirmPasswordInput;
+
+ public void setPassword(String password) {
+ setInputValue(passwordInput, password);
+ }
+
+ public void setNewPassword(String newPassword) {
+ setInputValue(newPasswordInput, newPassword);
+ }
+
+ public void setConfirmPassword(String confirmPassword) {
+ setInputValue(confirmPasswordInput, confirmPassword);
+ }
+
+ public void setPasswords(String password, String newPassword, String confirmPassword) {
+ setPassword(password);
+ setNewPassword(newPassword);
+ setConfirmPassword(confirmPassword);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthRealm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthRealm.java
new file mode 100644
index 0000000..e8a435c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthRealm.java
@@ -0,0 +1,58 @@
+package org.keycloak.testsuite.auth.page;
+
+import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
+import java.net.URI;
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+
+/**
+ * Keycloak realm.
+ *
+ * URL: http://localhost:${auth.server.http.port}/auth/realms/{authRealm}
+ *
+ * @author tkyjovsk
+ */
+public class AuthRealm extends AuthServer implements PageWithLoginUrl {
+
+ public static final String AUTH_REALM = "authRealm";
+
+ public static final String MASTER = "master";
+ public static final String TEST = "test";
+ public static final String DEMO = "demo";
+ public static final String EXAMPLE = "example";
+
+ public static final String ADMIN = "admin";
+
+ public AuthRealm() {
+ setUriParameter(AUTH_REALM, MASTER);
+ }
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder()
+ .path("realms/{" + AUTH_REALM + "}");
+ }
+
+ public void setAuthRealm(String authRealm) {
+ setUriParameter(AUTH_REALM, authRealm);
+ }
+
+ public void setAuthRealm(AuthRealm authRealm) {
+ setUriParameter(AUTH_REALM, authRealm.getAuthRealm());
+ }
+
+ public String getAuthRealm() {
+ return (String) getUriParameter(AUTH_REALM);
+ }
+
+ /**
+ *
+ * @return OIDC Login URL for authRealm
+ */
+ @Override
+ public URI getOIDCLoginUrl() {
+ return OIDCLoginProtocolService.authUrl(UriBuilder.fromPath(getAuthRoot()))
+ .build(getAuthRealm());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java
new file mode 100644
index 0000000..373c7bb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.auth.page;
+
+import java.net.URI;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.admin.client.Keycloak;
+
+/**
+ * Context path of Keycloak auth server.
+ *
+ * URL: http://localhost:${auth.server.http.port}/auth
+ *
+ * @author tkyjovsk
+ */
+public class AuthServer extends AuthServerContextRoot {
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder().path("auth");
+ }
+
+ public String getAuthRoot() {
+ URI uri = buildUri();
+ return uri.getScheme() + "://" + uri.getAuthority() + "/auth";
+ }
+
+ @ArquillianResource
+ protected Keycloak keycloak;
+
+ public Keycloak keycloak() {
+ return keycloak;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServerContextRoot.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServerContextRoot.java
new file mode 100644
index 0000000..6baf3a4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServerContextRoot.java
@@ -0,0 +1,26 @@
+package org.keycloak.testsuite.auth.page;
+
+import java.net.URL;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.arquillian.annotation.AuthServerContext;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+/**
+ * Context root of the tested Keycloak server.
+ *
+ * URL: http://localhost:${auth.server.http.port}
+ *
+ * @author tkyjovsk
+ */
+public class AuthServerContextRoot extends AbstractPageWithInjectedUrl {
+
+ @ArquillianResource
+ @AuthServerContext
+ private URL authServerContextRoot;
+
+ @Override
+ public URL getInjectedUrl() {
+ return authServerContextRoot;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Authenticate.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Authenticate.java
new file mode 100644
index 0000000..97dc1da
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Authenticate.java
@@ -0,0 +1,24 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class Authenticate extends LoginActions {
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder().path("authenticate");
+ }
+
+ @Page
+ private LoginForm login;
+
+ public LoginForm loginForm() {
+ return login;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Login.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Login.java
new file mode 100644
index 0000000..e06c5b9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Login.java
@@ -0,0 +1,72 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.auth.page.login;
+
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementNotPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public abstract class Login extends AuthRealm {
+
+ public static final String PROTOCOL = "protocol";
+ public static final String OIDC = "openid-connect";
+ public static final String SAML = "saml";
+
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder()
+ .path("protocol/{" + PROTOCOL + "}/auth");
+ }
+
+ public void setProtocol(String protocol) {
+ setUriParameter(PROTOCOL, protocol);
+ }
+
+ public String getProtocol() {
+ return getUriParameter(PROTOCOL).toString();
+ }
+
+ @Page
+ private LoginForm form;
+
+ public LoginForm form() {
+ return form;
+ }
+
+ @FindBy(css = "link[href*='login/keycloak/css/login.css']")
+ private WebElement keycloakTheme;
+
+ public void waitForKeycloakThemeNotPresent() {
+ waitGuiForElementNotPresent(keycloakTheme);
+ }
+
+ public void waitForKeycloakThemePresent() {
+ waitGuiForElement(keycloakTheme);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java
new file mode 100644
index 0000000..3441677
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginActions.java
@@ -0,0 +1,43 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class LoginActions extends AuthRealm {
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder()
+ .path("login-actions");
+ }
+
+ @FindBy(css = "input[type='submit']")
+ private WebElement submitButton;
+
+ @FindBy(css = "div[id='kc-form-options'] span a")
+ private WebElement backToLoginForm;
+
+ @FindBy(css = "span.kc-feedback-text")
+ private WebElement feedbackText;
+
+ public String getFeedbackText() {
+ waitGuiForElementPresent(feedbackText, "Feedback message should be visible");
+ return feedbackText.getText();
+ }
+
+ public void backToLoginPage() {
+ backToLoginForm.click();
+ }
+
+ public void submit() {
+ submitButton.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
new file mode 100644
index 0000000..61075f2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
@@ -0,0 +1,83 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import org.keycloak.testsuite.auth.page.account.AccountFields;
+import org.keycloak.testsuite.auth.page.account.PasswordFields;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElementNotPresent;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class LoginForm extends Form {
+
+ @Page
+ private AccountFields accountFields;
+ @Page
+ private PasswordFields passwordFields;
+
+ @FindBy(name = "login")
+ private WebElement loginButton;
+// @FindBy(name = "cancel")
+// private WebElement cancelButton;
+
+ @FindBy(linkText = "Register")
+ private WebElement registerLink;
+ @FindBy(linkText = "Forgot Password?")
+ private WebElement forgottenPassword;
+
+ public void setUsername(String username) {
+ accountFields.setUsername(username);
+ }
+
+ public void setPassword(String password) {
+ passwordFields.setPassword(password);
+ }
+
+ public void login(UserRepresentation user) {
+ login(user.getUsername(), getPasswordOf(user));
+ }
+
+ public void login(String username, String password) {
+ setUsername(username);
+ setPassword(password);
+ login();
+ }
+
+ public void register() {
+ waitForUsernameInputPresent();
+ waitAjaxForElement(registerLink);
+ registerLink.click();
+ }
+
+ public void login() {
+ waitAjaxForElement(loginButton);
+ loginButton.click();
+ }
+
+ public void forgotPassword() {
+ waitAjaxForElement(forgottenPassword);
+ forgottenPassword.click();
+ }
+
+// @Override
+// public void cancel() {
+// waitAjaxForElement(cancelButton);
+// cancelButton.click();
+// }
+
+ public void waitForUsernameInputPresent() {
+ accountFields.waitForUsernameInputPresent();
+ }
+
+ public void waitForRegisterLinkNotPresent() {
+ waitAjaxForElementNotPresent(registerLink);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/OIDCLogin.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/OIDCLogin.java
new file mode 100644
index 0000000..d002da8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/OIDCLogin.java
@@ -0,0 +1,13 @@
+package org.keycloak.testsuite.auth.page.login;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class OIDCLogin extends Login {
+
+ public OIDCLogin() {
+ setProtocol(OIDC);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/PageWithLoginUrl.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/PageWithLoginUrl.java
new file mode 100644
index 0000000..53bef17
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/PageWithLoginUrl.java
@@ -0,0 +1,15 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import java.net.URI;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * Used by util class LoginAssert. Implementing classes: AuthRealm, AdminConsole.
+ * @author tkyjovsk
+ */
+public interface PageWithLoginUrl {
+
+ WebDriver getDriver();
+ URI getOIDCLoginUrl();
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java
new file mode 100644
index 0000000..da70da4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/Registration.java
@@ -0,0 +1,77 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.auth.page.login;
+
+import org.keycloak.testsuite.auth.page.account.AccountFields;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElementPresent;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import org.keycloak.testsuite.auth.page.account.ContactInfoFields;
+import org.keycloak.testsuite.auth.page.account.PasswordFields;
+
+/**
+ *
+ * @author Filip Kiss
+ */
+public class Registration extends LoginActions {
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder()
+ .path("registration");
+ }
+
+ @Page
+ private AccountFields accountFields;
+
+ @Page
+ private PasswordFields passwordFields;
+
+ @Page
+ private ContactInfoFields contactInfoFields;
+
+ public void register(UserRepresentation user) {
+ setValues(user);
+ submit();
+ }
+
+ public void setValues(UserRepresentation user) {
+ setValues(user, getPasswordOf(user));
+ }
+
+ public void setValues(UserRepresentation user, String confirmPassword) {
+ accountFields.setValues(user);
+ passwordFields.setPassword(getPasswordOf(user));
+ passwordFields.setConfirmPassword(confirmPassword);
+ }
+
+ public void waitForUsernameInputPresent() {
+ accountFields.waitForUsernameInputPresent();
+ }
+
+ public void waitForUsernameInputNotPresent() {
+ accountFields.waitForUsernameInputNotPresent();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdateAccount.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdateAccount.java
new file mode 100644
index 0000000..b1e5c25
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdateAccount.java
@@ -0,0 +1,27 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import org.keycloak.testsuite.auth.page.account.AccountFields;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UpdateAccount extends Authenticate {
+
+ @Page
+ private AccountFields accountFields;
+
+ public void updateAccount(UserRepresentation user) {
+ updateAccount(user.getEmail(), user.getFirstName(), user.getLastName());
+ }
+
+ public void updateAccount(String email, String firstName, String lastName) {
+ accountFields.setEmail(email);
+ accountFields.setFirstName(firstName);
+ accountFields.setLastName(lastName);
+ submit();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdatePassword.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdatePassword.java
new file mode 100644
index 0000000..b0cc4c3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/UpdatePassword.java
@@ -0,0 +1,21 @@
+package org.keycloak.testsuite.auth.page.login;
+
+import org.keycloak.testsuite.auth.page.account.PasswordFields;
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UpdatePassword extends Authenticate {
+
+ @Page
+ private PasswordFields passwordFields;
+
+ public void updatePasswords(String newPassword, String confirmPassword) {
+ passwordFields.setNewPassword(newPassword);
+ passwordFields.setConfirmPassword(confirmPassword);
+ submit();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java
new file mode 100644
index 0000000..575ce7b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java
@@ -0,0 +1,9 @@
+package org.keycloak.testsuite.auth.page.login;
+
+/**
+ *
+ * @author vramik
+ */
+public class VerifyEmail extends Authenticate {
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsole.java
new file mode 100644
index 0000000..47bff5d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsole.java
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page;
+
+import java.net.URI;
+import org.keycloak.testsuite.auth.page.AuthServer;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
+import org.keycloak.testsuite.console.page.fragment.Menu;
+import org.keycloak.testsuite.console.page.fragment.ModalDialog;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ */
+public class AdminConsole extends AuthServer implements PageWithLoginUrl {
+
+ public static final String ADMIN_REALM = "adminRealm";
+
+ public AdminConsole() {
+ setUriParameter(ADMIN_REALM, MASTER);
+ }
+
+ public AdminConsole setAdminRealm(String adminRealm) {
+ setUriParameter(ADMIN_REALM, adminRealm);
+ return this;
+ }
+
+ public String getAdminRealm() {
+ return getUriParameter(ADMIN_REALM).toString();
+ }
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder().path("admin/{" + ADMIN_REALM + "}/console");
+ }
+
+ @Page
+ private Menu menu;
+
+ @FindBy(xpath = "//div[@class='modal-dialog']")
+ protected ModalDialog modalDialog;
+
+ /**
+ *
+ * @return OIDC Login URL for adminRealm parameter
+ */
+ @Override
+ public URI getOIDCLoginUrl() {
+ return OIDCLoginProtocolService.authUrl(UriBuilder.fromPath(getAuthRoot()))
+ .build(getAdminRealm());
+ }
+
+ @FindBy(css = ".btn-danger")
+ protected WebElement dangerButton;
+
+ //@FindByJQuery(".btn-primary:visible")
+ @FindBy(css = ".btn-primary")
+ protected WebElement primaryButton;
+
+ @FindBy(css = "navbar-brand")
+ protected WebElement brandLink;
+
+ public void logOut() {
+ menu.logOut();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleCreate.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleCreate.java
new file mode 100644
index 0000000..35be14d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleCreate.java
@@ -0,0 +1,47 @@
+package org.keycloak.testsuite.console.page;
+
+import javax.ws.rs.core.UriBuilder;
+import static org.keycloak.testsuite.console.page.AdminConsoleRealm.CONSOLE_REALM;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminConsoleCreate extends AdminConsole {
+
+ public static final String ENTITY = "entity";
+
+ public AdminConsoleCreate() {
+ setUriParameter(CONSOLE_REALM, TEST);
+ }
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder().path("/");
+ }
+
+ @Override
+ public String getUriFragment() {
+ return "/create/{" + ENTITY + "}/{" + CONSOLE_REALM + "}";
+ }
+
+ public AdminConsoleCreate setEntity(String entity) {
+ setUriParameter(ENTITY, entity);
+ return this;
+ }
+
+ public String getEntity() {
+ return getUriParameter(ENTITY).toString();
+ }
+
+ public AdminConsoleCreate setConsoleRealm(String consoleRealm) {
+ setUriParameter(CONSOLE_REALM, consoleRealm);
+ return this;
+ }
+
+ public String getConsoleRealm() {
+ return getUriParameter(CONSOLE_REALM).toString();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java
new file mode 100644
index 0000000..4fd57ba
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java
@@ -0,0 +1,121 @@
+package org.keycloak.testsuite.console.page;
+
+import org.keycloak.admin.client.resource.RealmResource;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+import org.keycloak.testsuite.util.WaitUtils;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
+
+ public static final String CONSOLE_REALM = "consoleRealm";
+
+ public AdminConsoleRealm() {
+ setUriParameter(CONSOLE_REALM, TEST);
+ }
+
+ public AdminConsoleRealm setConsoleRealm(String realm) {
+ setUriParameter(CONSOLE_REALM, realm);
+ return this;
+ }
+
+ public String getConsoleRealm() {
+ return getUriParameter(CONSOLE_REALM).toString();
+ }
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/{" + CONSOLE_REALM + "}";
+ }
+
+ @FindBy(xpath = "//div[./h2[text()='Configure']]")
+ private ConfigureMenu configureMenu;
+
+ public ConfigureMenu configure() {
+ waitGuiForElement(By.xpath("//div[./h2[text()='Configure']]"));
+ return configureMenu;
+ }
+
+ public RealmResource realmResource() {
+ return realmsResource().realm(getConsoleRealm());
+ }
+
+ public class ConfigureMenu {
+
+ @FindBy(partialLinkText = "Realm Settings")
+ private WebElement realmSettingsLink;
+ @FindBy(partialLinkText = "Clients")
+ private WebElement clientsLink;
+ @FindBy(partialLinkText = "Roles")
+ private WebElement rolesLink;
+ @FindBy(partialLinkText = "Identity Providers")
+ private WebElement identityProvidersLink;
+ @FindBy(partialLinkText = "User Feferation")
+ private WebElement userFederationLink;
+ @FindBy(partialLinkText = "Authentication")
+ private WebElement authenticationLink;
+
+ public void realmSettings() {
+ realmSettingsLink.click();
+ }
+
+ public void clients() {
+ clientsLink.click();
+ }
+
+ public void roles() {
+ rolesLink.click();
+ }
+
+ public void identityProviders() {
+ identityProvidersLink.click();
+ }
+
+ public void userFederation() {
+ userFederationLink.click();
+ }
+
+ public void authentication() {
+ authenticationLink.click();
+ }
+
+ }
+
+ @FindBy(xpath = "//div[./h2[text()='Manage']]")
+ protected ManageMenu manageMenu;
+
+ public ManageMenu manage() {
+ WaitUtils.waitGuiForElement(By.xpath("//div[./h2[text()='Manage']]"));
+ return manageMenu;
+ }
+
+ public class ManageMenu {
+
+ @FindBy(partialLinkText = "Users")
+ private WebElement usersLink;
+ @FindBy(partialLinkText = "Sessions")
+ private WebElement sessionsLink;
+ @FindBy(partialLinkText = "Events")
+ private WebElement eventsLink;
+
+ public void users() {
+ usersLink.click();
+ }
+
+ public void sessions() {
+ sessionsLink.click();
+ }
+
+ public void events() {
+ eventsLink.click();
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java
new file mode 100644
index 0000000..bb001ea
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java
@@ -0,0 +1,49 @@
+package org.keycloak.testsuite.console.page;
+
+import java.util.List;
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.admin.client.resource.RealmsResource;
+import org.keycloak.testsuite.console.page.fragment.RealmSelector;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AdminConsoleRealmsRoot extends AdminConsole {
+
+ @FindBy(xpath = "//tr[@data-ng-repeat='r in realms']//a[contains(@class,'ng-binding')]")
+ private List<WebElement> realmLinks;
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ return super.createUriBuilder().path("/");
+ }
+
+ @Override
+ public String getUriFragment() {
+ return "/realms";
+ }
+
+ public void clickRealm(String realm) {
+ boolean linkFound = false;
+ for (WebElement realmLink : realmLinks) {
+ if (realmLink.getText().equals(realm)) {
+ linkFound = true;
+ realmLink.click();
+ }
+ }
+ if (!linkFound) {
+ throw new IllegalStateException("A link for realm '" + realm + "' not found on the Realms page.");
+ }
+ }
+
+ @FindBy(css = "realm-selector")
+ protected RealmSelector realmSelector;
+
+ public RealmsResource realmsResource() {
+ return keycloak.realms();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Authentication.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Authentication.java
new file mode 100644
index 0000000..5cd74bf
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Authentication.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class Authentication extends AdminConsoleRealm {
+
+ @FindBy(xpath = "//h1[text()='Authentication']/..")
+ private AuthenticationTabs authenticationTabs;
+
+ public AuthenticationTabs tabs() {
+ return authenticationTabs;
+ }
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/authentication";
+ }
+
+ public class AuthenticationTabs {
+ @FindBy(linkText = "Flows")
+ private WebElement flowsTab;
+ @FindBy(linkText = "Required Actions")
+ private WebElement requiredActionsTab;
+ @FindBy(linkText = "Password Policy")
+ private WebElement passwordPolicyTab;
+ @FindBy(linkText = "Bindings")
+ private WebElement binding;
+ @FindBy(linkText = "OTP Policy")
+ private WebElement otpPolicy;
+
+ public void flows() {
+ flowsTab.click();
+ }
+
+ public void requiredActions() {
+ requiredActionsTab.click();
+ }
+
+ public void passwordPolicy() {
+ passwordPolicyTab.click();
+ }
+
+ public void binding() {
+ binding.click();
+ }
+
+ public void otpPolicy() {
+ otpPolicy.click();
+ }
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Bindings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Bindings.java
new file mode 100644
index 0000000..6e8d4a4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Bindings.java
@@ -0,0 +1,147 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * Created by mhajas on 8/21/15.
+ */
+public class Bindings extends Authentication{
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/flow-binding";
+ }
+
+ @FindBy(id = "browser")
+ private Select BrowserFlowSelect;
+
+ public void changeBrowserFlowSelect(BrowserFlowSelectValues value) {
+ BrowserFlowSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(id = "registration")
+ private Select RegistrationFlowSelect;
+
+ public void changeRegistrationFlowSelect(RegistrationFlowSelectValues value) {
+ RegistrationFlowSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(id = "grant")
+ private Select DirectGrantFlowSelect;
+
+ public void changeDirectGrantFlowSelect(DirectGrantFlowSelectValues value) {
+ DirectGrantFlowSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(id = "resetCredentials")
+ private Select ResetCredentialsSelect;
+
+ public void changeResetCredentialsSelect(ResetCredentialsSelectValues value) {
+ ResetCredentialsSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(id = "clientAuthentication")
+ private Select ClientAuthenticationSelect;
+
+ public void changeClientAuthenticationSelect(ClientAuthenticationSelectValues value) {
+ ClientAuthenticationSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(xpath = "//button[text()='Save']")
+ private WebElement saveButton;
+
+ public void clickSave() {
+ saveButton.click();
+ }
+
+ @FindBy(xpath = "//button[text()='Cancel']")
+ private WebElement cancelButton;
+
+ public void clickCancel() {
+ cancelButton.click();
+ }
+
+ public enum BrowserFlowSelectValues {
+
+ DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+ RESET_CREDENTIALS("reset credentials");
+
+ private String name;
+
+ private BrowserFlowSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public enum RegistrationFlowSelectValues {
+
+ DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+ RESET_CREDENTIALS("reset credentials");
+
+ private String name;
+
+ private RegistrationFlowSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public enum DirectGrantFlowSelectValues {
+
+ DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+ RESET_CREDENTIALS("reset credentials");
+
+ private String name;
+
+ private DirectGrantFlowSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public enum ResetCredentialsSelectValues {
+
+ DIRECT_GRANT("direct grant"), REGISTRATION("registration"), BROWSER("browser"),
+ RESET_CREDENTIALS("reset credentials"), NOTHING("");
+
+ private String name;
+
+ private ResetCredentialsSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public enum ClientAuthenticationSelectValues {
+
+ CLIENTS("clients");
+
+ private String name;
+
+ private ClientAuthenticationSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Flows.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Flows.java
new file mode 100644
index 0000000..1994064
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/Flows.java
@@ -0,0 +1,212 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class Flows extends Authentication {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/flows";
+ }
+
+ @FindBy(tagName = "select")
+ private Select flowSelect;
+
+ public void changeFlowSelect(FlowSelectValues value) {
+ flowSelect.selectByVisibleText(value.getName());
+ }
+
+ public enum FlowSelectValues {
+
+ DIRECT_GRANT("Direct grant"), REGISTRATION("Registration"), BROWSER("Browser"),
+ RESET_CREDENTIALS("Reset credentials"), CLIENTS("Clients");
+
+ private String name;
+
+ private FlowSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ @FindBy(linkText = "New")
+ private WebElement newButton;
+
+ @FindBy(linkText = "Copy")
+ private WebElement copyButton;
+
+ public void clickNew() {
+ newButton.click();
+ }
+
+ public void clickCopy() {
+ copyButton.click();
+ }
+
+ // Direct grant
+ public void setPasswordRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password')]]/../td[2]//input[@type='radio']")).click();
+ }
+
+ public void setPasswordDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setOTPRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'O T P')]]/../td[2]//input[@type='radio']")).click();
+ }
+
+ public void setOTPOptional() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'O T P')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setOTPDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'O T P')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ // Registration
+ public void setRegistrationFormRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration form')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setRegistrationFormDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration form')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setRegistrationUserCreationRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration User Creation')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setRegistrationUserCreationDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Registration User Creation')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setProfileValidationRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Profile Validation')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setProfileValidationDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Profile Validation')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setPasswordValidationRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password Validation')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setPasswordValidationDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Password Validation')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setRecaptchaRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Recaptcha')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setRecaptchaDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Recaptcha')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ // Browser
+ public void setCookieAlternative() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Cookie')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setCookieDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Cookie')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setKerberosAlternative() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Kerberos')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setKerberosRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Kerberos')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setKerberosDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Kerberos')]]/../td[5]//input[@type='radio']")).click();
+ }
+
+ public void setFormsAlternative() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Forms')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setFormsRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Forms')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setFormsDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Forms')]]/../td[5]//input[@type='radio']")).click();
+ }
+
+ public void setOTPFormRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' O T P Form')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setOTPFormOptional() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' O T P Form')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setOTPFormDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' O T P Form')]]/../td[5]//input[@type='radio']")).click();
+ }
+
+ // Reset credentials
+ public void setResetPasswordRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset Password')]]/../td[2]//input[@type='radio']")).click();
+ }
+
+ public void setResetPasswordOptional() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset Password')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setResetPasswordDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset Password')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setResetOTPRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset O T P')]]/../td[2]//input[@type='radio']")).click();
+ }
+
+ public void setResetOTPOptional() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset O T P')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setResetOTPDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Reset O T P')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ // Clients
+ public void setClientIdAndSecretRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Client Id and Secret')]]/../td[2]//input[@type='radio']")).click();
+ }
+
+ public void setClientIdAndSecretAlternative() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Client Id and Secret')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setClientIdAndSecretDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,'Client Id and Secret')]]/../td[4]//input[@type='radio']")).click();
+ }
+
+ public void setSignedJwtRequired() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' Signed Jwt')]]/../td[2]//input[@type='radio']")).click();
+ }
+
+ public void setSignedJwtAlternative() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' Signed Jwt')]]/../td[3]//input[@type='radio']")).click();
+ }
+
+ public void setSignedJwtDisabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()[contains(.,' Signed Jwt')]]/../td[4]//input[@type='radio']")).click();
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/OTPPolicy.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/OTPPolicy.java
new file mode 100644
index 0000000..34e8a09
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/OTPPolicy.java
@@ -0,0 +1,85 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * Created by mhajas on 8/21/15.
+ */
+public class OTPPolicy extends Authentication {
+
+ @FindBy(linkText = "Save")
+ private WebElement saveButton;
+
+ public void clickSave() {
+ saveButton.click();
+ }
+
+ @FindBy(linkText = "Cancel")
+ private WebElement cancelButton;
+
+ public void clickCancel() {
+ cancelButton.click();
+ }
+
+ @FindBy(id = "lookAhead")
+ private WebElement lookAheadInput;
+
+ public void setLookAheadInputValue(String value) {
+ Form.setInputValue(lookAheadInput, value);
+ }
+
+ @FindBy(id = "counter")
+ private WebElement initialCounterInput;
+
+ public void setInitialcounterInputValue(String value) {
+ Form.setInputValue(initialCounterInput, value);
+ }
+
+ public enum OTPTypeSelectValues {
+
+ TIME_BASED("time Based"), COUNTER_BASED("Counter Based");
+
+ private String name;
+
+ private OTPTypeSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public enum OTPHashAlgorithmSelectValues {
+
+ SHA1("SHA1"), SHA256("SHA256"), SHA512("SHA512");
+
+ private String name;
+
+ private OTPHashAlgorithmSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public enum NumberOfDigitsSelectValues {
+
+ NUMBER6("6"), NUMBER8("8");
+
+ private String name;
+
+ private NumberOfDigitsSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java
new file mode 100644
index 0000000..b2b08b5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java
@@ -0,0 +1,100 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import java.util.List;
+
+import org.jboss.arquillian.graphene.findby.ByJQuery;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author Petr Mensik
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class PasswordPolicy extends Authentication {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/password-policy";
+ }
+
+ @FindBy(tagName = "select")
+ private Select addPolicySelect;
+
+ @FindBy(tagName = "select")
+ private WebElement addPolicySelectElement;
+
+ @FindBy(css = "tr.ng-scope")
+ private List<WebElement> allRows;
+
+ public void addPolicy(PasswordPolicy.Type policy, String value) {
+ waitGuiForElement(addPolicySelectElement);
+ addPolicySelect.selectByVisibleText(policy.getName());
+ setPolicyValue(policy, value);
+ primaryButton.click();
+ }
+
+
+ public void addPolicy(PasswordPolicy.Type policy, int value) {
+ addPolicy(policy, String.valueOf(value));
+ }
+
+ public void addPolicy(PasswordPolicy.Type policy) {
+ addPolicySelect.selectByVisibleText(policy.getName());
+ primaryButton.click();
+ }
+
+ public void removePolicy(PasswordPolicy.Type policy) {
+ int policyInputLocation = findPolicy(policy);
+ allRows.get(policyInputLocation).findElements(By.tagName("button")).get(0).click();
+ primaryButton.click();
+ }
+
+ public void editPolicy(PasswordPolicy.Type policy, int value) {
+ editPolicy(policy, String.valueOf(value));
+ }
+
+ public void editPolicy(PasswordPolicy.Type policy, String value) {
+ setPolicyValue(policy, value);
+ primaryButton.click();
+ }
+
+ private void setPolicyValue(PasswordPolicy.Type policy, String value) {
+ int policyInputLocation = findPolicy(policy);
+ WebElement input = allRows.get(policyInputLocation).findElement(By.tagName("input"));
+ input.clear();
+ input.sendKeys(value);
+ }
+
+ private int findPolicy(PasswordPolicy.Type policy) {
+ for (int i = 0; i < allRows.size(); i++) {
+ String policyName = allRows.get(i).findElement(ByJQuery.selector("td:eq(0)")).getText();
+ if (policyName.equals(policy.getName())) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ public enum Type {
+
+ HASH_ITERATIONS("Hash Iterations"), LENGTH("Length"), DIGITS("Digits"), LOWER_CASE("Lower Case"),
+ UPPER_CASE("Upper Case"), SPECIAL_CHARS("Special Chars"), NOT_USERNAME("Not Username"),
+ REGEX_PATTERN("Regex Pattern"), PASSWORD_HISTORY("Password History"),
+ FORCE_EXPIRED_PASSWORD_CHANGE("Force Expired Password Change");
+
+ private String name;
+
+ private Type(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/RequiredActions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/RequiredActions.java
new file mode 100644
index 0000000..5da1cda
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/authentication/RequiredActions.java
@@ -0,0 +1,55 @@
+package org.keycloak.testsuite.console.page.authentication;
+
+import org.openqa.selenium.By;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class RequiredActions extends Authentication {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/required-actions";
+ }
+
+ public void clickTermsAndConditionEnabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Terms and Conditions']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+ }
+
+ public void clickTermsAndConditionDefaultAction() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Terms and Conditions']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+ }
+
+ public void clickVerifyEmailEnabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Verify Email']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+ }
+
+ public void clickVerifyEmailDefaultAction() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Verify Email']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+ }
+
+ public void clickUpdatePasswordEnabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Password']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+ }
+
+ public void clickUpdatePasswordDefaultAction() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Password']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+ }
+
+ public void clickConfigureTotpEnabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Configure Totp']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+ }
+
+ public void clickConfigureTotpDefaultAction() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Configure Totp']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+ }
+
+ public void clickUpdateProfileEnabled() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Profile']/..//input[@type='checkbox' and @ng-model='requiredAction.enabled']")).click();
+ }
+
+ public void clickUpdateProfileDefaultAction() {
+ driver.findElement(By.xpath("//td[@class='ng-binding' and text()='Update Profile']/..//input[@type='checkbox' and @ng-model='requiredAction.defaultAction']")).click();
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java
new file mode 100644
index 0000000..783cd0b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java
@@ -0,0 +1,107 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.testsuite.console.page.fragment.Breadcrumb;
+import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Client extends Clients {
+
+ public static final String ID = "id"; // TODO client.id vs client.clientId
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/{" + ID + "}";
+ }
+
+ public final void setId(String id) {
+ setUriParameter(ID, id);
+ }
+
+ public String getId() {
+ return getUriParameter(ID).toString();
+ }
+
+ @FindBy(xpath = BREADCRUMB_XPATH)
+ private Breadcrumb breadcrumb;
+
+ public Breadcrumb breadcrumb() {
+ return breadcrumb;
+ }
+
+ public void backToClientsViaBreadcrumb() {
+ breadcrumb.clickItemOneLevelUp();
+ }
+
+ @FindBy(id = "removeClient")
+ private WebElement deleteIcon;
+
+ public void delete() {
+ deleteIcon.click();
+ modalDialog.confirmDeletion();
+ }
+
+ @FindBy(xpath = "//div[@data-ng-controller='ClientTabCtrl']/ul")
+ protected ClientTabs clientTabs;
+
+ public ClientTabs tabs() {
+ return clientTabs;
+ }
+
+ public class ClientTabs {
+
+ @FindBy(linkText = "Settings")
+ private WebElement settingsLink;
+ @FindBy(linkText = "Roles")
+ private WebElement rolesLink;
+ @FindBy(linkText = "Mappers")
+ private WebElement mappersLink;
+ @FindBy(linkText = "Scope")
+ private WebElement scopeLink;
+ @FindBy(linkText = "Revocation")
+ private WebElement revocationLink;
+ @FindBy(linkText = "Sessions")
+ private WebElement sessionsLink;
+ @FindBy(linkText = "Installation")
+ private WebElement installationLink;
+
+ public void settings() {
+ settingsLink.click();
+ }
+
+ public void roles() {
+ rolesLink.click();
+ }
+
+ public void mappers() {
+ mappersLink.click();
+ }
+
+ public void scope() {
+ scopeLink.click();
+ }
+
+ public void revocation() {
+ revocationLink.click();
+ }
+
+ public void sessions() {
+ sessionsLink.click();
+ }
+
+ public void installation() {
+ installationLink.click();
+ }
+
+ }
+
+ public ClientResource clientResource() {
+ return clientsResource().get(getId());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientClustering.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientClustering.java
new file mode 100644
index 0000000..cdc8d6b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientClustering.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientClustering extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/clustering";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientCredentials.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientCredentials.java
new file mode 100644
index 0000000..08a3523
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientCredentials.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientCredentials extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/credentials";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientInstallation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientInstallation.java
new file mode 100644
index 0000000..65c1c6c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientInstallation.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientInstallation extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/installation";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientMappers.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientMappers.java
new file mode 100644
index 0000000..d56dca5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientMappers.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientMappers extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/mappers";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRevocation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRevocation.java
new file mode 100644
index 0000000..fb161a8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRevocation.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRevocation extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/revocation";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java
new file mode 100644
index 0000000..d0a0b0d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRole.java
@@ -0,0 +1,36 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.keycloak.testsuite.console.page.roles.*;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRole extends ClientRoles {
+
+ public static final String ROLE_ID = "roleId";
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/{" + ROLE_ID + "}";
+ }
+
+ public void setRoleId(String id) {
+ setUriParameter(ROLE_ID, id);
+ }
+
+ public String getRoleId() {
+ return getUriParameter(ROLE_ID).toString();
+ }
+
+ private RoleForm form;
+
+ public RoleForm form() {
+ return form;
+ }
+
+ public void backToClientRolesViaBreadcrumb() {
+ breadcrumb().clickItemOneLevelUp();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRoles.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRoles.java
new file mode 100644
index 0000000..a8ee969
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientRoles.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.keycloak.admin.client.resource.RolesResource;
+import org.keycloak.testsuite.console.page.roles.RolesTable;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientRoles extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/roles";
+ }
+
+ @FindBy(css = "table[class*='table']")
+ private RolesTable table;
+
+ public RolesTable roles() {
+ return table;
+ }
+
+ public RolesResource rolesResource() {
+ return clientResource().roles();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
new file mode 100644
index 0000000..6f9cccd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
@@ -0,0 +1,138 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page.clients;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+
+import static org.openqa.selenium.By.linkText;
+import static org.openqa.selenium.By.tagName;
+
+/**
+ *
+ * @author Filip Kisss
+ */
+public class Clients extends AdminConsoleRealm {
+
+ public static final String CREATE = "Create";
+ public static final String IMPORT = "Import";
+
+ public static final String EDIT = "Edit";
+ public static final String DELETE = "Delete";
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/clients";
+ }
+
+ @FindBy(tagName = "table")
+ private ClientsTable clientsTable;
+
+ public ClientsTable table() {
+ return clientsTable;
+ }
+
+ public class ClientsTable extends DataTable {
+
+ public List<ClientRepresentation> searchClients(String searchPattern) {
+ search(searchPattern);
+ return getClientsFromRows();
+ }
+
+ public void createClient() {
+ waitAjaxForBody();
+ clickHeaderLink(CREATE);
+ }
+
+ public void importClient() {
+ waitAjaxForBody();
+ clickHeaderLink(IMPORT);
+ }
+
+ public void clickClient(ClientRepresentation client) {
+ waitAjaxForBody();
+ clickClient(client.getClientId());
+ }
+
+ public void clickClient(String clientId) {
+ waitAjaxForBody();
+ body().findElement(linkText(clientId)).click();
+ }
+
+ public void editClient(String clientId) {
+ waitAjaxForBody();
+ clickRowActionButton(getRowByLinkText(clientId), EDIT);
+ }
+
+ public void deleteClient(String clientId) {
+ waitAjaxForBody();
+ clickRowActionButton(getRowByLinkText(clientId), DELETE);
+ }
+
+ public ClientRepresentation findClient(String clientId) {
+ List<ClientRepresentation> clients = searchClients(clientId);
+ if (clients.isEmpty()) {
+ return null;
+ } else {
+ assert 1 == clients.size();
+ return clients.get(0);
+ }
+ }
+
+ public List<ClientRepresentation> getClientsFromRows() {
+ List<ClientRepresentation> rows = new ArrayList<>();
+ for (WebElement row : rows()) {
+ ClientRepresentation client = getClientFromRow(row);
+ if (client != null) {
+ rows.add(client);
+ }
+ }
+ return rows;
+ }
+
+ public ClientRepresentation getClientFromRow(WebElement row) {
+ ClientRepresentation client = null;
+ if (row.isDisplayed()) {
+ client = new ClientRepresentation();
+ List<WebElement> tds = row.findElements(tagName("td"));
+ client.setClientId(tds.get(0).getText());
+ List<String> redirectUris = new ArrayList<>();
+ redirectUris.add(tds.get(2).getText()); // FIXME there can be more than 1 redirect uri
+ client.setRedirectUris(redirectUris);
+ }
+ return client;
+ }
+ }
+
+ public void deleteClient(String clientId) {
+ clientsTable.searchClients(clientId);
+ clientsTable.deleteClient(clientId);
+ }
+
+ public ClientsResource clientsResource() {
+ return realmResource().clients();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientScopeMappings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientScopeMappings.java
new file mode 100644
index 0000000..32107fd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientScopeMappings.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientScopeMappings extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/scope-mappings";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSessions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSessions.java
new file mode 100644
index 0000000..eae5013
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSessions.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.clients;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientSessions extends Client {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/sessions";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettings.java
new file mode 100644
index 0000000..8fe1c2c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettings.java
@@ -0,0 +1,18 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientSettings extends Client {
+
+ @Page
+ private ClientSettingsForm form;
+
+ public ClientSettingsForm form() {
+ return form;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettingsForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettingsForm.java
new file mode 100644
index 0000000..41cdf71
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/ClientSettingsForm.java
@@ -0,0 +1,91 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.auth.page.login.Login.OIDC;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ClientSettingsForm extends CreateClientForm {
+
+ @FindBy(id = "baseUrl")
+ private WebElement baseUrlInput;
+ @FindBy(id = "adminUrl")
+ private WebElement adminUrlInput;
+
+ @FindBy(id = "newWebOrigin")
+ private WebElement newWebOriginInput;
+ @FindBy(xpath = ".//input[ng-model='client.webOrigins[i]']")
+ private List<WebElement> webOriginInputs;
+ @FindBy(xpath = ".//i[contains(@data-ng-click, 'deleteWebOrigin')]")
+ private List<WebElement> deleteWebOriginIcons;
+
+ public void setBaseUrl(String baseUrl) {
+ setInputValue(baseUrlInput, baseUrl);
+ }
+
+ public String getBaseUrl() {
+ return getInputValue(baseUrlInput);
+ }
+
+ public void setAdminUrl(String adminUrl) {
+ setInputValue(adminUrlInput, adminUrl);
+ }
+
+ public String getAdminUrl() {
+ return getInputValue(adminUrlInput);
+ }
+
+ public void addWebOrigin(String redirectUri) {
+ newWebOriginInput.sendKeys(redirectUri);
+ }
+
+ public List<String> getWebOrigins() {
+ List<String> values = new ArrayList<>();
+ for (WebElement input : webOriginInputs) {
+ values.add(getInputValue(input));
+ }
+ return values;
+ }
+
+ public void setWebOrigins(List<String> webOrigins) {
+ while (!deleteWebOriginIcons.isEmpty()) {
+ deleteWebOriginIcons.get(0).click();
+ pause(100);
+ }
+ if (webOrigins != null) {
+ for (String redirectUri : webOrigins) {
+ addWebOrigin(redirectUri);
+ pause(100);
+ }
+ }
+ }
+
+ @Override
+ public void setValues(ClientRepresentation client) {
+ super.setValues(client);
+ setBaseUrl(client.getBaseUrl());
+ if (OIDC.equals(client.getProtocol())) {
+ setAdminUrl(client.getAdminUrl());
+ setWebOrigins(client.getWebOrigins());
+ }
+ }
+
+ @Override
+ public ClientRepresentation getValues() {
+ ClientRepresentation values = super.getValues();
+ values.setBaseUrl(getBaseUrl());
+ if (OIDC.equals(values.getProtocol())) {
+ values.setAdminUrl(getAdminUrl());
+ values.setWebOrigins(getWebOrigins());
+ }
+ return values;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClient.java
new file mode 100644
index 0000000..87568c9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClient.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateClient extends AdminConsoleCreate {
+
+ public CreateClient() {
+ setEntity("client");
+ }
+
+ @Page
+ private CreateClientForm form;
+
+ public CreateClientForm form() {
+ return form;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
new file mode 100644
index 0000000..87eadb5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
@@ -0,0 +1,230 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.page.Form.getInputValue;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.keycloak.testsuite.util.Timer;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateClientForm extends Form {
+
+ @FindBy(id = "clientId")
+ private WebElement clientIdInput;
+
+ @FindBy(id = "name")
+ private WebElement nameInput;
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='enabled']]")
+ private OnOffSwitch enabledSwitch;
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='consentRequired']]")
+ private OnOffSwitch consentRequiredSwitch;
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='directGrantsOnly']]")
+ private OnOffSwitch directGrantsOnlySwitch;
+
+ @FindBy(id = "protocol")
+ private Select protocolSelect;
+ @FindBy(id = "protocol")
+ private WebElement protocolSelectElement;
+
+ @FindBy
+ private SAMLClientSettingsForm samlForm;
+
+ public SAMLClientSettingsForm samlForm() {
+ return samlForm;
+ }
+
+ @FindBy(id = "accessType")
+ private Select accessTypeSelect;
+ @FindBy(id = "accessType")
+ private WebElement accessTypeSelectElement;
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='serviceAccountsEnabled']]")
+ private OnOffSwitch serviceAccountsEnabledSwitch;
+
+ @FindBy(id = "newRedirectUri")
+ private WebElement newRedirectUriInput;
+ @FindBy(xpath = ".//input[@ng-model='client.redirectUris[i]']")
+ private List<WebElement> redirectUriInputs;
+ @FindBy(xpath = ".//i[contains(@data-ng-click, 'deleteRedirectUri')]")
+ private List<WebElement> deleteRedirectUriIcons;
+
+ public void setValues(ClientRepresentation client) {
+ waitAjaxForElement(clientIdInput);
+
+ setClientId(client.getClientId());
+ setName(client.getName());
+ setEnabled(client.isEnabled());
+ setConsentRequired(client.isConsentRequired());
+ setDirectGrantsOnly(client.isDirectGrantsOnly());
+ setProtocol(client.getProtocol());
+ if (OIDC.equals(client.getProtocol())) {
+ setAccessType(client);
+ if (!client.isBearerOnly()) {
+ if (!client.isPublicClient()) {
+ setServiceAccountsEnabled(client.isServiceAccountsEnabled());
+ }
+ setRedirectUris(client.getRedirectUris());
+ }
+ }
+ }
+
+ public ClientRepresentation getValues() {
+ ClientRepresentation values = new ClientRepresentation();
+ values.setClientId(getClientId());
+ values.setName(getName());
+ values.setEnabled(isEnabled());
+ values.setConsentRequired(isConsentRequired());
+ values.setDirectGrantsOnly(isDirectGrantsOnly());
+ values.setProtocol(getProtocol());
+ if (OIDC.equals(values.getProtocol())) {
+ values.setBearerOnly(isBearerOnly());
+ if (!values.isBearerOnly()) {
+ values.setPublicClient(isPublicClient());
+ if (!values.isPublicClient()) {
+ values.setServiceAccountsEnabled(isServiceAccountsEnabled());
+ }
+ values.setRedirectUris(getRedirectUris());
+ }
+ }
+ return values;
+ }
+
+ public String getClientId() {
+ return getInputValue(clientIdInput);
+ }
+
+ public void setClientId(String clientId) {
+ setInputValue(clientIdInput, clientId);
+ }
+
+ public String getName() {
+ return getInputValue(nameInput);
+ }
+
+ public void setName(String name) {
+ setInputValue(nameInput, name);
+ }
+
+ public boolean isEnabled() {
+ return enabledSwitch.isOn();
+ }
+
+ public void setEnabled(boolean enabled) {
+ enabledSwitch.setOn(enabled);
+ }
+
+ public static final String BEARER_ONLY = "bearer-only";
+ public static final String PUBLIC = "public";
+ public static final String CONFIDENTIAL = "confidential";
+
+ public boolean isBearerOnly() {
+ return BEARER_ONLY.equals(
+ accessTypeSelect.getFirstSelectedOption().getAttribute(VALUE));
+ }
+
+ public boolean isPublicClient() {
+ return PUBLIC.equals(
+ accessTypeSelect.getFirstSelectedOption().getAttribute(VALUE));
+ }
+
+ public void setBearerOnly(boolean bearerOnly) {
+ accessTypeSelectElement.sendKeys(BEARER_ONLY);
+// accessTypeSelect.selectByVisibleText(BEARER_ONLY);
+ }
+
+ public void setPublicClient(boolean publicClient) {
+ accessTypeSelectElement.sendKeys(PUBLIC);
+// accessTypeSelect.selectByVisibleText(PUBLIC);
+ }
+
+ public void setAccessType(ClientRepresentation client) { // TODO verify
+ setBearerOnly(client.isBearerOnly());
+ setPublicClient(client.isPublicClient());
+ if (!client.isBearerOnly() && !client.isPublicClient()) {
+ accessTypeSelect.selectByVisibleText(CONFIDENTIAL);
+ }
+ }
+
+ public void addRedirectUri(String redirectUri) {
+ newRedirectUriInput.sendKeys(redirectUri);
+ }
+
+ public List<String> getRedirectUris() {
+ List<String> values = new ArrayList<>();
+ for (WebElement input : redirectUriInputs) {
+ values.add(getInputValue(input));
+ }
+ return values;
+ }
+
+ public void setRedirectUris(List<String> redirectUris) {
+ Timer.time();
+ while (!deleteRedirectUriIcons.isEmpty()) {
+ deleteRedirectUriIcons.get(0).click();
+ pause(100);
+ }
+ Timer.time("deleteRedirectUris");
+ if (redirectUris != null) {
+ for (String redirectUri : redirectUris) {
+ addRedirectUri(redirectUri);
+ pause(100);
+ }
+ }
+ Timer.time("addRedirectUris");
+ }
+
+ public boolean isConsentRequired() {
+ return consentRequiredSwitch.isOn();
+ }
+
+ public void setConsentRequired(boolean consentRequired) {
+ consentRequiredSwitch.setOn(consentRequired);
+ }
+
+ public boolean isDirectGrantsOnly() {
+ return directGrantsOnlySwitch.isOn();
+ }
+
+ public void setDirectGrantsOnly(boolean directGrantsOnly) {
+ directGrantsOnlySwitch.setOn(directGrantsOnly);
+ }
+
+ public String getProtocol() {
+ waitAjaxForElement(protocolSelect.getFirstSelectedOption());
+ return protocolSelect.getFirstSelectedOption().getText();
+ }
+
+ public void setProtocol(String protocol) {
+ Timer.time();
+ protocolSelectElement.sendKeys(protocol);
+ Timer.time("clientSettings.setProtocol()");
+ }
+
+ public boolean isServiceAccountsEnabled() {
+ return serviceAccountsEnabledSwitch.isOn();
+ }
+
+ public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+ serviceAccountsEnabledSwitch.setOn(serviceAccountsEnabled);
+ }
+
+ public class SAMLClientSettingsForm extends Form {
+
+ // TODO add SAML client attributes
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java
new file mode 100644
index 0000000..8a3317a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientRole.java
@@ -0,0 +1,25 @@
+package org.keycloak.testsuite.console.page.clients;
+
+import static org.keycloak.testsuite.console.page.clients.Client.ID;
+import org.keycloak.testsuite.console.page.roles.CreateRole;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateClientRole extends CreateRole {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/clients/{" + ID + "}";
+ }
+
+ public void setClientId(String id) {
+ setUriParameter(ID, id);
+ }
+
+ public String getClientId() {
+ return getUriParameter(ID).toString();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java
new file mode 100644
index 0000000..08e0e00
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java
@@ -0,0 +1,104 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class AdminEvents extends Events {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/admin-events";
+ }
+
+ @FindBy(tagName = "table")
+ private AdminEventsTable table;
+
+ public AdminEventsTable table() {
+ return table;
+ }
+
+ public class AdminEventsTable extends DataTable {
+
+ public void update() {
+ waitAjaxForBody();
+ clickHeaderButton("Update");
+ }
+
+ public void reset() {
+ waitAjaxForBody();
+ clickHeaderButton("Reset");
+ }
+
+ @FindBy(xpath = "//button[text()[contains(.,'Filter')]]")
+ private WebElement filterButton;
+
+ public void filter() {
+ waitAjaxForBody();
+ filterButton.click();
+ }
+
+ @FindBy(tagName = "form")
+ private AdminEventsTableFilterForm filterForm;
+
+ public AdminEventsTableFilterForm filterForm() {
+ return filterForm;
+ }
+
+ public class AdminEventsTableFilterForm extends Form {
+
+ public void addOperationType(String type) {
+ driver.findElement(By.xpath("//div[@id='s2id_adminEnabledEventOperations']/ul")).click();
+ driver.findElement(By.xpath("//div[@id='select2-drop']//div[text()[contains(.,'" + type + "')]]/..")).click();
+ }
+
+ public void removeOperationType(String type) {
+ driver.findElement(By.xpath("//div[@id='s2id_adminEnabledEventOperations']//div[text()='" + type + "']/../a")).click();
+ }
+
+ @FindBy(id = "resource")
+ private WebElement resourcePathInput;
+
+ public void setResourcePathInput(String value) {
+ setInputValue(resourcePathInput, value);
+ }
+
+ @FindBy(id = "realm")
+ private WebElement realmInput;
+
+ public void setRealmInput(String value) {
+ setInputValue(realmInput, value);
+ }
+
+ @FindBy(id = "client")
+ private WebElement clientInput;
+
+ public void setClientInput(String value) {
+ setInputValue(clientInput, value);
+ }
+
+ @FindBy(id = "user")
+ private WebElement userInput;
+
+ public void setUserInput(String value) {
+ setInputValue(userInput, value);
+ }
+
+ @FindBy(id = "ipAddress")
+ private WebElement ipAddressInput;
+
+ public void setIpAddressInput(String value) {
+ setInputValue(ipAddressInput, value);
+ }
+ }
+
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Config.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Config.java
new file mode 100644
index 0000000..686e902
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Config.java
@@ -0,0 +1,99 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class Config extends Events {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/events-settings";
+ }
+
+ @FindBy(xpath = "//form")
+ private ConfigForm form;
+
+ public ConfigForm form() {
+ return form;
+ }
+
+ public class ConfigForm extends Form {
+ @FindBy(id = "s2id_autogen1")
+ private WebElement eventListenersInput;
+
+ @FindBy(xpath = "//div[@id='s2id_autogen1']/..//select")
+ private Select eventListenersSelect;
+
+ public void addEventListener(String listener) {
+ eventListenersInput.click();
+ eventListenersSelect.selectByVisibleText(listener);
+ }
+
+ public void removeEventListener(String listener) {
+ eventListenersInput.findElement(By.xpath("//div[text()='" + listener + "']/../a")).click();
+ }
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='enabled']]")
+ private OnOffSwitch SaveEvents;
+
+ public void setSaveEvents(boolean value) {
+ SaveEvents.setOn(value);
+ }
+
+ @FindBy(xpath = "//div[@id='s2id_enabledEventTypes']//input")
+ private WebElement savedTypesInput;
+
+ @FindBy(xpath = "//div[@id='select2-drop']/ul")
+ private WebElement savedTypesOptions;
+
+ public void addSaveType(String type) {
+ savedTypesInput.click();
+ savedTypesOptions.findElement(By.xpath("//div[text()='" + type + "']")).click();
+ }
+
+ public void removeSaveType(String type) {
+ savedTypesInput.findElement(By.xpath("//div[text()='" + type + "']/../a")).click();
+ }
+
+ public void clearLoginEvents() {
+ driver.findElement(By.xpath("//button[@data-ng-click='clearEvents()']")).click();
+ }
+
+ @FindBy(id = "expiration")
+ private WebElement expirationInput;
+
+ @FindBy(name = "expirationUnit")
+ private Select expirationUnitSelect;
+
+ public void setExpiration(String value, String unit) {
+ expirationUnitSelect.selectByVisibleText(unit);
+ Form.setInputValue(expirationInput, value);
+ }
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='adminEventsEnabled']]")
+ private OnOffSwitch saveAdminEvents;
+
+ public void setSaveAdminEvents(boolean value) {
+ saveAdminEvents.setOn(value);
+ }
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='adminEventsDetailsEnabled']]")
+ private OnOffSwitch includeRepresentation;
+
+ public void setIncludeRepresentation(boolean value) {
+ includeRepresentation.setOn(value);
+ }
+
+ public void clearAdminEvents() {
+ driver.findElement(By.xpath("//button[@data-ng-click='clearAdminEvents()']")).click();
+ }
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Events.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Events.java
new file mode 100644
index 0000000..53c8345
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/Events.java
@@ -0,0 +1,35 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Events extends AdminConsoleRealm {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment();
+ }
+
+ @FindBy(linkText = "Login Events")
+ private WebElement loginEventsTab;
+ @FindBy(linkText = "Admin Events")
+ private WebElement adminEventsTab;
+ @FindBy(linkText = "Config")
+ private WebElement configTab;
+
+ public void loginEvents() {
+ loginEventsTab.click();
+ }
+ public void adminEvents() {
+ adminEventsTab.click();
+ }
+ public void config() {
+ configTab.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java
new file mode 100644
index 0000000..6752951
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java
@@ -0,0 +1,80 @@
+package org.keycloak.testsuite.console.page.events;
+
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class LoginEvents extends Events {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/events";
+ }
+
+ @FindBy(tagName = "table")
+ private LoginEventsTable table;
+
+ public LoginEventsTable table() {
+ return table;
+ }
+
+ public class LoginEventsTable extends DataTable {
+
+ public void update() {
+ waitAjaxForBody();
+ clickHeaderButton("Update");
+ }
+
+ public void reset() {
+ waitAjaxForBody();
+ clickHeaderButton("Reset");
+ }
+
+ @FindBy(xpath = "//button[text()[contains(.,'Filter')]]")
+ private WebElement filterButton;
+
+ public void filter() {
+ waitAjaxForBody();
+ filterButton.click();
+ }
+
+ @FindBy(tagName = "form")
+ private LoginEventsTableFilterForm filterForm;
+
+ public LoginEventsTableFilterForm filterForm() {
+ return filterForm;
+ }
+
+ public class LoginEventsTableFilterForm extends Form {
+
+ public void addEventType(String type) {
+ driver.findElement(By.xpath("//div[@id='s2id_eventTypes']/ul")).click();
+ driver.findElement(By.xpath("//div[@id='select2-drop']//div[text()='" + type + "']/..")).click();
+ }
+
+ public void removeOperationType(String type) {
+ driver.findElement(By.xpath("//div[@id='s2id_eventTypes']//div[text()='" + type + "']/../a")).click();
+ }
+
+ @FindBy(id = "client")
+ private WebElement clientInput;
+
+ public void setClientInput(String value) {
+ setInputValue(clientInput, value);
+ }
+
+ @FindBy(id = "user")
+ private WebElement userInput;
+
+ public void setUserInput(String value) {
+ setInputValue(userInput, value);
+ }
+ }
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/CreateLdapUserProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/CreateLdapUserProvider.java
new file mode 100644
index 0000000..4dc47f9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/CreateLdapUserProvider.java
@@ -0,0 +1,20 @@
+package org.keycloak.testsuite.console.page.federation;
+
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateLdapUserProvider extends AdminConsoleCreate {
+
+ public CreateLdapUserProvider() {
+ setEntity("user-federation");
+ }
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/providers/ldap";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/LdapUserProviderForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/LdapUserProviderForm.java
new file mode 100644
index 0000000..a9b8882
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/LdapUserProviderForm.java
@@ -0,0 +1,130 @@
+package org.keycloak.testsuite.console.page.federation;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+
+/**
+ * Created by fkiss.
+ */
+public class LdapUserProviderForm extends Form {
+
+ @FindBy(id = "consoleDisplayName")
+ private WebElement consoleDisplayNameInput;
+
+ @FindBy(id = "priority")
+ private WebElement priorityInput;
+
+ @FindBy(id = "usernameLDAPAttribute")
+ private WebElement usernameLDAPAttributeInput;
+
+ @FindBy(id = "userObjectClasses")
+ private WebElement userObjectClassesInput;
+
+ @FindBy(id = "ldapConnectionUrl")
+ private WebElement ldapConnectionUrlInput;
+
+ @FindBy(id = "ldapBaseDn")
+ private WebElement ldapBaseDnInput;
+
+ @FindBy(id = "ldapUsersDn")
+ private WebElement ldapUserDnInput;
+
+ @FindBy(id = "ldapBindDn")
+ private WebElement ldapBindDnInput;
+
+ @FindBy(id = "ldapBindCredential")
+ private WebElement ldapBindCredentialInput;
+
+ @FindBy(id = "kerberosRealm")
+ private WebElement kerberosRealmInput;
+
+ @FindBy(id = "serverPrincipal")
+ private WebElement serverPrincipalInput;
+
+ @FindBy(id = "keyTab")
+ private WebElement keyTabInput;
+
+ @FindBy(id = "batchSizeForSync")
+ private WebElement batchSizeForSyncInput;
+
+ @FindBy(id = "fullSyncPeriod")
+ private WebElement fullSyncPeriodInput;
+
+ @FindBy(id = "changedSyncPeriod")
+ private WebElement changedSyncPeriodInput;
+
+ @FindBy(id = "editMode")
+ private Select editModeSelect;
+
+ @FindBy(id = "vendor")
+ private Select vendorSelect;
+
+ @FindByJQuery("a:contains('Test connection')")
+ private WebElement testConnectionButton;
+
+ @FindByJQuery("a:contains('Test authentication')")
+ private WebElement testAuthenticationButton;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(0)")
+ private OnOffSwitch syncRegistrations;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(1)")
+ private OnOffSwitch connectionPooling;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(2)")
+ private OnOffSwitch pagination;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(3)")
+ private OnOffSwitch allowKerberosAuth;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(4)")
+ private OnOffSwitch debug;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(5)")
+ private OnOffSwitch useKerberosForPwdAuth;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(6)")
+ private OnOffSwitch periodicFullSync;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(7)")
+ private OnOffSwitch periodicChangedUsersSync;
+
+ @FindByJQuery("button:contains('Save')")
+ private WebElement saveButton;
+
+ public void selectEditMode(String mode){
+ waitGuiForElement(By.id("editMode"));
+ editModeSelect.selectByVisibleText(mode);
+ }
+
+ public void selectVendor(String vendor){
+ waitGuiForElement(By.id("editMode"));
+ vendorSelect.selectByVisibleText(vendor);
+ }
+
+ public void configureLdap(String displayName, String editMode, String vendor, String connectionUrl, String userDN, String ldapBindDn, String ldapBindCredential){
+ consoleDisplayNameInput.sendKeys(displayName);
+ editModeSelect.selectByVisibleText(editMode);
+ selectVendor(vendor);
+ ldapConnectionUrlInput.sendKeys(connectionUrl);
+ ldapUserDnInput.sendKeys(userDN);
+ ldapBindDnInput.sendKeys(ldapBindDn);
+ ldapBindCredentialInput.sendKeys(ldapBindCredential);
+ saveButton.click();
+ }
+
+ public void testConnection(){
+ testConnectionButton.click();
+ }
+
+ public void testAuthentication(){
+ testAuthenticationButton.click();
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/UserFederation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/UserFederation.java
new file mode 100644
index 0000000..b209b81
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/federation/UserFederation.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.console.page.federation;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.By;
+import org.openqa.selenium.support.ui.Select;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+
+/**
+ * Created by fkiss.
+ */
+public class UserFederation extends AdminConsoleRealm {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/user-federation";
+ }
+
+ @FindByJQuery("select[ng-model*='selectedProvider']")
+ private Select addProviderSelect;
+
+ public void addProvider(String provider) {
+ waitGuiForElement(By.cssSelector("select[ng-model*='selectedProvider']"));
+ addProviderSelect.selectByVisibleText(provider);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Breadcrumb.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Breadcrumb.java
new file mode 100644
index 0000000..d6d517b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/Breadcrumb.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import java.util.List;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Breadcrumb {
+
+ public static final String BREADCRUMB_XPATH = "//ol[@class='breadcrumb']";
+
+ @FindBy(xpath = "./li[not(contains(@class,'ng-hide'))]/a")
+ private List<WebElement> items;
+
+ public int size() {
+ return items.size();
+ }
+
+ public WebElement getItem(int index) {
+ return items.get(index);
+ }
+
+ public WebElement getItemFromEnd(int index) {
+ return items.get(size() - index - 1);
+ }
+
+ public void clickItemOneLevelUp() {
+ getItemFromEnd(0).click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java
new file mode 100644
index 0000000..d049d2e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java
@@ -0,0 +1,76 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import java.util.List;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.By;
+import static org.openqa.selenium.By.xpath;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class DataTable {
+
+ @FindBy(css = "input[class*='search']")
+ private WebElement searchInput;
+ @FindBy(css = "div[class='input-group-addon'] i")
+ private WebElement searchButton;
+
+ @FindBy(tagName = "thead")
+ private WebElement header;
+ @FindBy(css = "tbody")
+ private WebElement body;
+ @FindBy(css = "tbody tr.ng-scope")
+ private List<WebElement> rows;
+
+ @FindBy
+ private WebElement infoRow;
+
+ public void search(String pattern) {
+ waitAjaxForBody();
+ searchInput.sendKeys(pattern);
+ searchButton.click();
+ }
+
+ public void clickHeaderButton(String buttonText) {
+ waitAjaxForBody();
+ header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click();
+ }
+
+ public void clickHeaderLink(String linkText) {
+ waitAjaxForBody();
+ header.findElement(By.linkText(linkText)).click();
+ }
+
+ public WebElement body() {
+ return body;
+ }
+
+ public void waitAjaxForBody() {
+ waitAjaxForElement(body);
+ }
+
+ public List<WebElement> rows() {
+ waitAjaxForBody();
+ pause(250);
+ return rows;
+ }
+
+ public WebElement getRowByLinkText(String text) {
+ WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]"));
+ waitAjaxForElement(row);
+ return row;
+ }
+
+ public void clickRowByLinkText(String text) {
+ body.findElement(By.xpath(".//tr/td/a[text()='" + text + "']")).click();
+ }
+
+ public void clickRowActionButton(WebElement row, String buttonText) {
+ row.findElement(xpath(".//button[text()='" + buttonText + "']")).click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/InputList.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/InputList.java
new file mode 100644
index 0000000..902287e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/InputList.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import java.util.ArrayList;
+import java.util.List;
+import static org.keycloak.testsuite.page.Form.getInputValue;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class InputList {
+
+ @FindBy(xpath=".//input[@ng-model='client.redirectUris[i]']")
+ private List<WebElement> inputs;
+
+ public List<String> getValues() {
+ List<String> values = new ArrayList<>();
+ for (WebElement input: inputs) {
+ values.add(getInputValue(input));
+ }
+ return values;
+ }
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
new file mode 100644
index 0000000..9bb95dd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
@@ -0,0 +1,36 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ModalDialog {
+
+ @FindBy(xpath = ".//button[text()='Cancel']")
+ private WebElement cancelButton;
+ @FindBy(xpath = ".//button[text()='Delete']")
+ private WebElement deleteButton;
+
+ @FindBy(xpath = ".//button[@ng-click='ok()']")
+ private WebElement okButton;
+
+ public void ok() {
+ waitAjaxForElement(okButton);
+ okButton.click();
+ }
+
+ public void confirmDeletion() {
+ waitAjaxForElement(deleteButton);
+ deleteButton.click();
+ }
+
+ public void cancel() {
+ waitAjaxForElement(cancelButton);
+ cancelButton.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/RealmSelector.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/RealmSelector.java
new file mode 100644
index 0000000..5e2ea52
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/RealmSelector.java
@@ -0,0 +1,11 @@
+package org.keycloak.testsuite.console.page.fragment;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RealmSelector {
+
+ // TODO
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CacheSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CacheSettings.java
new file mode 100644
index 0000000..e903f01
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/CacheSettings.java
@@ -0,0 +1,42 @@
+package org.keycloak.testsuite.console.page.realm;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+
+/**
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class CacheSettings extends RealmSettings {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/cache-settings";
+ }
+
+ @Page
+ private CacheSettingsForm form;
+
+ public CacheSettingsForm form() {
+ return form;
+ }
+
+ public class CacheSettingsForm extends Form {
+ @FindByJQuery("div[class='onoffswitch']:eq(0)")
+ private OnOffSwitch realmCacheEnabled;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(1)")
+ private OnOffSwitch userCacheEnabled;
+
+ public void setRealmCacheEnabled(boolean value) {
+ realmCacheEnabled.setOn(value);
+ }
+
+ public void setUserCacheEnabled(boolean value) {
+ userCacheEnabled.setOn(value);
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/EmailSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/EmailSettings.java
new file mode 100644
index 0000000..f75117b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/EmailSettings.java
@@ -0,0 +1,70 @@
+package org.keycloak.testsuite.console.page.realm;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * Created by mhajas on 8/25/15.
+ */
+public class EmailSettings extends RealmSettings {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/smtp-settings";
+ }
+
+ @Page
+ private EmailSettingsForm form;
+
+ public EmailSettingsForm form() {
+ return form;
+ }
+
+ public class EmailSettingsForm extends Form {
+ @FindBy(id = "smtpHost")
+ private WebElement hostInput;
+
+ @FindBy(id = "smtpPort")
+ private WebElement portInput;
+
+ @FindBy(id = "smtpFrom")
+ private WebElement fromInput;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(0)")
+ private OnOffSwitch enableSSL;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(1)")
+ private OnOffSwitch enableStartTLS;
+
+ @FindByJQuery("div[class='onoffswitch']:eq(2)")
+ private OnOffSwitch enableAuthentication;
+
+ public void setEnableSSL(boolean sslEnabled) {
+ enableSSL.setOn(sslEnabled);
+ }
+
+ public void setEnableStartTLS(boolean startTLS) {
+ enableSSL.setOn(startTLS);
+ }
+
+ public void setEnableAuthentication(boolean authentication) {
+ enableSSL.setOn(authentication);
+ }
+
+ public void setHostInput(String value) {
+ setInputValue(hostInput, value);
+ }
+
+ public void setPortInput(String value) {
+ setInputValue(portInput, value);
+ }
+
+ public void setFromInput(String value) {
+ setInputValue(fromInput, value);
+ }
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/KeysSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/KeysSettings.java
new file mode 100644
index 0000000..902acf0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/KeysSettings.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.realm;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class KeysSettings extends RealmSettings {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/cache-settings";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/RealmSettings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/RealmSettings.java
new file mode 100644
index 0000000..83b1a67
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/RealmSettings.java
@@ -0,0 +1,72 @@
+package org.keycloak.testsuite.console.page.realm;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RealmSettings extends AdminConsoleRealm {
+
+ @FindBy(xpath = "//div[@data-ng-controller='RealmTabCtrl']/ul")
+ private RealmTabs realmTabs;
+
+ public RealmTabs tabs() {
+ return realmTabs;
+ }
+
+ public class RealmTabs {
+
+ @FindBy(linkText = "General")
+ private WebElement generalSettingsTab;
+ @FindBy(linkText = "Login")
+ private WebElement loginSettingsTab;
+ @FindBy(linkText = "Keys")
+ private WebElement keysSettingsTab;
+ @FindBy(linkText = "Email")
+ private WebElement emailSettingsTab;
+ @FindBy(linkText = "Themes")
+ private WebElement themeSettingsTab;
+ @FindBy(linkText = "Cache")
+ private WebElement cacheSettingsTab;
+ @FindBy(linkText = "Tokens")
+ private WebElement tokenSettingsTab;
+ @FindBy(linkText = "Security Defenses")
+ private WebElement defenseTab;
+
+ public void general() {
+ generalSettingsTab.click();
+ }
+
+ public void login() {
+ loginSettingsTab.click();
+ }
+
+ public void keys() {
+ keysSettingsTab.click();
+ }
+
+ public void email() {
+ emailSettingsTab.click();
+ }
+
+ public void themes() {
+ themeSettingsTab.click();
+ }
+
+ public void cache() {
+ cacheSettingsTab.click();
+ }
+
+ public void tokens() {
+ tokenSettingsTab.click();
+ }
+
+ public void securityDefenses() {
+ defenseTab.click();
+ }
+
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/SecurityDefenses.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/SecurityDefenses.java
new file mode 100644
index 0000000..00bd0b8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/realm/SecurityDefenses.java
@@ -0,0 +1,197 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page.realm;
+
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.page.Form.setInputValue;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ * @author Filip Kiss
+ * @author mhajas
+ */
+public class SecurityDefenses extends RealmSettings {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/defense"; // NOTE: page doesn't exist, only subpages
+ }
+
+ public class Headers extends SecurityDefenses {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/headers";
+ }
+
+ @Page
+ private HeadersForm form;
+
+ public HeadersForm form() {
+ return form;
+ }
+
+ public class HeadersForm extends Form {
+
+ @FindBy(id = "xFrameOptions")
+ private WebElement xFrameOptions;
+
+ public void setXFrameOptions(String value) {
+ setInputValue(xFrameOptions, value);
+ }
+
+ @FindBy(id = "contentSecurityPolicy")
+ private WebElement contentSecurityPolicy;
+
+ public void setContentSecurityPolicy(String value) {
+ setInputValue(contentSecurityPolicy, value);
+ }
+ }
+ }
+
+ public enum TimeSelectValues {
+
+ SECONDS("Seconds"), MINUTES("Minutes"), HOURS("Hours"), DAYS("Days");
+
+ private String name;
+
+ private TimeSelectValues(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public class BruteForceDetection extends SecurityDefenses {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/brute-force";
+ }
+
+ @Page
+ private BruteForceDetectionForm form;
+
+ public BruteForceDetectionForm form() {
+ return form;
+ }
+
+ public class BruteForceDetectionForm extends Form {
+
+ @FindByJQuery("div[class='onoffswitch']")
+ private OnOffSwitch protectionEnabled;
+
+ public void setProtectionEnabled(boolean protectionEnabled) {
+ this.protectionEnabled.setOn(protectionEnabled);
+ }
+
+ @FindBy(id = "failureFactor")
+ private WebElement maxLoginFailures;
+
+ public void setMaxLoginFailures(String value) {
+ setInputValue(maxLoginFailures, value);
+ }
+
+ @FindBy(id = "waitIncrement")
+ private WebElement waitIncrementInput;
+
+ @FindBy(name = "waitIncrementUnit")
+ private Select waitIncrementSelect;
+
+ public void setWaitIncrementInput(String value) {
+ setInputValue(waitIncrementInput, value);
+ }
+
+ public void setWaitIncrementSelect(TimeSelectValues value) {
+ waitIncrementSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(id = "quickLoginCheckMilliSeconds")
+ private WebElement quickLoginCheckInput;
+
+ public void setQuickLoginCheckInput(String value) {
+ setInputValue(quickLoginCheckInput, value);
+ }
+
+ @FindBy(id = "minimumQuickLoginWait")
+ private WebElement minQuickLoginWaitInput;
+
+ @FindBy(name = "minimumQuickLoginWaitUnit")
+ private Select minQuickLoginWaitSelect;
+
+ public void setMinQuickLoginWaitInput(String value) {
+ setInputValue(minQuickLoginWaitInput, value);
+ }
+
+ public void setMinQuickLoginWaitSelect(TimeSelectValues value) {
+ minQuickLoginWaitSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(id = "maxFailureWait")
+ private WebElement maxWaitInput;
+
+ @FindBy(name = "maxFailureWaitUnit")
+ private Select maxWaitSelect;
+
+ public void setMaxWaitInput(String value) {
+ setInputValue(maxWaitInput, value);
+ }
+
+ public void setMaxWaitSelect(TimeSelectValues value) {
+ maxWaitSelect.selectByVisibleText(value.getName());
+ }
+
+ @FindBy(id = "maxDeltaTime")
+ private WebElement failureResetTimeInput;
+
+ @FindBy(name = "maxDeltaTimeUnit")
+ private Select failureResetTimeSelect;
+
+ public void setFailureResetTimeInput(String value) {
+ setInputValue(failureResetTimeInput, value);
+ }
+
+ public void setFailureResetTimeSelect(TimeSelectValues value) {
+ failureResetTimeSelect.selectByVisibleText(value.getName());
+ }
+
+ }
+
+ }
+
+ @FindByJQuery("a:contains('Brute Force Detection')")
+ private WebElement bruteForceDetectionTab;
+
+ public void goToBruteForceDetection() {
+ bruteForceDetectionTab.click();
+ }
+
+ @FindByJQuery("a:contains('Headers')")
+ private WebElement headersTab;
+
+ public void goToHeaders() {
+ headersTab.click();
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/CreateRole.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/CreateRole.java
new file mode 100644
index 0000000..d1f218b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/CreateRole.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateRole extends AdminConsoleCreate {
+
+ public CreateRole() {
+ setEntity("role");
+ }
+
+ @Page
+ private RoleForm form;
+
+ public RoleForm form() {
+ return form;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Role.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Role.java
new file mode 100644
index 0000000..2bde155
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Role.java
@@ -0,0 +1,33 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Role extends RealmRoles {
+
+ public static final String ROLE_ID = "roleId";
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/{" + ROLE_ID + "}";
+ }
+
+ public void setRoleId(String id) {
+ setUriParameter(ROLE_ID, id);
+ }
+
+ public String getRoleId() {
+ return getUriParameter(ROLE_ID).toString();
+ }
+
+ @Page
+ private RoleForm form;
+
+ public RoleForm form() {
+ return form;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java
new file mode 100644
index 0000000..876b45b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java
@@ -0,0 +1,182 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.keycloak.representations.idm.RoleRepresentation.Composites;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author fkiss
+ * @author tkyjovsk
+ */
+public class RoleCompositeRoles extends Form {
+
+ @FindBy(id = "available")
+ protected Select availableRealmRolesSelect;
+ @FindBy(id = "assigned")
+ protected Select assignedRealmRolesSelect;
+
+ @FindBy(id = "clients")
+ protected Select clientSelect;
+ @FindBy(id = "available-client")
+ protected Select availableClientRolesSelect;
+ @FindBy(id = "assigned-client")
+ protected Select assignedClientRolesSelect;
+
+ @FindBy(css = "button[ng-click*='addRealm']")
+ protected WebElement addSelectedRealmRolesButton;
+ @FindBy(css = "button[ng-click*='addClient']")
+ protected WebElement addSelectedClientRolesButton;
+ @FindBy(css = "button[ng-click*='deleteRealm']")
+ protected WebElement removeSelectedRealmRolesButton;
+ @FindBy(css = "button[ng-click*='deleteClient']")
+ protected WebElement removeSelectedClientRolesButton;
+
+ public Composites getComposites() {
+ Composites composites = new Composites();
+ // realm roles
+ composites.setRealm(getSelectValues(assignedRealmRolesSelect));
+ // client roles
+ Map<String, List<String>> clientRoles = new HashMap<>();
+ for (String client : getSelectValues(clientSelect)) {
+ clientSelect.selectByVisibleText(client);
+ clientRoles.put(client, new ArrayList(getSelectValues(assignedClientRolesSelect)));
+ }
+ composites.setClient(clientRoles);
+ return composites;
+ }
+
+ public void setComposites(Composites composites) {
+ if (composites != null) {
+ setRealmRoles(composites.getRealm());
+ for (String client : composites.getClient().keySet()) {
+ clientSelect.selectByVisibleText(client);
+ setClientRoles(composites.getClient().get(client));
+ }
+ }
+ }
+
+ private void setRealmRoles(Collection<String> roles) {
+ removeRedundantRoles(assignedRealmRolesSelect, removeSelectedRealmRolesButton, roles);
+ addMissingRoles(availableRealmRolesSelect, addSelectedRealmRolesButton, roles);
+ }
+
+ private void setClientRoles(Collection<String> roles) {
+ removeRedundantRoles(assignedClientRolesSelect, removeSelectedClientRolesButton, roles);
+ addMissingRoles(availableClientRolesSelect, addSelectedClientRolesButton, roles);
+ }
+
+ private void removeRedundantRoles(Select select, WebElement button, Collection<String> roles) {
+ select.deselectAll();
+ for (String role : getSelectValues(select)) {
+ if (roles == null // if roles not provided, remove all
+ || !roles.contains(role)) { // if roles provided, remove only the redundant
+ select.selectByVisibleText(role);
+ }
+ }
+ button.click();
+ }
+
+ protected void addMissingRoles(Select select, WebElement button, Collection<String> roles) {
+ select.deselectAll();
+ if (roles != null) { // if roles not provided, don't add any
+ for (String role : getSelectValues(select)) {
+ if (roles.contains(role)) { // if roles provided, add only the missing
+ select.selectByVisibleText(role);
+ }
+ }
+ button.click();
+ }
+ }
+
+ public static Set<String> getSelectValues(Select select) {
+ Set<String> roles = new HashSet<>();
+ for (WebElement option : select.getOptions()) {
+ roles.add(option.getText());
+ }
+ return roles;
+ }
+
+ // ***
+ public Set<String> getAvailableRealmRoles() {
+ return getSelectValues(availableRealmRolesSelect);
+ }
+
+ public Set<String> getAvailableClientRoles(String client) {
+ return getSelectValues(availableClientRolesSelect);
+ }
+
+ public Set<String> getAssignedRealmRoles() {
+ return getSelectValues(assignedRealmRolesSelect);
+ }
+
+ public Set<String> getAssignedClientRoles() {
+ return getSelectValues(assignedClientRolesSelect);
+ }
+
+ // *** original methods ***
+ public void addAvailableRole(String... roles) {
+ waitGuiForElement(By.id("available"));
+ for (String role : roles) {
+ availableRealmRolesSelect.selectByVisibleText(role);
+ addSelectedRealmRolesButton.click();
+ }
+ }
+
+ public void removeAssignedRole(String role) {
+ waitGuiForElement(By.id("assigned"));
+ assignedRealmRolesSelect.selectByVisibleText(role);
+ removeSelectedRealmRolesButton.click();
+ }
+
+ public boolean isAssignedRole(String role) {
+ waitGuiForElement(By.id("assigned"));
+ try {
+ assignedRealmRolesSelect.selectByVisibleText(role);
+ } catch (Exception ex) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean isAssignedClientRole(String role) {
+ waitGuiForElement(By.id("assigned"));
+ try {
+ assignedClientRolesSelect.selectByVisibleText(role);
+ } catch (Exception ex) {
+ return false;
+ }
+ return true;
+ }
+
+ public void selectClientRole(String client) {
+ waitGuiForElement(By.id("clients"));
+ clientSelect.selectByVisibleText(client);
+ }
+
+ public void addAvailableClientRole(String... roles) {
+ waitGuiForElement(By.id("available-client"));
+ for (String role : roles) {
+ availableClientRolesSelect.selectByVisibleText(role);
+ addSelectedClientRolesButton.click();
+ }
+ }
+
+ public void removeAssignedClientRole(String client) {
+ waitGuiForElement(By.id("assigned-client"));
+ assignedClientRolesSelect.selectByVisibleText(client);
+ removeSelectedClientRolesButton.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java
new file mode 100644
index 0000000..ac1db15
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RoleForm.java
@@ -0,0 +1,101 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RoleForm extends Form {
+
+ @FindBy(id = "name")
+ private WebElement nameInput;
+
+ @FindBy(id = "description")
+ private WebElement descriptionInput;
+
+ @FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='compositeSwitch']]")
+ private OnOffSwitch compositeSwitch;
+
+ @FindBy(xpath = ".//fieldset[./legend[contains(text(),'Composite Roles')]]")
+ private RoleCompositeRoles compositeRoles;
+
+ @FindBy(id = "removeRole")
+ private WebElement removeIcon;
+
+ public RoleRepresentation getRole() {
+ RoleRepresentation role = new RoleRepresentation(getName(), getDescription());
+ role.setComposite(isComposite());
+ if (role.isComposite()) {
+ role.setComposites(compositeRoles.getComposites());
+ }
+ return role;
+ }
+
+ public void setRole(RoleRepresentation role) {
+ setBasicAttributes(role);
+ }
+
+ public RoleRepresentation getBasicAttributes() {
+ RoleRepresentation role = new RoleRepresentation();
+ role.setName(getName());
+ role.setDescription(getDescription());
+ role.setComposite(isComposite());
+ log.info(role.getName() + ": " + role.getDescription() + ", comp: " + role.isComposite());
+ return role;
+ }
+
+ public void setBasicAttributes(RoleRepresentation role) {
+ setName(role.getName());
+ setDescription(role.getDescription());
+ if (role.isComposite()) {
+ setCompositeRoles(role);
+ }
+ }
+
+ // TODO KEYCLOAK-1364 enabling/disabling composite role seems unintuitive
+ // it should be possible to remove all composite roles by switching to OFF
+ public void setCompositeRoles(RoleRepresentation role) {
+ if (role.isComposite() && role.getComposites() != null) {
+ setComposite(true);
+ }
+ compositeRoles.setComposites(role.getComposites());
+ }
+
+ public void setName(String name) {
+ setInputValue(nameInput, name);
+ }
+
+ public String getName() {
+ return getInputValue(nameInput);
+ }
+
+ public void setDescription(String description) {
+ setInputValue(descriptionInput, description);
+ }
+
+ public String getDescription() {
+ return getInputValue(descriptionInput);
+ }
+
+ public void setComposite(boolean composite) {
+ compositeSwitch.setOn(composite);
+ }
+
+ public boolean isComposite() {
+ return compositeSwitch.isOn();
+ }
+
+ public RoleCompositeRoles compositeRoles() {
+ return compositeRoles;
+ }
+
+ public void delete() {
+ removeIcon.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java
new file mode 100644
index 0000000..910e470
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java
@@ -0,0 +1,42 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import org.keycloak.admin.client.resource.RolesResource;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Roles extends AdminConsoleRealm {
+
+ @FindBy(css = "ul.nav-tabs")
+ private RoleTabs tabs;
+
+ public RoleTabs tabs() {
+ return tabs;
+ }
+
+ public class RoleTabs {
+
+ @FindBy(linkText = "Realm Roles")
+ private WebElement realmRolesTab;
+ @FindBy(linkText = "Default Roles")
+ private WebElement defaultRolesTab;
+
+ public void realmRoles() {
+ realmRolesTab.click();
+ }
+
+ public void defaultRoles() {
+ defaultRolesTab.click();
+ }
+
+ }
+
+ public RolesResource rolesResource() {
+ return realmResource().roles();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java
new file mode 100644
index 0000000..b215844
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java
@@ -0,0 +1,85 @@
+package org.keycloak.testsuite.console.page.roles;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import static org.openqa.selenium.By.tagName;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class RolesTable extends DataTable {
+
+ public static final String ADD_ROLE = "Add Role";
+
+ public static final String EDIT = "Edit";
+ public static final String DELETE = "Delete";
+
+ public List<RoleRepresentation> searchRoles(String searchPattern) {
+ search(searchPattern);
+ return getRolesFromTableRows();
+ }
+
+ public void addRole() {
+ clickHeaderLink(ADD_ROLE);
+ }
+
+ public void clickRole(String name) {
+ waitAjaxForBody();
+ clickRowByLinkText(name);
+ }
+
+ public void editRole(String name) {
+ clickRowActionButton(getRowByLinkText(name), EDIT);
+ }
+
+ public void deleteRole(String name) {
+ clickRowActionButton(getRowByLinkText(name), DELETE);
+ }
+
+ public RoleRepresentation findRole(String name) {
+ List<RoleRepresentation> roles = searchRoles(name);
+ if (roles.isEmpty()) {
+ return null;
+ } else {
+ assert 1 == roles.size();
+ return roles.get(0);
+ }
+ }
+
+ public boolean containsRole(String roleName) {
+ for (RoleRepresentation r : getRolesFromTableRows()) {
+ if (roleName.equals(r.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public List<RoleRepresentation> getRolesFromTableRows() {
+ List<RoleRepresentation> rows = new ArrayList<>();
+ for (WebElement row : rows()) {
+ RoleRepresentation role = getRoleFromRow(row);
+ if (role != null) {
+ rows.add(role);
+ }
+ }
+ return rows;
+ }
+
+ public RoleRepresentation getRoleFromRow(WebElement row) {
+ RoleRepresentation role = null;
+ List<WebElement> tds = row.findElements(tagName("td"));
+ if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
+ role = new RoleRepresentation();
+ role.setName(tds.get(0).getText());
+ role.setComposite(Boolean.valueOf(tds.get(1).getText()));
+ role.setDescription(tds.get(2).getText());
+ }
+ return role;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Revocation.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Revocation.java
new file mode 100644
index 0000000..0175848
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Revocation.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.sessions;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Revocation extends Sessions {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/revocation";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Sessions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Sessions.java
new file mode 100644
index 0000000..a0a8dba
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/sessions/Sessions.java
@@ -0,0 +1,32 @@
+package org.keycloak.testsuite.console.page.sessions;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Sessions extends AdminConsoleRealm {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/sessions";
+ }
+
+ @FindBy(linkText = "Realm Sessions")
+ private WebElement realmSessionsTab;
+
+ @FindBy(linkText = "Revocation")
+ private WebElement revocationTab;
+
+ public void realmSessions() {
+ realmSessionsTab.click();
+ }
+
+ public void revocation() {
+ revocationTab.click();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/CreateUser.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/CreateUser.java
new file mode 100644
index 0000000..4cd0df6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/CreateUser.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.testsuite.console.page.AdminConsoleCreate;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class CreateUser extends AdminConsoleCreate {
+
+ public CreateUser() {
+ setEntity("user");
+ }
+
+ @Page
+ private UserAttributesForm form;
+
+ public UserAttributesForm form() {
+ return form;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/User.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/User.java
new file mode 100644
index 0000000..fba2adb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/User.java
@@ -0,0 +1,83 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.testsuite.console.page.fragment.Breadcrumb;
+import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class User extends Users {
+
+ public static final String ID = "id";
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/{" + ID + "}";
+ }
+
+ public void setId(String id) {
+ setUriParameter(ID, id);
+ }
+
+ public String getId() {
+ return (String) getUriParameter(ID);
+ }
+
+ @FindBy(xpath = BREADCRUMB_XPATH)
+ private Breadcrumb breadcrumb;
+
+ public Breadcrumb breadcrumb() {
+ return breadcrumb;
+ }
+
+ @FindBy(xpath = "//div[@data-ng-controller='UserTabCtrl']/ul")
+ protected UserTabs userTabs;
+
+ public UserTabs tabs() {
+ return userTabs;
+ }
+
+ public class UserTabs {
+
+ @FindBy(linkText = "Attributes")
+ private WebElement attributesLink;
+ @FindBy(linkText = "Credentials")
+ private WebElement credentialsLink;
+ @FindBy(linkText = "Role Mappings")
+ private WebElement roleMappingsLink;
+ @FindBy(linkText = "Consents")
+ private WebElement consentsLink;
+ @FindBy(linkText = "Sessions")
+ private WebElement sessionsLink;
+
+ public void attributes() {
+ attributesLink.click();
+ }
+
+ public void credentials() {
+ credentialsLink.click();
+ }
+
+ public void roleMappings() {
+ roleMappingsLink.click();
+ }
+
+ public void consents() {
+ consentsLink.click();
+ }
+
+ public void sessions() {
+ sessionsLink.click();
+ }
+
+ }
+
+ public UserResource userResource() {
+ return usersResource().get(getId());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributes.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributes.java
new file mode 100644
index 0000000..ebe5218
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributes.java
@@ -0,0 +1,22 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserAttributes extends User {
+
+ @FindBy(name = "userForm")
+ private UserAttributesForm form;
+
+ public UserAttributesForm form() {
+ return form;
+ }
+
+ public void backToUsersViaBreadcrumb() {
+ breadcrumb().clickItemOneLevelUp();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java
new file mode 100644
index 0000000..85b32e6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java
@@ -0,0 +1,139 @@
+package org.keycloak.testsuite.console.page.users;
+
+import java.util.List;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import org.keycloak.testsuite.page.Form;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class UserAttributesForm extends Form {
+
+ @FindBy(id = "id")
+ private WebElement idInput;
+
+ @FindBy(id = "username")
+ private WebElement usernameInput;
+
+ @FindBy(id = "email")
+ private WebElement emailInput;
+
+ @FindBy(id = "firstName")
+ private WebElement firstNameInput;
+
+ @FindBy(id = "lastName")
+ private WebElement lastNameInput;
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='userEnabled']]")
+ private OnOffSwitch userEnabledSwitch;
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='emailVerified']]")
+ private OnOffSwitch emailVerifiedSwitch;
+
+ @FindBy(xpath = ".//div[./label[contains(text(), 'Required User Actions')]]//input")
+ private WebElement requiredUserActionsInput;
+
+ @FindBy(id = "reqActions")
+ private Select requiredUserActionsSelect;
+
+ @FindBy(className = "select2-result-label")
+ private WebElement requiredUserActionsConfirm;
+
+ @FindBy(className = "select2-search-choice-close")
+ private List<WebElement> removeRequiredActionsList;
+
+ @FindBy(xpath = "//button[@data-ng-click='unlockUser()']")
+ private WebElement unlockUserButton;
+
+ public String getId() {
+ return getInputValue(idInput);
+ }
+
+ public String getUsername() {
+ return getInputValue(usernameInput);
+ }
+
+ public void setUsername(String username) {
+ setInputValue(usernameInput, username);
+ }
+
+ public String getEmail() {
+ return getInputValue(emailInput);
+ }
+
+ public void setEmail(String email) {
+ setInputValue(emailInput, email);
+ }
+
+ public String getFirstName() {
+ return getInputValue(firstNameInput);
+ }
+
+ public void setFirstName(String firstName) {
+ setInputValue(firstNameInput, firstName);
+ }
+
+ public String getLastName() {
+ return getInputValue(lastNameInput);
+ }
+
+ public void setLastName(String lastname) {
+ setInputValue(lastNameInput, lastname);
+ }
+
+ public boolean isEnabled() {
+ return userEnabledSwitch.isOn();
+ }
+
+ public void setEnabled(boolean enabled) {
+ userEnabledSwitch.setOn(enabled);
+ }
+
+ public void unlockUser() {
+ unlockUserButton.click();
+ }
+
+ public boolean isEmailVerified() {
+ return emailVerifiedSwitch.isOn();
+ }
+
+ public void setEmailVerified(boolean emailVerified) {
+ emailVerifiedSwitch.setOn(emailVerified);
+ }
+
+ public void addRequiredAction(String requiredAction) {
+ requiredUserActionsInput.click();
+ requiredUserActionsSelect.selectByVisibleText(requiredAction);
+ }
+
+ public void setRequiredActions(List<String> requiredActions) {
+ for (WebElement e : removeRequiredActionsList) {
+ e.click();
+ }
+ if (requiredActions != null && !requiredActions.isEmpty()) {
+ for (String action : requiredActions) {
+ addRequiredAction(action);
+ }
+ }
+ }
+
+ public void setValues(UserRepresentation user) {
+ waitAjaxForElement(usernameInput);
+ setUsername(user.getUsername());
+ setEmail(user.getEmail());
+ setFirstName(user.getFirstName());
+ setLastName(user.getLastName());
+ setEnabled(user.isEnabled());
+ setEmailVerified(user.isEmailVerified());
+ setRequiredActions(user.getRequiredActions());
+ }
+
+ // TODO Contact Information section
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserConsents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserConsents.java
new file mode 100644
index 0000000..6525763
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserConsents.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.users;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserConsents extends User {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/consents";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java
new file mode 100644
index 0000000..830d789
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
+import static org.keycloak.testsuite.page.Form.setInputValue;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserCredentials extends User {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/user-credentials";
+ }
+
+ @FindBy(id = "password")
+ private WebElement newPasswordInput;
+
+ @FindBy(id = "confirmPassword")
+ private WebElement confirmPasswordInput;
+
+ @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='temporaryPassword']]")
+ private OnOffSwitch temporaryOnOffSwitch;
+
+ @FindBy(xpath = ".//button[contains(@data-ng-click, 'resetPassword')]")
+ private WebElement resetPasswordButton;
+
+ public void setNewPassword(String newPassword) {
+ setInputValue(newPasswordInput, newPassword);
+ }
+
+ public void setConfirmPassword(String confirmPassword) {
+ setInputValue(confirmPasswordInput, confirmPassword);
+ }
+
+ public void setTemporary(boolean temporary) {
+ temporaryOnOffSwitch.setOn(temporary);
+ }
+
+ public void clickResetPasswordAndConfirm() {
+ resetPasswordButton.click();
+ modalDialog.ok();
+ }
+
+ public void resetPassword(String newPassword) {
+ resetPassword(newPassword, newPassword);
+ }
+ public void resetPassword(String newPassword, String confirmPassword) {
+ setNewPassword(newPassword);
+ setConfirmPassword(confirmPassword);
+ clickResetPasswordAndConfirm();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java
new file mode 100644
index 0000000..3a05b68
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java
@@ -0,0 +1,28 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.keycloak.admin.client.resource.RoleMappingResource;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserRoleMappings extends User {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "role-mappings";
+ }
+
+ @Page
+ private UserRoleMappingsForm form;
+
+ public UserRoleMappingsForm form() {
+ return form;
+ }
+
+ public RoleMappingResource roleMappingResource() {
+ return userResource().roles();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappingsForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappingsForm.java
new file mode 100644
index 0000000..2629017
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappingsForm.java
@@ -0,0 +1,46 @@
+package org.keycloak.testsuite.console.page.users;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.ui.Select;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.roles.RoleCompositeRoles;
+
+/**
+ * Created by fkiss.
+ */
+public class UserRoleMappingsForm extends RoleCompositeRoles {
+
+ @FindBy(id = "realm-composite")
+ private Select effectiveRolesSelect;
+
+ @FindBy(id = "client-composite")
+ private Select effectiveClientRolesSelect;
+
+ public boolean isEffectiveRealmRolesComplete(RoleRepresentation... roles) {
+ return isEffectiveRolesComplete(effectiveRolesSelect, roles);
+ }
+
+ public boolean isEffectiveClientRolesComplete(RoleRepresentation... roles) {
+ return isEffectiveRolesComplete(effectiveClientRolesSelect, roles);
+ }
+
+ private boolean isEffectiveRolesComplete(Select select, RoleRepresentation... roles) {
+ List<String> roleNames = new ArrayList<>();
+ for (RoleRepresentation role : roles) {
+ roleNames.add(role.getName());
+ }
+ for (WebElement role : select.getOptions()) {
+ roleNames.contains(role.getText());
+ roleNames.remove(role.getText());
+ }
+ log.info(Arrays.toString(roles));
+ log.info(roleNames);
+ return roleNames.isEmpty();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/Users.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/Users.java
new file mode 100644
index 0000000..3b1d730
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/Users.java
@@ -0,0 +1,142 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.page.users;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.keycloak.testsuite.console.page.fragment.DataTable;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import static org.openqa.selenium.By.*;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class Users extends AdminConsoleRealm {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/users";
+ }
+
+ public static final String VIEW_ALL_USERS = "View all users";
+ public static final String UNLOCK_USERS = "Unlock Users";
+ public static final String ADD_USER = "Add User";
+
+ public static final String EDIT = "Edit";
+ public static final String IMPERSONATE = "Impersonate";
+ public static final String DELETE = "Delete";
+
+ @FindBy(xpath = "//div[./h1[text()='Users']]/table")
+ private UsersTable table;
+
+ public UsersTable table() {
+ return table;
+ }
+
+ public class UsersTable extends DataTable {
+
+ public List<UserRepresentation> searchUsers(String searchPattern) {
+ search(searchPattern);
+ return getUsersFromTableRows();
+ }
+
+ public void viewAllUsers() {
+ clickHeaderButton(VIEW_ALL_USERS);
+ }
+
+ public void unlockUsers() {
+ clickHeaderButton(UNLOCK_USERS);
+ }
+
+ public void clickUser(String username) {
+ waitAjaxForElement(body());
+ body().findElement(linkText(username)).click();
+ }
+
+ public void editUser(String username) {
+ clickRowActionButton(getRowByLinkText(username), EDIT);
+ }
+
+ public void impersonateUser(String username) {
+ clickRowActionButton(getRowByLinkText(username), IMPERSONATE);
+ }
+
+ public void deleteUser(String username) {
+ clickRowActionButton(getRowByLinkText(username), DELETE);
+ modalDialog.confirmDeletion();
+ }
+
+ public void addUser() {
+ clickHeaderLink(ADD_USER);
+ }
+
+ public UserRepresentation findUser(String searchPattern) {
+ List<UserRepresentation> users = searchUsers(searchPattern);
+ if (users.isEmpty()) {
+ return null;
+ } else {
+ assert 1 == users.size();
+ return users.get(0);
+ }
+ }
+
+ public UserRepresentation getUserFromTableRow(WebElement row) {
+ UserRepresentation user = null;
+ List<WebElement> tds = row.findElements(tagName("td"));
+ if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
+ user = new UserRepresentation();
+ user.setUsername(tds.get(0).getText());
+ user.setLastName(tds.get(1).getText());
+ user.setFirstName(tds.get(2).getText());
+ user.setEmail(tds.get(3).getText());
+ }
+ return user;
+ }
+
+ public List<UserRepresentation> getUsersFromTableRows() {
+ List<UserRepresentation> users = new ArrayList<>();
+ List<WebElement> rows = rows();
+// if (rows.size() > 1) {
+ for (WebElement rowElement : rows) {
+ if (rowElement.isDisplayed()) {
+ UserRepresentation user = getUserFromTableRow(rowElement);
+ if (user != null) {
+ users.add(user);
+ }
+ }
+ }
+// }
+ return users;
+ }
+
+ }
+
+ public UsersResource usersResource() {
+ return realmResource().users();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserSessions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserSessions.java
new file mode 100644
index 0000000..bfe9ac5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserSessions.java
@@ -0,0 +1,14 @@
+package org.keycloak.testsuite.console.page.users;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UserSessions extends User {
+
+ @Override
+ public String getUriFragment() {
+ return super.getUriFragment() + "/sessions";
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java
new file mode 100644
index 0000000..a06666c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java
@@ -0,0 +1,83 @@
+package org.keycloak.testsuite.page;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import javax.ws.rs.core.UriBuilder;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.openqa.selenium.WebDriver;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractPage {
+
+ protected final Logger log = Logger.getLogger(this.getClass());
+
+ private final Map<String, Object> uriParameters = new HashMap<>();
+
+ @Drone
+ protected WebDriver driver;
+
+ private UriBuilder builder;
+
+ public WebDriver getDriver() {
+ return driver;
+ }
+
+ public abstract UriBuilder createUriBuilder();
+
+ public String getUriFragment() {
+ return "";
+ }
+
+ /**
+ *
+ * @return Instance of UriBuilder that can build URIs for a concrete page.
+ */
+ public UriBuilder getUriBuilder() {
+ if (builder == null) {
+ builder = createUriBuilder();
+ String fragment = getUriFragment();
+ if (fragment != null && !fragment.isEmpty()) {
+ builder.fragment(fragment);
+ }
+ }
+ return builder;
+ }
+
+ public AbstractPage setUriParameter(String name, Object value) {
+ uriParameters.put(name, value);
+ return this;
+ }
+
+ public Object getUriParameter(String name) {
+ return uriParameters.get(name);
+ }
+
+ public URI buildUri() {
+ return getUriBuilder().buildFromMap(uriParameters);
+ }
+
+ @Override
+ public String toString() {
+ return buildUri().toASCIIString();
+ }
+
+ public void navigateTo() {
+ String uri = buildUri().toASCIIString();
+ log.debug("current URL: " + driver.getCurrentUrl());
+ log.info("navigating to " + uri);
+ driver.navigate().to(uri);
+ pause(300); // this is needed for FF for some reason
+ log.info("current URL: " + driver.getCurrentUrl());
+ }
+
+ public boolean isCurrent() {
+ return driver.getCurrentUrl().equals(toString());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java
new file mode 100644
index 0000000..b85c75a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java
@@ -0,0 +1,23 @@
+package org.keycloak.testsuite.page;
+
+import java.net.URISyntaxException;
+import java.net.URL;
+import javax.ws.rs.core.UriBuilder;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractPageWithInjectedUrl extends AbstractPage {
+
+ public abstract URL getInjectedUrl();
+
+ @Override
+ public UriBuilder createUriBuilder() {
+ try {
+ return UriBuilder.fromUri(getInjectedUrl().toURI());
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java
new file mode 100644
index 0000000..eee8a21
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.page;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import static org.jboss.arquillian.graphene.Graphene.guardAjax;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Form {
+
+ protected final Logger log = Logger.getLogger(this.getClass());
+
+ @Drone
+ protected WebDriver driver;
+
+ public static final String ACTIVE_DIV_XPATH = ".//div[not(contains(@class,'ng-hide'))]";
+
+ @FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Save']")
+ private WebElement save;
+ @FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Cancel']")
+ private WebElement cancel;
+
+ public void save() {
+// guardAjax(save).click();
+ save.click();
+ }
+
+ public void cancel() {
+ guardAjax(cancel).click();
+ }
+
+ public static String getInputValue(WebElement input) {
+ waitAjaxForElement(input);
+ return input.getAttribute(VALUE);
+ }
+
+ public static final String VALUE = "value";
+
+ public static void setInputValue(WebElement input, String value) {
+ waitAjaxForElement(input);
+ if (input.isEnabled()) {
+ input.clear();
+ if (value != null) {
+ input.sendKeys(value);
+ }
+ } else {
+ // TODO log warning
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/servlet/ApplicationServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/servlet/ApplicationServlet.java
new file mode 100644
index 0000000..2898773
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/servlet/ApplicationServlet.java
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.servlet;
+
+import org.keycloak.services.resources.RealmsResource;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ApplicationServlet extends HttpServlet {
+
+ private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String title;
+ if (req.getRequestURI().endsWith("auth")) {
+ title = "AUTH_RESPONSE";
+ } else if (req.getRequestURI().endsWith("logout")) {
+ title = "LOGOUT_REQUEST";
+ } else {
+ title = "APP_REQUEST";
+ }
+
+ PrintWriter pw = resp.getWriter();
+ pw.printf("<html><head><title>%s</title></head><body>", title);
+ UriBuilder base = UriBuilder.fromUri("http://localhost:8081/auth");
+ pw.printf(LINK, RealmsResource.accountUrl(base).build("test"), "account", "account");
+
+ pw.print("</body></html>");
+ pw.flush();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
new file mode 100644
index 0000000..9ff2bcf
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java
@@ -0,0 +1,43 @@
+package org.keycloak.testsuite.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class IOUtil {
+
+ public static <T> T loadJson(InputStream is, Class<T> type) {
+ try {
+ return JsonSerialization.readValue(is, type);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load json.", e);
+ }
+ }
+
+ public static RealmRepresentation loadRealm(String realmConfig) {
+ return loadRealm(IOUtil.class.getResourceAsStream(realmConfig));
+ }
+
+ public static RealmRepresentation loadRealm(File realmFile) {
+ try {
+ return loadRealm(new FileInputStream(realmFile));
+ } catch (FileNotFoundException ex) {
+ throw new IllegalStateException("Test realm file not found: " + realmFile);
+ }
+ }
+
+ public static RealmRepresentation loadRealm(InputStream is) {
+ RealmRepresentation realm = loadJson(is, RealmRepresentation.class);
+ System.out.println("Loaded realm " + realm.getRealm());
+ return realm;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPTestConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPTestConfiguration.java
new file mode 100644
index 0000000..9d1d19e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPTestConfiguration.java
@@ -0,0 +1,128 @@
+package org.keycloak.testsuite.util;
+
+import org.jboss.logging.Logger;
+import org.keycloak.constants.KerberosConstants;
+import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.UserFederationProvider;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class LDAPTestConfiguration {
+
+ private static final Logger log = Logger.getLogger(LDAPTestConfiguration.class);
+
+ private String connectionPropertiesLocation;
+ private boolean startEmbeddedLdapLerver = true;
+ private Map<String, String> config;
+
+ protected static final Map<String, String> PROP_MAPPINGS = new HashMap<String, String>();
+ protected static final Map<String, String> DEFAULT_VALUES = new HashMap<String, String>();
+
+ static {
+ PROP_MAPPINGS.put(LDAPConstants.CONNECTION_URL, "idm.test.ldap.connection.url");
+ PROP_MAPPINGS.put(LDAPConstants.BASE_DN, "idm.test.ldap.base.dn");
+ PROP_MAPPINGS.put(LDAPConstants.USERS_DN, "idm.test.ldap.user.dn.suffix");
+ PROP_MAPPINGS.put(LDAPConstants.BIND_DN, "idm.test.ldap.bind.dn");
+ PROP_MAPPINGS.put(LDAPConstants.BIND_CREDENTIAL, "idm.test.ldap.bind.credential");
+ PROP_MAPPINGS.put(LDAPConstants.VENDOR, "idm.test.ldap.vendor");
+ PROP_MAPPINGS.put(LDAPConstants.CONNECTION_POOLING, "idm.test.ldap.connection.pooling");
+ PROP_MAPPINGS.put(LDAPConstants.PAGINATION, "idm.test.ldap.pagination");
+ PROP_MAPPINGS.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, "idm.test.ldap.batch.size.for.sync");
+ PROP_MAPPINGS.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, "idm.test.ldap.username.ldap.attribute");
+ PROP_MAPPINGS.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, "idm.test.ldap.rdn.ldap.attribute");
+ PROP_MAPPINGS.put(LDAPConstants.USER_OBJECT_CLASSES, "idm.test.ldap.user.object.classes");
+ PROP_MAPPINGS.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, "idm.test.ldap.user.account.controls.after.password.update");
+ PROP_MAPPINGS.put(LDAPConstants.EDIT_MODE, "idm.test.ldap.edit.mode");
+
+ PROP_MAPPINGS.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "idm.test.kerberos.allow.kerberos.authentication");
+ PROP_MAPPINGS.put(KerberosConstants.KERBEROS_REALM, "idm.test.kerberos.realm");
+ PROP_MAPPINGS.put(KerberosConstants.SERVER_PRINCIPAL, "idm.test.kerberos.server.principal");
+ PROP_MAPPINGS.put(KerberosConstants.KEYTAB, "idm.test.kerberos.keytab");
+ PROP_MAPPINGS.put(KerberosConstants.DEBUG, "idm.test.kerberos.debug");
+ PROP_MAPPINGS.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "idm.test.kerberos.allow.password.authentication");
+ PROP_MAPPINGS.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "idm.test.kerberos.update.profile.first.login");
+ PROP_MAPPINGS.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "idm.test.kerberos.use.kerberos.for.password.authentication");
+
+ DEFAULT_VALUES.put(LDAPConstants.CONNECTION_URL, "ldap://localhost:10389");
+ DEFAULT_VALUES.put(LDAPConstants.BASE_DN, "dc=keycloak,dc=org");
+ DEFAULT_VALUES.put(LDAPConstants.USERS_DN, "ou=People,dc=keycloak,dc=org");
+ DEFAULT_VALUES.put(LDAPConstants.BIND_DN, "uid=admin,ou=system");
+ DEFAULT_VALUES.put(LDAPConstants.BIND_CREDENTIAL, "secret");
+ DEFAULT_VALUES.put(LDAPConstants.VENDOR, LDAPConstants.VENDOR_OTHER);
+ DEFAULT_VALUES.put(LDAPConstants.CONNECTION_POOLING, "true");
+ DEFAULT_VALUES.put(LDAPConstants.PAGINATION, "true");
+ DEFAULT_VALUES.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, String.valueOf(LDAPConstants.DEFAULT_BATCH_SIZE_FOR_SYNC));
+ DEFAULT_VALUES.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, null);
+ DEFAULT_VALUES.put(LDAPConstants.USER_OBJECT_CLASSES, null);
+ DEFAULT_VALUES.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, "false");
+ DEFAULT_VALUES.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.READ_ONLY.toString());
+
+ DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
+ DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
+ DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
+ URL keytabUrl = LDAPTestConfiguration.class.getResource("/kerberos/http.keytab");
+ String keyTabPath = new File(keytabUrl.getFile()).getAbsolutePath();
+ DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
+ DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
+ DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
+ DEFAULT_VALUES.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
+ DEFAULT_VALUES.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "false");
+ }
+
+ public static LDAPTestConfiguration readConfiguration(String connectionPropertiesLocation) {
+ LDAPTestConfiguration ldapTestConfiguration = new LDAPTestConfiguration();
+ ldapTestConfiguration.setConnectionPropertiesLocation(connectionPropertiesLocation);
+ ldapTestConfiguration.loadConnectionProperties();
+ return ldapTestConfiguration;
+ }
+
+ protected void loadConnectionProperties() {
+ Properties p = new Properties();
+ try {
+ log.info("Reading LDAP configuration from: " + connectionPropertiesLocation);
+ InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(connectionPropertiesLocation);
+ p.load(is);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ config = new HashMap<String, String>();
+ for (Map.Entry<String, String> property : PROP_MAPPINGS.entrySet()) {
+ String propertyName = property.getKey();
+ String configName = property.getValue();
+
+ String value = (String) p.get(configName);
+ if (value == null) {
+ value = DEFAULT_VALUES.get(propertyName);
+ }
+
+ config.put(propertyName, value);
+ }
+
+ startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty("idm.test.ldap.start.embedded.ldap.server", "true"));
+ log.info("Start embedded server: " + startEmbeddedLdapLerver);
+ log.info("Read config: " + config);
+ }
+
+ public Map<String,String> getLDAPConfig() {
+ return config;
+ }
+
+ public void setConnectionPropertiesLocation(String connectionPropertiesLocation) {
+ this.connectionPropertiesLocation = connectionPropertiesLocation;
+ }
+
+ public boolean isStartEmbeddedLdapLerver() {
+ return startEmbeddedLdapLerver;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java
new file mode 100644
index 0000000..ba5790d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java
@@ -0,0 +1,11 @@
+package org.keycloak.testsuite.util;
+
+/**
+ *
+ * @author vramik
+ */
+public class MailServerConfiguration {
+ public static final String FROM = "server@mail.test";
+ public static final String HOST = "localhost";
+ public static final String PORT = "3025";
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Timer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Timer.java
new file mode 100644
index 0000000..0ce7eda
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Timer.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.util;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class Timer {
+
+ private static Long time;
+
+ private static final Map<String, List<Long>> stats = new HashMap<>();
+
+ public static void time() {
+ time = new Date().getTime();
+ }
+
+ public static void time(String operation) {
+ if (time == null) {
+ System.out.println(MessageFormat.format("Starting timer for operation {0}", operation));
+ time();
+ } else {
+ long timeOrig = time;
+ time();
+ logOperation(operation, time - timeOrig);
+ System.out.println(MessageFormat.format("Operation {0} took {1} ms", operation, time - timeOrig));
+ }
+ }
+
+ private static void logOperation(String operation, long delta) {
+ if (!stats.containsKey(operation)) {
+ stats.put(operation, new ArrayList<Long>());
+ }
+ stats.get(operation).add(delta);
+ }
+
+ public static void printStats() {
+ if (!stats.isEmpty()) {
+ System.out.println("OPERATION STATS:");
+ }
+ for (String op : stats.keySet()) {
+ long sum = 0;
+ for (Long t : stats.get(op)) {
+ sum += t;
+ }
+ System.out.println(MessageFormat.format("Operation {0} average time: {1,number,#} ms", op, sum / stats.get(op).size()));
+ }
+ stats.clear();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/testsuite/integration-arquillian/tests/base/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
new file mode 100644
index 0000000..88c25fa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
@@ -0,0 +1,3 @@
+org.keycloak.testsuite.arquillian.KeycloakArquillianExtension
+!org.jboss.arquillian.container.impl.ContainerExtension
+org.keycloak.testsuite.arquillian.containers.MultipleContainersExtension
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java
new file mode 100644
index 0000000..98aa62e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java
@@ -0,0 +1,104 @@
+package org.keycloak.testsuite;
+
+import java.text.MessageFormat;
+import java.util.List;
+import org.jboss.arquillian.graphene.findby.FindByJQuery;
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.keycloak.admin.client.resource.RealmResource;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.login.OIDCLogin;
+import org.keycloak.testsuite.console.page.fragment.FlashMessage;
+import org.openqa.selenium.Cookie;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractAuthTest extends AbstractKeycloakTest {
+
+ @Page
+ protected AuthRealm testRealmPage;
+ @Page
+ protected OIDCLogin testRealmLoginPage;
+
+ protected UserRepresentation testUser;
+
+ @FindByJQuery(".alert")
+ protected FlashMessage flashMessage;
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ RealmRepresentation testRealmRep = new RealmRepresentation();
+ testRealmRep.setRealm(TEST);
+ testRealmRep.setEnabled(true);
+ testRealms.add(testRealmRep);
+ }
+
+ @Before
+ public void beforeAuthTest() {
+ testRealmLoginPage.setAuthRealm(testRealmPage);
+
+ testUser = createUserRepresentation("test", "test@email.test", "test", "user", true);
+ setPasswordFor(testUser, PASSWORD);
+
+ deleteAllCookiesForTestRealm();
+ }
+
+ public void createTestUserWithAdminClient() {
+ log.debug("creating test user");
+ String id = createUserAndResetPasswordWithAdminClient(testRealmResource(), testUser, PASSWORD);
+ testUser.setId(id);
+ }
+
+ public static UserRepresentation createUserRepresentation(String username, String email, String firstName, String lastName, boolean enabled) {
+ UserRepresentation user = new UserRepresentation();
+ user.setUsername(username);
+ user.setEmail(email);
+ user.setFirstName(firstName);
+ user.setLastName(lastName);
+ user.setEnabled(enabled);
+ return user;
+ }
+
+ public void deleteAllCookiesForTestRealm() {
+ testRealmPage.navigateTo();
+ log.debug("deleting cookies in test realm");
+ driver.manage().deleteAllCookies();
+ }
+
+ public void listCookies() {
+ log.info("LIST OF COOKIES: ");
+ for (Cookie c : driver.manage().getCookies()) {
+ log.info(MessageFormat.format(" {1} {2} {0}",
+ c.getName(), c.getDomain(), c.getPath(), c.getValue()));
+ }
+ }
+
+ public void assertFlashMessageSuccess() {
+ flashMessage.waitUntilPresent();
+ assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+ }
+
+ public void assertFlashMessageDanger() {
+ flashMessage.waitUntilPresent();
+ assertTrue(flashMessage.getText(), flashMessage.isDanger());
+ }
+
+ public void assertFlashMessageError() {
+ flashMessage.waitUntilPresent();
+ assertTrue(flashMessage.getText(), flashMessage.isError());
+ }
+
+ public RealmResource testRealmResource() {
+ return adminClient.realm(testRealmPage.getAuthRealm());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
new file mode 100644
index 0000000..3399115
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -0,0 +1,176 @@
+package org.keycloak.testsuite;
+
+import org.keycloak.testsuite.arquillian.TestContext;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import javax.ws.rs.NotFoundException;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.logging.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import org.keycloak.testsuite.arquillian.SuiteContext;
+import org.openqa.selenium.WebDriver;
+import org.keycloak.testsuite.auth.page.AuthServer;
+import org.keycloak.testsuite.auth.page.AuthServerContextRoot;
+import static org.keycloak.testsuite.util.URLAssert.*;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
+import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
+import org.keycloak.testsuite.auth.page.account.Account;
+import org.keycloak.testsuite.auth.page.login.OIDCLogin;
+import org.keycloak.testsuite.auth.page.login.UpdatePassword;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@RunWith(Arquillian.class)
+@RunAsClient
+public abstract class AbstractKeycloakTest {
+
+ protected Logger log = Logger.getLogger(this.getClass());
+
+ @ArquillianResource
+ protected SuiteContext suiteContext;
+
+ @ArquillianResource
+ protected TestContext testContext;
+
+ @ArquillianResource
+ protected Keycloak adminClient;
+
+ protected List<RealmRepresentation> testRealmReps;
+
+ @Drone
+ protected WebDriver driver;
+
+ @Page
+ protected AuthServerContextRoot authServerContextRootPage;
+ @Page
+ protected AuthServer authServerPage;
+
+ @Page
+ protected AuthRealm masterRealmPage;
+
+ @Page
+ protected Account accountPage;
+ @Page
+ protected OIDCLogin loginPage;
+ @Page
+ protected UpdatePassword updatePasswordPage;
+
+ protected UserRepresentation adminUser;
+
+ @Before
+ public void beforeAbstractKeycloakTest() {
+ adminUser = createAdminUserRepresentation();
+
+ setDefaultPageUriParameters();
+
+ driverSettings();
+
+ if (!suiteContext.isAdminPasswordUpdated()) {
+ updateMasterAdminPassword();
+ suiteContext.setAdminPasswordUpdated(true);
+ }
+
+ importTestRealms();
+ }
+
+ @After
+ public void afterAbstractKeycloakTest() {
+// removeTestRealms(); // keeping test realms after test to be able to inspect failures, instead deleting existing realms before import
+// keycloak.close(); // keeping admin connection open
+ Timer.printStats();
+ }
+
+ private void updateMasterAdminPassword() {
+ accountPage.navigateTo();
+ loginPage.form().login(ADMIN, ADMIN);
+ updatePasswordPage.updatePasswords(ADMIN, ADMIN);
+ assertCurrentUrlStartsWith(accountPage);
+ deleteAllCookiesForMasterRealm();
+ }
+
+ public void deleteAllCookiesForMasterRealm() {
+ masterRealmPage.navigateTo();
+ log.debug("deleting cookies in master realm");
+ driver.manage().deleteAllCookies();
+ }
+
+ protected void driverSettings() {
+ driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
+ driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
+ driver.manage().timeouts().setScriptTimeout(3, TimeUnit.SECONDS);
+ driver.manage().window().maximize();
+ }
+
+ public void setDefaultPageUriParameters() {
+ masterRealmPage.setAuthRealm(MASTER);
+ loginPage.setAuthRealm(MASTER);
+ }
+
+ public abstract void addTestRealms(List<RealmRepresentation> testRealms);
+
+ private void addTestRealms() {
+ log.debug("loading test realms");
+ if (testRealmReps == null) {
+ testRealmReps = new ArrayList<>();
+ }
+ if (testRealmReps.isEmpty()) {
+ addTestRealms(testRealmReps);
+ }
+ }
+
+ public void importTestRealms() {
+ addTestRealms();
+ log.info("importing test realms");
+ for (RealmRepresentation testRealm : testRealmReps) {
+ importRealm(testRealm);
+ }
+ }
+
+ public void removeTestRealms() {
+ log.info("removing test realms");
+ for (RealmRepresentation testRealm : testRealmReps) {
+ removeRealm(testRealm);
+ }
+ }
+
+ private UserRepresentation createAdminUserRepresentation() {
+ UserRepresentation adminUserRep = new UserRepresentation();
+ adminUserRep.setUsername(ADMIN);
+ setPasswordFor(adminUserRep, ADMIN);
+ return adminUserRep;
+ }
+
+ public void importRealm(RealmRepresentation realm) {
+ log.debug("importing realm: " + realm.getRealm());
+ try { // TODO - figure out a way how to do this without try-catch
+ RealmResource realmResource = adminClient.realms().realm(realm.getRealm());
+ RealmRepresentation rRep = realmResource.toRepresentation();
+ log.debug("realm already exists on server, re-importing");
+ realmResource.remove();
+ } catch (NotFoundException nfe) {
+ // expected when realm does not exist
+ }
+ adminClient.realms().create(realm);
+ }
+
+ public void removeRealm(RealmRepresentation realm) {
+ adminClient.realms().realm(realm.getRealm()).remove();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AbstractAccountManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AbstractAccountManagementTest.java
new file mode 100644
index 0000000..6a7a4c1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AbstractAccountManagementTest.java
@@ -0,0 +1,31 @@
+package org.keycloak.testsuite.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.testsuite.AbstractAuthTest;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.account.AccountManagement;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractAccountManagementTest extends AbstractAuthTest {
+
+ @Page
+ protected AccountManagement testRealmAccountManagementPage;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(TEST);
+ testRealmAccountManagementPage.setAuthRealm(TEST);
+ }
+
+ @Before
+ public void beforeAbstractAccountTest() {
+ // make user test user exists in test realm
+ createTestUserWithAdminClient();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
new file mode 100644
index 0000000..e509276
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -0,0 +1,80 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.After;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.keycloak.testsuite.auth.page.account.Account;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class AccountTest extends AbstractAccountManagementTest {
+
+ private static final String UPDATED_EMAIL = "new-name@email.test";
+ private static final String NEW_FIRST_NAME = "John";
+ private static final String NEW_LAST_NAME = "Smith";
+
+ @Page
+ private Account testRealmAccountPage;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmAccountPage.setAuthRealm(testRealmPage);
+ }
+
+ @Before
+ public void beforeAccountTest() {
+ testRealmAccountManagementPage.navigateTo();
+ testRealmLoginPage.form().login(testUser);
+ }
+
+ @After
+ public void afterAccountTest() {
+ testRealmAccountManagementPage.navigateTo();
+ testRealmAccountManagementPage.signOut();
+ }
+
+ @Test
+ public void editAccount() {
+ testRealmAccountManagementPage.account();
+ assertEquals(testRealmAccountPage.getUsername(), testUser.getUsername());
+
+ testRealmAccountPage.setEmail(UPDATED_EMAIL);
+ testRealmAccountPage.setFirstName(NEW_FIRST_NAME);
+ testRealmAccountPage.setLastName(NEW_LAST_NAME);
+ testRealmAccountPage.save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountManagementPage.signOut();
+ testRealmLoginPage.form().login(testUser);
+
+ testRealmAccountManagementPage.account();
+ assertEquals(testRealmAccountPage.getEmail(), UPDATED_EMAIL);
+ assertEquals(testRealmAccountPage.getFirstName(), NEW_FIRST_NAME);
+ assertEquals(testRealmAccountPage.getLastName(), NEW_LAST_NAME);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ChangePasswordTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ChangePasswordTest.java
new file mode 100644
index 0000000..5787903
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ChangePasswordTest.java
@@ -0,0 +1,67 @@
+package org.keycloak.testsuite.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.auth.page.account.ChangePassword;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class ChangePasswordTest extends AbstractAccountManagementTest {
+
+ private static final String NEW_PASSWORD = "newpassword";
+ private static final String WRONG_PASSWORD = "wrongpassword";
+
+ @Page
+ private ChangePassword testRealmChangePasswordPage;
+
+ private String correctPassword;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmChangePasswordPage.setAuthRealm(testRealmPage);
+ }
+
+ @Before
+ public void beforeChangePasswordTest() {
+ correctPassword = getPasswordOf(testUser);
+ testRealmAccountManagementPage.navigateTo();
+ testRealmLoginPage.form().login(testUser);
+ testRealmAccountManagementPage.password();
+ }
+
+ @Test
+ public void invalidChangeAttempts() {
+ testRealmChangePasswordPage.save();
+ assertFlashMessageError();
+
+ testRealmChangePasswordPage.changePasswords(WRONG_PASSWORD, NEW_PASSWORD, NEW_PASSWORD);
+ assertFlashMessageError();
+
+ testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD + "-mismatch");
+ assertFlashMessageError();
+ }
+
+ @Test
+ public void successfulChangeAttempts() {
+ // change password successfully
+ testRealmChangePasswordPage.changePasswords(correctPassword, NEW_PASSWORD, NEW_PASSWORD);
+ assertFlashMessageSuccess();
+
+ // login using new password
+ testRealmAccountManagementPage.signOut();
+ testRealmLoginPage.form().login(testUser.getUsername(), NEW_PASSWORD);
+ assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+
+ // change password back
+ testRealmAccountManagementPage.password();
+ testRealmChangePasswordPage.changePasswords(NEW_PASSWORD, correctPassword, correctPassword);
+ assertFlashMessageSuccess();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/RegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/RegistrationTest.java
new file mode 100644
index 0000000..5297038
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/RegistrationTest.java
@@ -0,0 +1,132 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+import org.keycloak.testsuite.auth.page.login.Registration;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
+import static org.keycloak.testsuite.admin.Users.getPasswordOf;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class RegistrationTest extends AbstractAccountManagementTest {
+
+ @Page
+ private Registration testRealmRegistrationPage;
+
+ private UserRepresentation newUser;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmRegistrationPage.setAuthRealm(testRealmPage);
+ }
+
+ @Before
+ public void beforeUserRegistration() {
+ // enable user registration in test realm
+ RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+ testRealmRep.setRegistrationAllowed(true);
+ testRealmResource().update(testRealmRep);
+
+ newUser = createUserRepresentation("new_user", "new_user@email.test", "new", "user", true);
+ setPasswordFor(newUser, PASSWORD);
+
+ testRealmAccountManagementPage.navigateTo();
+ testRealmLoginPage.form().register();
+ }
+
+ public void assertUserExistsWithAdminClient(UserRepresentation user) {
+ assertNotNull(findUserByUsername(testRealmResource(), user.getUsername()));
+ }
+
+ public void assertUserDoesntExistWithAdminClient(UserRepresentation user) {
+ assertNull(findUserByUsername(testRealmResource(), user.getUsername()));
+ }
+
+ public void assertMessageAttributeMissing(String attributeName) {
+ assertTrue(testRealmRegistrationPage.getFeedbackText()
+ .contains("Please specify " + attributeName + "."));
+ }
+
+ @Test
+ public void successfulRegistration() {
+ testRealmRegistrationPage.register(newUser);
+ assertUserExistsWithAdminClient(newUser);
+ }
+
+ @Test
+ public void invalidEmail() {
+ newUser.setEmail("invalid.email.value");
+ testRealmRegistrationPage.register(newUser);
+ assertTrue(testRealmRegistrationPage.getFeedbackText()
+ .equals("Invalid email address."));
+ assertUserDoesntExistWithAdminClient(newUser);
+ }
+
+ @Test
+ public void emptyAttributes() {
+ UserRepresentation newUserEmpty = new UserRepresentation(); // empty user attributes
+
+ testRealmRegistrationPage.register(newUserEmpty);
+ assertMessageAttributeMissing("username");
+
+ newUserEmpty.setUsername(newUser.getUsername());
+ testRealmRegistrationPage.register(newUserEmpty);
+ assertMessageAttributeMissing("first name");
+
+ newUserEmpty.setFirstName(newUser.getFirstName());
+ testRealmRegistrationPage.register(newUserEmpty);
+ assertMessageAttributeMissing("last name");
+
+ newUserEmpty.setLastName(newUser.getLastName());
+ testRealmRegistrationPage.register(newUserEmpty);
+ assertMessageAttributeMissing("email");
+
+ newUserEmpty.setEmail(newUser.getEmail());
+ testRealmRegistrationPage.register(newUserEmpty);
+ assertMessageAttributeMissing("password");
+
+ setPasswordFor(newUserEmpty, getPasswordOf(newUser));
+ testRealmRegistrationPage.register(newUser);
+ assertUserExistsWithAdminClient(newUserEmpty);
+ }
+
+ @Test
+ public void notMatchingPasswords() {
+ testRealmRegistrationPage.setValues(newUser, "not-matching-password");
+ testRealmRegistrationPage.submit();
+ assertTrue(testRealmRegistrationPage.getFeedbackText()
+ .equals("Password confirmation doesn't match."));
+
+ testRealmRegistrationPage.register(newUser);
+ assertUserExistsWithAdminClient(newUser);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResetCredentialsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResetCredentialsTest.java
new file mode 100644
index 0000000..95bff41
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResetCredentialsTest.java
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.AfterClass;
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.login.ResetCredentials;
+import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl;
+import org.keycloak.testsuite.util.MailServer;
+import org.keycloak.testsuite.util.MailServerConfiguration;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+
+/**
+ *
+ * @author vramik
+ */
+public class ResetCredentialsTest extends AbstractAccountManagementTest {
+
+ @Page
+ private ResetCredentials testRealmResetCredentialsPage;
+
+ private static boolean init = false;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmResetCredentialsPage.setAuthRealm(testRealmPage);
+ }
+
+ @Before
+ public void beforeResetCredentials() {
+ // enable reset credentials and configure smpt server in test realm
+ RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+ testRealmRep.setSmtpServer(suiteContext.getSmtpServer());
+ testRealmRep.setResetPasswordAllowed(true);
+ testRealmResource().update(testRealmRep);
+
+ if (!init) {
+ init = true;
+ MailServer.start();
+ MailServer.createEmailAccount(testUser.getEmail(), "password");
+ }
+
+ testRealmAccountManagementPage.navigateTo();
+ testRealmLoginPage.form().forgotPassword();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ MailServer.stop();
+ }
+
+ @Test
+ public void resetCredentialsWithEmail() {
+ testRealmResetCredentialsPage.resetCredentials(testUser.getEmail());
+ resetCredentialsAndLoginWithNewPassword();
+ }
+
+ @Test
+ public void resetCredentialsWithUsername() {
+ testRealmResetCredentialsPage.resetCredentials(testUser.getUsername());
+ resetCredentialsAndLoginWithNewPassword();
+ }
+
+ private void resetCredentialsAndLoginWithNewPassword() {
+ assertEquals("You should receive an email shortly with further instructions.",
+ testRealmResetCredentialsPage.getFeedbackText());
+
+ String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, testUser.getEmail(),
+ "Someone just requested to change your Test account's credentials.");
+
+ log.info("navigating to " + url);
+ driver.navigate().to(url);
+ assertCurrentUrlStartsWith(testRealmResetCredentialsPage);
+ testRealmResetCredentialsPage.updatePassword("newPassword");
+ assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+ testRealmAccountManagementPage.signOut();
+ testRealmLoginPage.form().login("test", "newPassword");
+ assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/VerifyEmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/VerifyEmailTest.java
new file mode 100644
index 0000000..59e08cc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/VerifyEmailTest.java
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.AfterClass;
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.login.VerifyEmail;
+import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl;
+import org.keycloak.testsuite.util.MailServer;
+import org.keycloak.testsuite.util.MailServerConfiguration;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+
+/**
+ *
+ * @author vramik
+ */
+public class VerifyEmailTest extends AbstractAccountManagementTest {
+
+ @Page
+ private VerifyEmail testRealmVerifyEmailPage;
+
+ private static boolean init = false;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmVerifyEmailPage.setAuthRealm(testRealmPage);
+ }
+
+ @Before
+ public void beforeVerifyEmail() {
+ // enable verify email and configure smpt server in test realm
+ RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+ testRealmRep.setSmtpServer(suiteContext.getSmtpServer());
+ testRealmRep.setVerifyEmail(true);
+ testRealmResource().update(testRealmRep);
+
+ if (!init) {
+ init = true;
+ MailServer.start();
+ MailServer.createEmailAccount(testUser.getEmail(), "password");
+ }
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ MailServer.stop();
+ }
+
+ @Test
+ public void verifyEmail() {
+ testRealmAccountManagementPage.navigateTo();
+ testRealmLoginPage.form().login(testUser);
+
+ assertEquals("You need to verify your email address to activate your account.",
+ testRealmVerifyEmailPage.getFeedbackText());
+
+ String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, testUser.getEmail(),
+ "Someone has created a Test account with this email address.");
+
+ log.info("navigating to " + url);
+ driver.navigate().to(url);
+ assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+ testRealmAccountManagementPage.signOut();
+ testRealmLoginPage.form().login(testUser);
+ assertCurrentUrlStartsWith(testRealmAccountManagementPage);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
new file mode 100644
index 0000000..73ea7a6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java
@@ -0,0 +1,139 @@
+package org.keycloak.testsuite.adapter;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractAuthTest;
+import org.keycloak.testsuite.arquillian.ContainersTestEnricher;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+import org.keycloak.testsuite.adapter.page.AppServerContextRoot;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer
+public abstract class AbstractAdapterTest extends AbstractAuthTest {
+
+ @Page
+ protected AppServerContextRoot appServerContextRootPage;
+
+ public static final String JBOSS_DEPLOYMENT_STRUCTURE_XML = "jboss-deployment-structure.xml";
+ public static final URL jbossDeploymentStructure = AbstractServletsAdapterTest.class
+ .getResource("/adapter-test/" + JBOSS_DEPLOYMENT_STRUCTURE_XML);
+ public static final String TOMCAT_CONTEXT_XML = "context.xml";
+ public static final URL tomcatContext = AbstractServletsAdapterTest.class
+ .getResource("/adapter-test/" + TOMCAT_CONTEXT_XML);
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ addAdapterTestRealms(testRealms);
+ for (RealmRepresentation tr : testRealms) {
+ log.info("Setting redirect-uris in test realm '" + tr.getRealm() + "' as " + (isRelative() ? "" : "non-") + "relative");
+
+ modifyClientRedirectUris(tr, "http://localhost:8080", "");
+ modifyClientUrls(tr, "http://localhost:8080", "");
+
+ if (isRelative()) {
+ modifyClientRedirectUris(tr, appServerContextRootPage.toString(), "");
+ modifyClientUrls(tr, appServerContextRootPage.toString(), "");
+ modifyClientWebOrigins(tr, "8080", System.getProperty("auth.server.http.port", null));
+ } else {
+ modifyClientRedirectUris(tr, "^(/.*/\\*)", appServerContextRootPage.toString() + "$1");
+ modifyClientUrls(tr, "^(/.*)", appServerContextRootPage.toString() + "$1");
+ }
+ }
+ }
+
+ public abstract void addAdapterTestRealms(List<RealmRepresentation> testRealms);
+
+ public boolean isRelative() {
+ return ContainersTestEnricher.isRelative(this.getClass());
+ }
+
+ protected void modifyClientRedirectUris(RealmRepresentation realm, String regex, String replacement) {
+ for (ClientRepresentation client : realm.getClients()) {
+ List<String> redirectUris = client.getRedirectUris();
+ if (redirectUris != null) {
+ List<String> newRedirectUris = new ArrayList<>();
+ for (String uri : redirectUris) {
+ newRedirectUris.add(uri.replaceAll(regex, replacement));
+ }
+ client.setRedirectUris(newRedirectUris);
+ }
+ }
+ }
+
+ protected void modifyClientUrls(RealmRepresentation realm, String regex, String replacement) {
+ for (ClientRepresentation client : realm.getClients()) {
+ String baseUrl = client.getBaseUrl();
+ if (baseUrl != null) {
+ client.setBaseUrl(baseUrl.replaceAll(regex, replacement));
+ }
+ String adminUrl = client.getAdminUrl();
+ if (adminUrl != null) {
+ client.setAdminUrl(adminUrl.replaceAll(regex, replacement));
+ }
+ }
+ }
+
+ protected void modifyClientWebOrigins(RealmRepresentation realm, String regex, String replacement) {
+ for (ClientRepresentation client : realm.getClients()) {
+ List<String> webOrigins = client.getWebOrigins();
+ if (webOrigins != null) {
+ List<String> newWebOrigins = new ArrayList<>();
+ for (String uri : webOrigins) {
+ newWebOrigins.add(uri.replaceAll(regex, replacement));
+ }
+ client.setWebOrigins(newWebOrigins);
+ }
+ }
+ }
+
+ /**
+ * Modifies baseUrl, adminUrl and redirectUris for client based on real
+ * deployment url of the app.
+ *
+ * @param realm
+ * @param clientId
+ * @param deploymentUrl
+ */
+ protected void fixClientUrisUsingDeploymentUrl(RealmRepresentation realm, String clientId, String deploymentUrl) {
+ for (ClientRepresentation client : realm.getClients()) {
+ if (clientId.equals(client.getClientId())) {
+ if (client.getBaseUrl() != null) {
+ client.setBaseUrl(deploymentUrl);
+ }
+ if (client.getAdminUrl() != null) {
+ client.setAdminUrl(deploymentUrl);
+ }
+ List<String> redirectUris = client.getRedirectUris();
+ if (redirectUris != null) {
+ List<String> newRedirectUris = new ArrayList<>();
+ for (String uri : redirectUris) {
+ newRedirectUris.add(deploymentUrl + "/*");
+ }
+ client.setRedirectUris(newRedirectUris);
+ }
+ }
+ }
+ }
+
+ public static void addContextXml(Archive archive, String contextPath) {
+ try {
+ String contextXmlContent = IOUtils.toString(tomcatContext.openStream())
+ .replace("%CONTEXT_PATH%", contextPath);
+ archive.add(new StringAsset(contextXmlContent), "/META-INF/context.xml");
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java
new file mode 100644
index 0000000..defb866
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java
@@ -0,0 +1,62 @@
+package org.keycloak.testsuite.adapter;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.IOUtils;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractExampleAdapterTest extends AbstractAdapterTest {
+
+ public static final String EXAMPLES_HOME;
+ public static final String EXAMPLES_VERSION_SUFFIX;
+ public static final String EXAMPLES_HOME_DIR;
+ public static final String EXAMPLES_WEB_XML;
+
+ static {
+ EXAMPLES_HOME = System.getProperty("examples.home", null);
+ Assert.assertNotNull("Property ${examples.home} must bet set.", EXAMPLES_HOME);
+ System.out.println(EXAMPLES_HOME);
+
+ EXAMPLES_VERSION_SUFFIX = System.getProperty("examples.version.suffix", null);
+ Assert.assertNotNull("Property ${examples.version.suffix} must bet set.", EXAMPLES_VERSION_SUFFIX);
+ System.out.println(EXAMPLES_VERSION_SUFFIX);
+
+ EXAMPLES_HOME_DIR = EXAMPLES_HOME + "/keycloak-examples-" + EXAMPLES_VERSION_SUFFIX;
+
+ EXAMPLES_WEB_XML = EXAMPLES_HOME + "/web.xml";
+ }
+
+ protected static WebArchive exampleDeployment(String name) throws IOException {
+ return ShrinkWrap.createFromZipFile(WebArchive.class,
+ new File(EXAMPLES_HOME + "/" + name + "-" + EXAMPLES_VERSION_SUFFIX + ".war"))
+ .addAsWebInfResource(jbossDeploymentStructure, JBOSS_DEPLOYMENT_STRUCTURE_XML);
+ }
+
+ protected static WebArchive exampleDeployment(String name, String contextPath) throws IOException {
+ URL webXML = Paths.get(EXAMPLES_WEB_XML).toUri().toURL();
+ String webXmlContent = IOUtils.toString(webXML.openStream())
+ .replace("%CONTEXT_PATH%", contextPath);
+ WebArchive webArchive = ShrinkWrap.createFromZipFile(WebArchive.class,
+ new File(EXAMPLES_HOME + "/" + name + "-" + EXAMPLES_VERSION_SUFFIX + ".war"))
+ .addAsWebInfResource(jbossDeploymentStructure, JBOSS_DEPLOYMENT_STRUCTURE_XML)
+ .add(new StringAsset(webXmlContent), "/WEB-INF/web.xml");
+ return webArchive;
+ }
+
+ protected static JavaArchive exampleJarDeployment(String name) {
+ return ShrinkWrap.createFromZipFile(JavaArchive.class,
+ new File(EXAMPLES_HOME + "/" + name + "-" + EXAMPLES_VERSION_SUFFIX + ".jar"));
+ }
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
new file mode 100644
index 0000000..7dc58c0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
@@ -0,0 +1,45 @@
+package org.keycloak.testsuite.adapter;
+
+import java.net.URL;
+import java.util.List;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.keycloak.representations.idm.RealmRepresentation;
+import static org.keycloak.testsuite.util.IOUtil.*;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+
+public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
+
+ protected static WebArchive servletDeployment(String name, Class... servletClasses) {
+ return servletDeployment(name, "keycloak.json", servletClasses);
+ }
+
+ protected static WebArchive servletDeployment(String name, String adapterConfig, Class... servletClasses) {
+ String webInfPath = "/adapter-test/" + name + "/WEB-INF/";
+
+ URL keycloakJSON = AbstractServletsAdapterTest.class.getResource(webInfPath + adapterConfig);
+ URL webXML = AbstractServletsAdapterTest.class.getResource(webInfPath + "web.xml");
+
+ WebArchive deployment = ShrinkWrap.create(WebArchive.class, name + ".war")
+ .addClasses(servletClasses)
+ .addAsWebInfResource(webXML, "web.xml")
+ .addAsWebInfResource(keycloakJSON, "keycloak.json")
+ .addAsWebInfResource(jbossDeploymentStructure, JBOSS_DEPLOYMENT_STRUCTURE_XML);
+
+ addContextXml(deployment, name);
+
+ return deployment;
+ }
+
+ @Override
+ public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+ testRealms.add(loadRealm("/adapter-test/demorealm.json"));
+ }
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(DEMO);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractBasicAuthExampleAdapterTest.java
new file mode 100644
index 0000000..8a592d9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractBasicAuthExampleAdapterTest.java
@@ -0,0 +1,68 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.Response;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import org.keycloak.testsuite.adapter.page.BasicAuthExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.EXAMPLE;
+
+public abstract class AbstractBasicAuthExampleAdapterTest extends AbstractExampleAdapterTest {
+
+ @Page
+ private BasicAuthExample basicAuthExample;
+
+ @Deployment(name = BasicAuthExample.DEPLOYMENT_NAME)
+ private static WebArchive basicAuthExample() throws IOException {
+ return exampleDeployment("examples-basicauth");
+ }
+
+ @Override
+ public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+ testRealms.add(loadRealm(new File(EXAMPLES_HOME_DIR + "/basic-auth/basicauthrealm.json")));
+ }
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(EXAMPLE);
+ }
+
+ @Test
+ public void testBasicAuthExample() {
+ String value = "hello";
+ Client client = ClientBuilder.newClient();
+
+ Response response = client.target(basicAuthExample
+ .setTemplateValues("admin", "password", value).buildUri()).request().get();
+ assertEquals(200, response.getStatus());
+ assertEquals(value, response.readEntity(String.class));
+ response.close();
+
+ response = client.target(basicAuthExample
+ .setTemplateValues("invalid-user", "password", value).buildUri()).request().get();
+ assertEquals(401, response.getStatus());
+ assertTrue(response.readEntity(String.class).contains("Unauthorized"));
+ response.close();
+
+ response = client.target(basicAuthExample
+ .setTemplateValues("admin", "invalid-password", value).buildUri()).request().get();
+ assertEquals(401, response.getStatus());
+ assertTrue(response.readEntity(String.class).contains("Unauthorized"));
+ response.close();
+
+ client.close();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java
new file mode 100644
index 0000000..72db4bb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java
@@ -0,0 +1,105 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import org.keycloak.testsuite.adapter.page.AngularCorsProductExample;
+import org.keycloak.testsuite.adapter.page.CorsDatabaseServiceExample;
+import org.keycloak.testsuite.arquillian.jira.Jira;
+import org.keycloak.testsuite.auth.page.account.Account;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ * Created by fkiss.
+ */
+public abstract class AbstractCorsExampleAdapterTest extends AbstractExampleAdapterTest {
+
+ public static final String CORS = "cors";
+
+ @Page
+ private AngularCorsProductExample angularCorsProductExample;
+
+ @Page
+ private Account testRealmAccount;
+
+ @Deployment(name = AngularCorsProductExample.DEPLOYMENT_NAME)
+ private static WebArchive angularCorsProductExample() throws IOException {
+ return exampleDeployment(AngularCorsProductExample.DEPLOYMENT_NAME, "angular-cors-product");
+ }
+
+ @Deployment(name = CorsDatabaseServiceExample.DEPLOYMENT_NAME)
+ private static WebArchive corsDatabaseServiceExample() throws IOException {
+ return exampleDeployment("database-service");
+ }
+
+ @Override
+ public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+ testRealms.add(
+ loadRealm(new File(EXAMPLES_HOME_DIR + "/cors/cors-realm.json")));
+ }
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(CORS);
+ testRealmLoginPage.setAuthRealm(CORS);
+ testRealmAccount.setAuthRealm(CORS);
+ }
+
+ @Before
+ public void beforeDemoExampleTest() {
+ angularCorsProductExample.navigateTo();
+ driver.manage().deleteAllCookies();
+ }
+
+ @Jira("KEYCLOAK-1546")
+ @Test
+ public void angularCorsProductTest() {
+ angularCorsProductExample.navigateTo();
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+ assertCurrentUrlStartsWith(angularCorsProductExample);
+ angularCorsProductExample.reloadData();
+ Assert.assertTrue(driver.getPageSource().contains("Product Listing"));
+ Assert.assertTrue(driver.getPageSource().contains("iphone"));
+ Assert.assertTrue(driver.getPageSource().contains("ipad"));
+ Assert.assertTrue(driver.getPageSource().contains("ipod"));
+
+ angularCorsProductExample.loadRoles();
+ Assert.assertTrue(driver.getPageSource().contains("Role Listing"));
+ Assert.assertTrue(driver.getPageSource().contains("user"));
+
+ angularCorsProductExample.addRole();
+ Assert.assertTrue(driver.getPageSource().contains("stuff"));
+
+ angularCorsProductExample.deleteRole();
+ Assert.assertFalse(driver.getPageSource().contains("stuff"));
+
+ angularCorsProductExample.loadAvailableSocialProviders();
+ Assert.assertTrue(driver.getPageSource().contains("Available social providers"));
+ Assert.assertTrue(driver.getPageSource().contains("twitter"));
+ Assert.assertTrue(driver.getPageSource().contains("google"));
+ Assert.assertTrue(driver.getPageSource().contains("linkedin"));
+ Assert.assertTrue(driver.getPageSource().contains("facebook"));
+ Assert.assertTrue(driver.getPageSource().contains("stackoverflow"));
+ Assert.assertTrue(driver.getPageSource().contains("github"));
+
+ angularCorsProductExample.loadPublicRealmInfo();
+ Assert.assertTrue(driver.getPageSource().contains("Realm name: cors"));
+
+ angularCorsProductExample.loadVersion();
+ Assert.assertTrue(driver.getPageSource().contains("Keycloak version: "));
+
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java
new file mode 100644
index 0000000..d31d390
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractDemoExampleAdapterTest.java
@@ -0,0 +1,157 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.*;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.account.Account;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import org.keycloak.testsuite.adapter.page.CustomerPortalExample;
+import org.keycloak.testsuite.adapter.page.DatabaseServiceExample;
+import org.keycloak.testsuite.adapter.page.ProductPortalExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+import org.openqa.selenium.By;
+
+public abstract class AbstractDemoExampleAdapterTest extends AbstractExampleAdapterTest {
+
+ @Page
+ private CustomerPortalExample customerPortalExample;
+ @Page
+ private ProductPortalExample productPortalExample;
+ @Page
+ private DatabaseServiceExample databaseServiceExample;
+
+ @Page
+ private Account testRealmAccount;
+
+ @Deployment(name = CustomerPortalExample.DEPLOYMENT_NAME)
+ private static WebArchive customerPortalExample() throws IOException {
+ return exampleDeployment(CustomerPortalExample.DEPLOYMENT_NAME);
+ }
+
+ @Deployment(name = ProductPortalExample.DEPLOYMENT_NAME)
+ private static WebArchive productPortalExample() throws IOException {
+ return exampleDeployment(ProductPortalExample.DEPLOYMENT_NAME);
+ }
+
+ @Deployment(name = DatabaseServiceExample.DEPLOYMENT_NAME)
+ private static WebArchive databaseServiceExample() throws IOException {
+ return exampleDeployment("database-service");
+ }
+
+ @Override
+ public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+ testRealms.add(
+ loadRealm(new File(EXAMPLES_HOME_DIR + "/preconfigured-demo/testrealm.json")));
+ }
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(DEMO);
+ testRealmLoginPage.setAuthRealm(DEMO);
+ testRealmAccount.setAuthRealm(DEMO);
+ }
+
+ @Before
+ public void beforeDemoExampleTest() {
+ customerPortalExample.navigateTo();
+ driver.manage().deleteAllCookies();
+ productPortalExample.navigateTo();
+ driver.manage().deleteAllCookies();
+ }
+
+ @Test
+ public void customerPortalListingTest() {
+
+ customerPortalExample.navigateTo();
+ customerPortalExample.customerListing();
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+ assertCurrentUrlStartsWith(customerPortalExample);
+ customerPortalExample.waitForCustomerListingHeader();
+
+ Assert.assertTrue(driver.getPageSource().contains("Username: bburke@redhat.com"));
+ Assert.assertTrue(driver.getPageSource().contains("Bill Burke"));
+ Assert.assertTrue(driver.getPageSource().contains("Stian Thorgersen"));
+ }
+
+ @Test
+ public void customerPortalSessionTest() {
+
+ customerPortalExample.navigateTo();
+ customerPortalExample.customerSession();
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+ assertCurrentUrlStartsWith(customerPortalExample);
+
+ customerPortalExample.waitForCustomerSessionHeader();
+ Assert.assertTrue(driver.getPageSource().contains("You visited this page"));
+ }
+
+ @Test
+ public void productPortalListingTest() {
+
+ productPortalExample.navigateTo();
+ productPortalExample.productListing();
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+ assertCurrentUrlStartsWith(productPortalExample);
+ productPortalExample.waitForProductListingHeader();
+
+ Assert.assertTrue(driver.getPageSource().contains("iphone"));
+ Assert.assertTrue(driver.getPageSource().contains("ipad"));
+ Assert.assertTrue(driver.getPageSource().contains("ipod"));
+
+ productPortalExample.goToCustomers();
+ }
+
+ @Test
+ public void goToProductPortalWithOneLoginTest() {
+
+ productPortalExample.navigateTo();
+ productPortalExample.productListing();
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+ assertCurrentUrlStartsWith(productPortalExample);
+ productPortalExample.waitForProductListingHeader();
+ productPortalExample.goToCustomers();
+
+ assertCurrentUrlStartsWith(customerPortalExample);
+ customerPortalExample.customerListing();
+ customerPortalExample.goToProducts();
+ assertCurrentUrlStartsWith(productPortalExample);
+ }
+
+ @Test
+ public void logoutFromAllAppsTest() {
+
+ productPortalExample.navigateTo();
+ productPortalExample.productListing();
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+ assertCurrentUrlStartsWith(productPortalExample);
+ productPortalExample.waitForProductListingHeader();
+
+ productPortalExample.logOut();
+ assertCurrentUrlStartsWith(productPortalExample);
+ productPortalExample.productListing();
+
+ customerPortalExample.navigateTo();
+ customerPortalExample.customerListing();
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+
+ customerPortalExample.logOut();
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java
new file mode 100644
index 0000000..647b15b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java
@@ -0,0 +1,131 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.util.List;
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.auth.page.account.Account;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.adapter.AbstractExampleAdapterTest.EXAMPLES_HOME_DIR;
+import org.keycloak.testsuite.adapter.page.fuse.AdminInterface;
+import org.keycloak.testsuite.adapter.page.fuse.CustomerListing;
+import org.keycloak.testsuite.adapter.page.fuse.CustomerPortalFuseExample;
+import org.keycloak.testsuite.adapter.page.fuse.ProductPortalFuseExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractFuseExampleAdapterTest extends AbstractExampleAdapterTest {
+
+ @Page
+ protected CustomerPortalFuseExample customerPortal;
+ @Page
+ protected CustomerListing customerListing;
+ @Page
+ protected AdminInterface adminInterface;
+
+ @Page
+ protected ProductPortalFuseExample productPortal;
+
+ @Page
+ protected Account testRealmAccount;
+
+ @Override
+ public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+ RealmRepresentation fureRealm = loadRealm(new File(EXAMPLES_HOME_DIR + "/fuse/testrealm.json"));
+ testRealms.add(fureRealm);
+ }
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(DEMO);
+ testRealmLoginPage.setAuthRealm(DEMO);
+ testRealmAccount.setAuthRealm(DEMO);
+ }
+
+ // no Arquillian deployments - examples already installed by maven
+
+ @Test
+ public void testCustomerListingAndAccountManagement() {
+ customerPortal.navigateTo();
+ assertCurrentUrlStartsWith(customerPortal);
+
+ customerPortal.clickCustomerListingLink();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlStartsWith(customerListing);
+
+ String src = driver.getPageSource();
+ assertTrue(src.contains("Username: bburke@redhat.com")
+ && src.contains("Bill Burke")
+ && src.contains("Stian Thorgersen")
+ );
+
+ // account mgmt
+ customerListing.clickAccountManagement();
+
+ assertCurrentUrlStartsWith(testRealmAccount);
+ assertEquals(testRealmAccount.getUsername(), "bburke@redhat.com");
+
+ driver.navigate().back();
+ customerListing.clickLogOut();
+
+ // assert user not logged in
+ customerPortal.clickCustomerListingLink();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ }
+
+ @Test
+ public void testAdminInterface() {
+ customerPortal.navigateTo();
+ assertCurrentUrlStartsWith(customerPortal);
+
+ customerPortal.clickAdminInterfaceLink();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ testRealmLoginPage.form().login("admin", "password");
+ assertCurrentUrlStartsWith(adminInterface);
+ assertTrue(driver.getPageSource().contains("Hello admin!"));
+
+ customerListing.navigateTo();
+ customerListing.clickLogOut();
+ pause(500);
+ assertCurrentUrlStartsWith(customerPortal);
+
+ customerPortal.clickAdminInterfaceLink();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlStartsWith(adminInterface);
+ assertTrue(driver.getPageSource().contains("Status code is 403"));
+ }
+
+ @Test
+ public void testProductPortal() {
+ productPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlStartsWith(productPortal);
+
+ assertTrue(productPortal.getProduct1UnsecuredText().contains("401: Unauthorized"));
+ assertTrue(productPortal.getProduct1SecuredText().contains("Product received: id=1"));
+ assertTrue(productPortal.getProduct2SecuredText().contains("Product received: id=2"));
+
+ productPortal.clickLogOutLink();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
new file mode 100644
index 0000000..61d8efa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
@@ -0,0 +1,133 @@
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import org.keycloak.testsuite.adapter.page.JSConsoleExample;
+import static org.keycloak.testsuite.auth.page.AuthRealm.EXAMPLE;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+
+public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampleAdapterTest {
+
+ @Page
+ private JSConsoleExample jsConsoleExample;
+
+ public static int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
+
+ @Deployment(name = JSConsoleExample.DEPLOYMENT_NAME)
+ private static WebArchive jsConsoleExample() throws IOException {
+ return exampleDeployment(JSConsoleExample.CLIENT_ID);
+ }
+
+ @Override
+ public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+ RealmRepresentation jsConsoleRealm = loadRealm(new File(EXAMPLES_HOME_DIR + "/js-console/example-realm.json"));
+
+ fixClientUrisUsingDeploymentUrl(jsConsoleRealm,
+ JSConsoleExample.CLIENT_ID, jsConsoleExample.buildUri().toASCIIString());
+
+ jsConsoleRealm.setAccessTokenLifespan(30 + TOKEN_LIFESPAN_LEEWAY); // seconds
+
+ testRealms.add(jsConsoleRealm);
+ }
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(EXAMPLE);
+ }
+
+ @Test
+ public void testJSConsoleAuth() {
+ jsConsoleExample.navigateTo();
+ assertCurrentUrlStartsWith(jsConsoleExample);
+
+ pause(1000);
+
+ jsConsoleExample.logIn();
+ testRealmLoginPage.form().login("user", "invalid-password");
+ assertCurrentUrlDoesntStartWith(jsConsoleExample);
+
+ testRealmLoginPage.form().login("invalid-user", "password");
+ assertCurrentUrlDoesntStartWith(jsConsoleExample);
+
+ testRealmLoginPage.form().login("user", "password");
+ assertCurrentUrlStartsWith(jsConsoleExample);
+ assertTrue(driver.getPageSource().contains("Init Success (Authenticated)"));
+ assertTrue(driver.getPageSource().contains("Auth Success"));
+
+ pause(1000);
+
+ jsConsoleExample.logOut();
+ assertCurrentUrlStartsWith(jsConsoleExample);
+ assertTrue(driver.getPageSource().contains("Init Success (Not Authenticated)"));
+ }
+
+ @Test
+ public void testRefreshToken() {
+ jsConsoleExample.navigateTo();
+ assertCurrentUrlStartsWith(jsConsoleExample);
+
+ jsConsoleExample.refreshToken();
+ assertTrue(driver.getPageSource().contains("Failed to refresh token"));
+
+ jsConsoleExample.logIn();
+ testRealmLoginPage.form().login("user", "password");
+ assertCurrentUrlStartsWith(jsConsoleExample);
+ assertTrue(driver.getPageSource().contains("Auth Success"));
+
+ jsConsoleExample.refreshToken();
+ assertTrue(driver.getPageSource().contains("Auth Refresh Success"));
+ }
+
+ @Test
+ public void testRefreshTokenIfUnder30s() {
+ jsConsoleExample.navigateTo();
+ assertCurrentUrlStartsWith(jsConsoleExample);
+
+ jsConsoleExample.refreshToken();
+ assertTrue(driver.getPageSource().contains("Failed to refresh token"));
+
+ jsConsoleExample.logIn();
+ testRealmLoginPage.form().login("user", "password");
+ assertCurrentUrlStartsWith(jsConsoleExample);
+ assertTrue(driver.getPageSource().contains("Auth Success"));
+
+ jsConsoleExample.refreshTokenIfUnder30s();
+ assertTrue(driver.getPageSource().contains("Token not refreshed, valid for"));
+
+ pause((TOKEN_LIFESPAN_LEEWAY + 2) * 1000);
+
+ jsConsoleExample.refreshTokenIfUnder30s();
+ assertTrue(driver.getPageSource().contains("Auth Refresh Success"));
+ }
+
+ @Test
+ public void testGetProfile() {
+ jsConsoleExample.navigateTo();
+ assertCurrentUrlStartsWith(jsConsoleExample);
+
+ jsConsoleExample.getProfile();
+ assertTrue(driver.getPageSource().contains("Failed to load profile"));
+
+ jsConsoleExample.logIn();
+ testRealmLoginPage.form().login("user", "password");
+ assertCurrentUrlStartsWith(jsConsoleExample);
+ assertTrue(driver.getPageSource().contains("Auth Success"));
+
+ jsConsoleExample.getProfile();
+ assertTrue(driver.getPageSource().contains("Failed to load profile"));
+ assertTrue(driver.getPageSource().contains("\"username\": \"user\""));
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
new file mode 100644
index 0000000..38e47b7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
@@ -0,0 +1,386 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.Version;
+import org.keycloak.constants.AdapterConstants;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.adapter.page.CustomerDb;
+import org.keycloak.testsuite.adapter.page.CustomerDbErrorPage;
+import org.keycloak.testsuite.adapter.page.CustomerPortal;
+import org.keycloak.testsuite.adapter.page.InputPortal;
+import org.keycloak.testsuite.adapter.page.ProductPortal;
+import org.keycloak.testsuite.adapter.page.SecurePortal;
+import org.keycloak.testsuite.arquillian.jira.Jira;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import org.keycloak.util.BasicAuthHelper;
+import org.keycloak.util.Time;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAdapterTest {
+
+ @Page
+ private CustomerPortal customerPortal;
+ @Page
+ private SecurePortal securePortal;
+ @Page
+ private CustomerDb customerDb;
+ @Page
+ private CustomerDbErrorPage customerDbErrorPage;
+ @Page
+ private ProductPortal productPortal;
+ @Page
+ private InputPortal inputPortal;
+
+ @Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
+ protected static WebArchive customerPortal() {
+ return servletDeployment(CustomerPortal.DEPLOYMENT_NAME, CustomerServlet.class, ErrorServlet.class);
+ }
+
+ @Deployment(name = SecurePortal.DEPLOYMENT_NAME)
+ protected static WebArchive securePortal() {
+ return servletDeployment(SecurePortal.DEPLOYMENT_NAME, CallAuthenticatedServlet.class);
+ }
+
+ @Deployment(name = CustomerDb.DEPLOYMENT_NAME)
+ protected static WebArchive customerDb() {
+ return servletDeployment(CustomerDb.DEPLOYMENT_NAME, CustomerDatabaseServlet.class);
+ }
+
+ @Deployment(name = CustomerDbErrorPage.DEPLOYMENT_NAME)
+ protected static WebArchive customerDbErrorPage() {
+ return servletDeployment(CustomerDbErrorPage.DEPLOYMENT_NAME, CustomerDatabaseServlet.class, ErrorServlet.class);
+ }
+
+ @Deployment(name = ProductPortal.DEPLOYMENT_NAME)
+ protected static WebArchive productPortal() {
+ return servletDeployment(ProductPortal.DEPLOYMENT_NAME, ProductServlet.class);
+ }
+
+ @Deployment(name = InputPortal.DEPLOYMENT_NAME)
+ protected static WebArchive inputPortal() {
+ return servletDeployment(InputPortal.DEPLOYMENT_NAME, "keycloak.json", InputServlet.class);
+ }
+
+ @Test
+ public void testSavedPostRequest() throws InterruptedException {
+ // test login to customer-portal which does a bearer request to customer-db
+ inputPortal.navigateTo();
+ assertCurrentUrlEquals(inputPortal);
+ inputPortal.execute("hello");
+
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertEquals(driver.getCurrentUrl(), inputPortal + "/secured/post");
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("parameter=hello"));
+
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, customerPortal.toString())
+ .build("demo").toString();
+ driver.navigate().to(logoutUri);
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ productPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ customerPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ // test unsecured POST KEYCLOAK-901
+ Client client = ClientBuilder.newClient();
+ Form form = new Form();
+ form.param("parameter", "hello");
+ String text = client.target(inputPortal + "/unsecured").request().post(Entity.form(form), String.class);
+ assertTrue(text.contains("parameter=hello"));
+ client.close();
+ }
+
+ @Test
+ public void testLoginSSOAndLogout() {
+ // test login to customer-portal which does a bearer request to customer-db
+ customerPortal.navigateTo();
+ testRealmLoginPage.form().waitForUsernameInputPresent();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlEquals(customerPortal);
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+ // test SSO
+ productPortal.navigateTo();
+ assertCurrentUrlEquals(productPortal);
+ pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
+
+ // View stats
+ List<Map<String, String>> stats = testRealmResource().getClientSessionStats();
+ Map<String, String> customerPortalStats = null;
+ Map<String, String> productPortalStats = null;
+ for (Map<String, String> s : stats) {
+ switch (s.get("clientId")) {
+ case "customer-portal":
+ customerPortalStats = s;
+ break;
+ case "product-portal":
+ productPortalStats = s;
+ break;
+ }
+ }
+ assertEquals(1, Integer.parseInt(customerPortalStats.get("active")));
+ assertEquals(1, Integer.parseInt(productPortalStats.get("active")));
+
+ // test logout
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, customerPortal.toString()).build("demo").toString();
+ driver.navigate().to(logoutUri);
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ productPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ customerPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+// testRealmLoginPage.form().cancel();
+// assertTrue(driver.getPageSource().contains("Error Page"));
+ }
+
+ @Test
+ public void testServletRequestLogout() {
+ // test login to customer-portal which does a bearer request to customer-db
+ customerPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlEquals(customerPortal);
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+ // test SSO
+ productPortal.navigateTo();
+ assertCurrentUrlEquals(productPortal);
+ pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
+
+ // back
+ customerPortal.navigateTo();
+ assertCurrentUrlEquals(customerPortal);
+ pageSource = driver.getPageSource();
+ Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+ // test logout
+
+ driver.navigate().to(customerPortal + "/logout");
+ assertTrue(driver.getPageSource().contains("servlet logout ok"));
+
+ customerPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ productPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ }
+
+ @Test
+ public void testLoginSSOIdle() {
+ // test login to customer-portal which does a bearer request to customer-db
+ customerPortal.navigateTo();
+ testRealmLoginPage.form().waitForUsernameInputPresent();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlEquals(customerPortal);
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+ RealmRepresentation demoRealmRep = testRealmResource().toRepresentation();
+ int originalIdle = demoRealmRep.getSsoSessionIdleTimeout();
+ demoRealmRep.setSsoSessionIdleTimeout(1);
+ testRealmResource().update(demoRealmRep);
+
+// Thread.sleep(2000);
+ productPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ demoRealmRep.setSsoSessionIdleTimeout(originalIdle);
+ testRealmResource().update(demoRealmRep);
+ }
+
+ @Test
+ @Jira(value = "KEYCLOAK-1478") // rejected
+ public void testLoginSSOIdleRemoveExpiredUserSessions() {
+ // test login to customer-portal which does a bearer request to customer-db
+ customerPortal.navigateTo();
+ log.info("Current url: " + driver.getCurrentUrl());
+ testRealmLoginPage.form().waitForUsernameInputPresent();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ log.info("Current url: " + driver.getCurrentUrl());
+ assertCurrentUrlEquals(customerPortal);
+ String pageSource = driver.getPageSource();
+ log.info(pageSource);
+ Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+ RealmRepresentation demoRealmRep = testRealmResource().toRepresentation();
+ int originalIdle = demoRealmRep.getSsoSessionIdleTimeout();
+ demoRealmRep.setSsoSessionIdleTimeout(1);
+ testRealmResource().update(demoRealmRep);
+
+ Time.setOffset(2);
+
+ productPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ // need to cleanup so other tests don't fail, so invalidate http sessions on remote clients.
+ demoRealmRep.setSsoSessionIdleTimeout(originalIdle);
+ // note: sessions invalidated after each test, see: AbstractKeycloakTest.afterAbstractKeycloakTest()
+
+ Time.setOffset(0);
+ }
+
+ @Test
+ public void testLoginSSOMax() throws InterruptedException {
+ // test login to customer-portal which does a bearer request to customer-db
+ customerPortal.navigateTo();
+ testRealmLoginPage.form().waitForUsernameInputPresent();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlEquals(customerPortal);
+ String pageSource = driver.getPageSource();
+ Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+ RealmRepresentation demoRealmRep = testRealmResource().toRepresentation();
+ int originalIdle = demoRealmRep.getSsoSessionMaxLifespan();
+ demoRealmRep.setSsoSessionMaxLifespan(1);
+ testRealmResource().update(demoRealmRep);
+
+ TimeUnit.SECONDS.sleep(2);
+ productPortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ demoRealmRep.setSsoSessionIdleTimeout(originalIdle);
+ testRealmResource().update(demoRealmRep);
+ }
+
+ @Jira("KEYCLOAK-518")
+ @Test
+ public void testNullBearerToken() {
+ Client client = ClientBuilder.newClient();
+ WebTarget target = client.target(customerDb.toString());
+ Response response = target.request().get();
+ assertEquals(401, response.getStatus());
+ response.close();
+ response = target.request().header(HttpHeaders.AUTHORIZATION, "Bearer null").get();
+ assertEquals(401, response.getStatus());
+ response.close();
+ client.close();
+ }
+
+ @Jira("KEYCLOAK-1368")
+ @Test
+ public void testNullBearerTokenCustomErrorPage() {
+ Client client = ClientBuilder.newClient();
+ WebTarget target = client.target(customerDbErrorPage.toString());
+ Response response = target.request().get();
+
+ // TODO: follow redirects automatically if possible
+ if (response.getStatus() == 302) {
+ String location = response.getHeaderString(HttpHeaders.LOCATION);
+ response.close();
+ response = client.target(location).request().get();
+ }
+ assertEquals(200, response.getStatus());
+ String errorPageResponse = response.readEntity(String.class);
+ assertTrue(errorPageResponse.contains("Error Page"));
+ response.close();
+
+ response = target.request().header(HttpHeaders.AUTHORIZATION, "Bearer null").get();
+ // TODO: follow redirects automatically if possible
+ if (response.getStatus() == 302) {
+ String location = response.getHeaderString(HttpHeaders.LOCATION);
+ response.close();
+ response = client.target(location).request().get();
+ }
+ assertEquals(200, response.getStatus());
+ errorPageResponse = response.readEntity(String.class);
+ assertTrue(errorPageResponse.contains("Error Page"));
+ response.close();
+
+ client.close();
+ }
+
+ @Jira("KEYCLOAK-518")
+ @Test
+ public void testBadUser() {
+ Client client = ClientBuilder.newClient();
+ URI uri = OIDCLoginProtocolService.tokenUrl(authServerPage.createUriBuilder()).build("demo");
+ WebTarget target = client.target(uri);
+ String header = BasicAuthHelper.createHeader("customer-portal", "password");
+ Form form = new Form();
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
+ .param("username", "monkey@redhat.com")
+ .param("password", "password");
+ Response response = target.request()
+ .header(HttpHeaders.AUTHORIZATION, header)
+ .post(Entity.form(form));
+ assertEquals(401, response.getStatus());
+ response.close();
+ client.close();
+
+ }
+
+ @Test
+ public void testVersion() {
+ Client client = ClientBuilder.newClient();
+ WebTarget target = client.target(authServerPage.createUriBuilder()).path("version");
+ Version version = target.request().get(Version.class);
+ assertNotNull(version);
+ assertNotNull(version.getVersion());
+ assertNotNull(version.getBuildTime());
+ assertNotEquals(version.getVersion(), Version.UNKNOWN);
+ assertNotEquals(version.getBuildTime(), Version.UNKNOWN);
+
+ Version version2 = client.target(securePortal.toString()).path(AdapterConstants.K_VERSION).request().get(Version.class);
+ assertNotNull(version2);
+ assertNotNull(version2.getVersion());
+ assertNotNull(version2.getBuildTime());
+ assertEquals(version.getVersion(), version2.getVersion());
+ assertEquals(version.getBuildTime(), version2.getBuildTime());
+ client.close();
+ }
+
+ @Test
+ public void testAuthenticated() {
+ // test login to customer-portal which does a bearer request to customer-db
+ securePortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlEquals(securePortal);
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+ // test logout
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, securePortal.toString()).build("demo").toString();
+ driver.navigate().to(logoutUri);
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ securePortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java
new file mode 100644
index 0000000..79c0bef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java
@@ -0,0 +1,184 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.After;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.adapter.page.SessionPortal;
+import org.keycloak.testsuite.arquillian.jira.Jira;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+import org.keycloak.testsuite.auth.page.account.Sessions;
+import org.keycloak.testsuite.auth.page.login.Login;
+import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import org.keycloak.testsuite.util.SecondBrowser;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractSessionServletAdapterTest extends AbstractServletsAdapterTest {
+
+ @Page
+ private SessionPortal sessionPortalPage;
+
+ @Page
+ private Sessions testRealmSessions;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmSessions.setAuthRealm(DEMO);
+ }
+
+ @Deployment(name = SessionPortal.DEPLOYMENT_NAME)
+ protected static WebArchive sessionPortal() {
+ return servletDeployment(SessionPortal.DEPLOYMENT_NAME, "keycloak.json", SessionServlet.class);
+ }
+
+ @After
+ public void afterSessionServletAdapterTest() {
+ sessionPortalPage.navigateTo();
+ driver.manage().deleteAllCookies();
+ }
+
+ @Drone
+ @SecondBrowser
+ protected WebDriver driver2;
+
+ @Jira("KEYCLOAK-732")
+ @Test
+ public void testSingleSessionInvalidated() {
+
+ loginAndCheckSession(driver, testRealmLoginPage);
+
+ // cannot pass to loginAndCheckSession becayse loginPage is not working together with driver2, therefore copypasta
+ driver2.navigate().to(sessionPortalPage.toString());
+ assertCurrentUrlStartsWithLoginUrlOf(driver2, testRealmPage);
+ driver2.findElement(By.id("username")).sendKeys("bburke@redhat.com");
+ driver2.findElement(By.id("password")).sendKeys("password");
+ driver2.findElement(By.id("password")).submit();
+ assertCurrentUrlEquals(driver2, sessionPortalPage);
+ String pageSource = driver2.getPageSource();
+ assertTrue(pageSource.contains("Counter=1"));
+ // Counter increased now
+ driver2.navigate().to(sessionPortalPage.toString());
+ pageSource = driver2.getPageSource();
+ assertTrue(pageSource.contains("Counter=2"));
+
+ // Logout in browser1
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, sessionPortalPage.toString()).build("demo").toString();
+ driver.navigate().to(logoutUri);
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ // Assert that I am logged out in browser1
+ sessionPortalPage.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ // Assert that I am still logged in browser2 and same session is still preserved
+ driver2.navigate().to(sessionPortalPage.toString());
+ assertCurrentUrlEquals(driver2, sessionPortalPage);
+ pageSource = driver2.getPageSource();
+ assertTrue(pageSource.contains("Counter=3"));
+
+ driver2.navigate().to(logoutUri);
+ assertCurrentUrlStartsWithLoginUrlOf(driver2, testRealmPage);
+
+ }
+
+ @Test
+ @Jira("KEYCLOAK-741, KEYCLOAK-1485")
+ public void testSessionInvalidatedAfterFailedRefresh() {
+ RealmRepresentation testRealmRep = testRealmResource().toRepresentation();
+ ClientResource sessionPortalRes = null;
+ for (ClientRepresentation clientRep : testRealmResource().clients().findAll()) {
+ if ("session-portal".equals(clientRep.getClientId())) {
+ sessionPortalRes = testRealmResource().clients().get(clientRep.getId());
+ }
+ }
+ assertNotNull(sessionPortalRes);
+ sessionPortalRes.toRepresentation().setAdminUrl("");
+ int origTokenLifespan = testRealmRep.getAccessCodeLifespan();
+ testRealmRep.setAccessCodeLifespan(1);
+ testRealmResource().update(testRealmRep);
+
+ // Login
+ loginAndCheckSession(driver, testRealmLoginPage);
+
+ // Logout
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, sessionPortalPage.toString()).build("demo").toString();
+ driver.navigate().to(logoutUri);
+
+ // Assert that http session was invalidated
+ sessionPortalPage.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertEquals(driver.getCurrentUrl(), sessionPortalPage.toString());
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Counter=1"));
+
+ sessionPortalRes.toRepresentation().setAdminUrl(sessionPortalPage.toString());
+ testRealmRep.setAccessCodeLifespan(origTokenLifespan);
+ testRealmResource().update(testRealmRep);
+ }
+
+ @Test
+ @Jira("KEYCLOAK-942")
+ public void testAdminApplicationLogout() {
+ // login as bburke
+ loginAndCheckSession(driver, testRealmLoginPage);
+ // logout mposolda with admin client
+ findClientResourceByClientId(testRealmResource(), "session-portal")
+ .logoutUser("mposolda");
+ // bburke should be still logged with original httpSession in our browser window
+ sessionPortalPage.navigateTo();
+ assertEquals(driver.getCurrentUrl(), sessionPortalPage.toString());
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Counter=3"));
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, sessionPortalPage.toString()).build("demo").toString();
+ driver.navigate().to(logoutUri);
+ }
+
+ @Test
+ @Jira("KEYCLOAK-1216, KEYCLOAK-1485")
+ public void testAccountManagementSessionsLogout() {
+ // login as bburke
+ loginAndCheckSession(driver, testRealmLoginPage);
+ testRealmSessions.navigateTo();
+ testRealmSessions.logoutAll();
+ // Assert I need to login again (logout was propagated to the app)
+ loginAndCheckSession(driver, testRealmLoginPage);
+ }
+
+ private void loginAndCheckSession(WebDriver driver, Login login) {
+ sessionPortalPage.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ login.form().login("bburke@redhat.com", "password");
+ assertEquals(driver.getCurrentUrl(), sessionPortalPage.toString());
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Counter=1"));
+
+ // Counter increased now
+ sessionPortalPage.navigateTo();
+ pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Counter=2"));
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java
new file mode 100644
index 0000000..573363a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java
@@ -0,0 +1,111 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.AbstractAuthTest;
+import org.keycloak.testsuite.console.page.AdminConsole;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm.ConfigureMenu;
+import org.keycloak.testsuite.console.page.AdminConsoleRealm.ManageMenu;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.login.Login;
+import org.keycloak.testsuite.console.page.fragment.ModalDialog;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public abstract class AbstractConsoleTest extends AbstractAuthTest {
+
+ @Page
+ protected AdminConsole adminConsolePage;
+ @Page
+ protected AdminConsoleRealm adminConsoleRealmPage;
+
+ @Page
+ protected AdminConsole testRealmAdminConsolePage;
+
+ @FindBy(xpath = "//div[@class='modal-dialog']")
+ protected ModalDialog modalDialog;
+
+ protected boolean adminLoggedIn = false;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm(TEST);
+ testRealmAdminConsolePage.setAdminRealm(TEST);
+ }
+
+ @Before
+ public void beforeConsoleTest() {
+ createTestUserWithAdminClient();
+ if (!testContext.isAdminLoggedIn()) {
+ loginToMasterRealmAdminConsoleAs(adminUser);
+ testContext.setAdminLoggedIn(true);
+ } else {
+// adminConsoleRealmPage.navigateTo();
+ }
+ }
+
+ public void loginToMasterRealmAdminConsoleAs(UserRepresentation user) {
+ loginToAdminConsoleAs(adminConsolePage, loginPage, user);
+ }
+
+ public void logoutFromMasterRealmConsole() {
+ logoutFromAdminConsole(adminConsolePage);
+ }
+
+ public void loginToTestRealmConsoleAs(UserRepresentation user) {
+ loginToAdminConsoleAs(testRealmAdminConsolePage, testRealmLoginPage, user);
+ }
+
+ public void logoutFromTestRealmConsole() {
+ logoutFromAdminConsole(testRealmAdminConsolePage);
+ }
+
+ public void loginToAdminConsoleAs(AdminConsole adminConsole, Login login, UserRepresentation user) {
+ adminConsole.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(adminConsole);
+ login.form().login(user);
+ assertCurrentUrlStartsWith(adminConsole);
+ }
+
+ public void logoutFromAdminConsole(AdminConsole adminConsole) {
+ adminConsole.navigateTo();
+ assertCurrentUrlStartsWith(adminConsole);
+ adminConsole.logOut();
+ assertCurrentUrlStartsWithLoginUrlOf(adminConsole);
+ }
+
+ public ConfigureMenu configure() {
+ return adminConsoleRealmPage.configure();
+ }
+
+ public ManageMenu manage() {
+ return adminConsoleRealmPage.manage();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java
new file mode 100644
index 0000000..75cf70f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java
@@ -0,0 +1,164 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.authentication;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.authentication.PasswordPolicy;
+
+import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.*;
+import org.keycloak.testsuite.console.page.users.UserCredentials;
+
+/**
+ * @author Petr Mensik
+ * @author mhajas
+ */
+//@Ignore // FIXME still unstable
+public class PasswordPolicyTest extends AbstractConsoleTest {
+
+ @Page
+ private PasswordPolicy passwordPolicyPage;
+
+ @Page
+ private UserCredentials testUserCredentialsPage;
+
+ @Before
+ public void beforePasswordPolicyTest() {
+ testUserCredentialsPage.setId(testUser.getId());
+ passwordPolicyPage.navigateTo();
+ }
+
+ @Test
+ public void testAddAndRemovePolicy() {
+ passwordPolicyPage.addPolicy(HASH_ITERATIONS, 5);
+ passwordPolicyPage.removePolicy(HASH_ITERATIONS);
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testInvalidPolicyValues() {
+ passwordPolicyPage.addPolicy(HASH_ITERATIONS, "asd");
+ assertFlashMessageDanger();
+ passwordPolicyPage.removePolicy(HASH_ITERATIONS);
+
+ passwordPolicyPage.addPolicy(REGEX_PATTERN, "^[A-Z]{8,5}");
+ assertFlashMessageDanger();
+ }
+
+ @Test
+ public void testLengthPolicy() {
+ passwordPolicyPage.addPolicy(LENGTH, 8);
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword("1234567");
+ assertFlashMessageDanger();
+
+ testUserCredentialsPage.resetPassword("12345678");
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testDigitsPolicy() {
+ passwordPolicyPage.addPolicy(DIGITS, 2);
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword("invalidPassword1");
+ assertFlashMessageDanger();
+
+ testUserCredentialsPage.resetPassword("validPassword12");
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testLowerCasePolicy() {
+ passwordPolicyPage.addPolicy(LOWER_CASE, 2);
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword("iNVALIDPASSWORD");
+ assertFlashMessageDanger();
+
+ testUserCredentialsPage.resetPassword("vaLIDPASSWORD");
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testUpperCasePolicy() {
+ passwordPolicyPage.addPolicy(UPPER_CASE, 2);
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword("Invalidpassword");
+ assertFlashMessageDanger();
+
+ testUserCredentialsPage.resetPassword("VAlidpassword");
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testSpecialCharsPolicy() {
+ passwordPolicyPage.addPolicy(SPECIAL_CHARS, 2);
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword("invalidPassword*");
+ assertFlashMessageDanger();
+
+ testUserCredentialsPage.resetPassword("validPassword*#");
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testNotUsernamePolicy() {
+ passwordPolicyPage.addPolicy(NOT_USERNAME);
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword(testUser.getUsername());
+ assertFlashMessageDanger();
+
+ testUserCredentialsPage.resetPassword("validpassword");
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testRegexPatternsPolicy() {
+ passwordPolicyPage.addPolicy(REGEX_PATTERN, "^[A-Z]+#[a-z]{8}$");
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword("invalidPassword");
+ assertFlashMessageDanger();
+
+ testUserCredentialsPage.resetPassword("VALID#password");
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void testPasswordHistoryPolicy() {
+ passwordPolicyPage.addPolicy(PASSWORD_HISTORY, 2);
+
+ testUserCredentialsPage.navigateTo();
+ testUserCredentialsPage.resetPassword("firstPassword");
+ assertFlashMessageSuccess();
+
+ testUserCredentialsPage.resetPassword("secondPassword");
+ assertFlashMessageSuccess();
+
+ testUserCredentialsPage.resetPassword("firstPassword");
+ assertFlashMessageDanger();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/RequiredActionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/RequiredActionsTest.java
new file mode 100644
index 0000000..9c818d1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/authentication/RequiredActionsTest.java
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.authentication;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.auth.page.login.Registration;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.authentication.RequiredActions;
+import org.keycloak.testsuite.console.page.realm.LoginSettings;
+import org.openqa.selenium.By;
+
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+
+/**
+ * @author Petr Mensik
+ * @author mhajas
+ */
+public class RequiredActionsTest extends AbstractConsoleTest {
+
+ @Page
+ private RequiredActions requiredActionsPage;
+
+ @Page
+ private LoginSettings loginSettingsPage;
+
+ @Page
+ private Registration testRealmRegistrationPage;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmRegistrationPage.setAuthRealm("test");
+ }
+
+ @Before
+ public void beforeRequiredActionsTest() {
+ requiredActionsPage.navigateTo();
+ }
+
+ @Test
+ public void requiredActionsTest() {
+ requiredActionsPage.clickTermsAndConditionEnabled();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickTermsAndConditionDefaultAction();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickVerifyEmailEnabled();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickVerifyEmailDefaultAction();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickUpdatePasswordEnabled();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickUpdatePasswordDefaultAction();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickConfigureTotpEnabled();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickConfigureTotpDefaultAction();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickUpdateProfileEnabled();
+ assertFlashMessageSuccess();
+
+ requiredActionsPage.clickUpdateProfileDefaultAction();
+ assertFlashMessageSuccess();
+ }
+
+ @Test
+ public void termsAndConditionsDefaultActionTest() {
+ requiredActionsPage.clickTermsAndConditionEnabled();
+ requiredActionsPage.clickTermsAndConditionDefaultAction();
+
+ allowTestRealmUserRegistration();
+
+ navigateToTestRealmRegistration();
+
+ registerTestUser();
+
+ driver.findElement(By.xpath("//div[@id='kc-header-wrapper' and text()[contains(.,'Terms and Conditions')]]"));
+ }
+
+ @Test
+ public void configureTotpDefaultActionTest() {
+ requiredActionsPage.clickConfigureTotpDefaultAction();
+
+ allowTestRealmUserRegistration();
+
+ navigateToTestRealmRegistration();
+
+ registerTestUser();
+
+ driver.findElement(By.xpath("//div[@id='kc-header-wrapper' and text()[contains(.,'Mobile Authenticator Setup')]]"));
+ }
+
+ private void allowTestRealmUserRegistration() {
+ loginSettingsPage.navigateTo();
+ loginSettingsPage.form().setRegistrationAllowed(true);
+ loginSettingsPage.form().save();
+ }
+
+ private void navigateToTestRealmRegistration() {
+ testRealmAdminConsolePage.navigateTo();
+ testRealmLoginPage.form().register();
+ }
+
+ private void registerTestUser() {
+ UserRepresentation user = createUserRepresentation("testUser", "testUser@email.test", "test", "user", true);
+ setPasswordFor(user, PASSWORD);
+
+ testRealmRegistrationPage.register(user);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
new file mode 100644
index 0000000..6c40d64
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
@@ -0,0 +1,74 @@
+package org.keycloak.testsuite.console.clients;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.clients.Client;
+import org.keycloak.testsuite.console.page.clients.Clients;
+import org.keycloak.testsuite.console.page.clients.CreateClient;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractClientTest extends AbstractConsoleTest {
+
+ @Page
+ protected Clients clientsPage;
+ @Page
+ protected Client clientPage; // note: cannot call navigateTo() unless client id is set
+ @Page
+ protected CreateClient createClientPage;
+
+ @Before
+ public void beforeClientTest() {
+// configure().clients();
+ clientsPage.navigateTo();
+ }
+
+ public void createClient(ClientRepresentation client) {
+ assertCurrentUrlEquals(clientsPage);
+ clientsPage.table().createClient();
+ createClientPage.form().setValues(client);
+ createClientPage.form().save();
+ }
+
+ public void deleteClientViaTable(String clientId) {
+ assertCurrentUrlEquals(clientsPage);
+ clientsPage.deleteClient(clientId);
+ }
+
+ public void deleteClientViaPage(String clientId) {
+ assertCurrentUrlEquals(clientsPage);
+ clientsPage.table().search(clientId);
+ clientsPage.table().clickClient(clientId);
+ clientPage.delete();
+ }
+
+ public static ClientRepresentation createClientRepresentation(String clientId, String... redirectUris) {
+ ClientRepresentation client = new ClientRepresentation();
+ client.setClientId(clientId);
+ client.setEnabled(true);
+ client.setConsentRequired(false);
+ client.setDirectGrantsOnly(false);
+
+ client.setProtocol(OIDC);
+
+ client.setBearerOnly(false);
+ client.setPublicClient(false);
+ client.setServiceAccountsEnabled(false);
+
+ List<String> redirectUrisList = new ArrayList();
+ redirectUrisList.addAll(Arrays.asList(redirectUris));
+ client.setRedirectUris(redirectUrisList);
+
+ return client;
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java
new file mode 100644
index 0000000..e005d60
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientRolesTest.java
@@ -0,0 +1,273 @@
+package org.keycloak.testsuite.console.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+import org.keycloak.testsuite.console.page.users.UserRoleMappingsForm;
+
+import static org.junit.Assert.*;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.clients.ClientRole;
+import org.keycloak.testsuite.console.page.clients.ClientRoles;
+import org.keycloak.testsuite.console.page.clients.CreateClientRole;
+import org.keycloak.testsuite.console.page.users.User;
+
+/**
+ * Created by fkiss.
+ */
+public class ClientRolesTest extends AbstractClientTest {
+
+ @Page
+ private ClientRoles clientRolesPage;
+ @Page
+ private CreateClientRole createClientRolePage;
+ @Page
+ private ClientRole clientRolePage;
+
+ @Page
+ private User userPage; // note: cannot call navigateTo() unless user id is set
+
+ @Page
+ private UserRoleMappingsForm userRolesPage;
+
+ public void addClientRole(RoleRepresentation roleRep) {
+// assertCurrentUrl(clientRoles);
+ clientRolesPage.roles().addRole();
+// assertCurrentUrl(createClientRole); // can't do this, need client id to build uri
+ createClientRolePage.form().setBasicAttributes(roleRep);
+ createClientRolePage.form().save();
+ assertFlashMessageSuccess();
+ createClientRolePage.form().setCompositeRoles(roleRep);
+ // TODO add verification of notification message when KEYCLOAK-1497 gets resolved
+ }
+
+ @Test
+ public void testAddClientRole() {
+ ClientRepresentation newClient = createClientRepresentation("test-client1", "http://example.com/*");
+ RoleRepresentation newRole = new RoleRepresentation("client-role", "");
+
+ createClient(newClient);
+ assertFlashMessageSuccess();
+
+ clientPage.tabs().roles();
+ addClientRole(newRole);
+ assertFlashMessageSuccess();
+
+ clientRolePage.backToClientRolesViaBreadcrumb();
+ assertFalse(clientRolesPage.roles().getRolesFromTableRows().isEmpty());
+
+ configure().clients();
+ clientsPage.table().search(newClient.getClientId());
+ clientsPage.table().deleteClient(newClient.getClientId());
+ modalDialog.confirmDeletion();
+ assertFlashMessageSuccess();
+ assertNull(clientsPage.table().findClient(newClient.getClientId()));
+ }
+
+// @Test
+// @Jira("KEYCLOAK-1497")
+// public void testAddClientRoleToUser() {
+// ClientRepresentation newClient = createClientRepresentation("test-client2", "http://example.com/*");
+// RoleRepresentation newRole = new RoleRepresentation("client-role2", "");
+// String testUsername = "test-user2";
+// UserRepresentation newUser = new UserRepresentation();
+// newUser.setUsername(testUsername);
+// newUser.credential(PASSWORD, "pass");
+//
+// createClient(newClient);
+// assertFlashMessageSuccess();
+//
+// client.tabs().roles();
+// addClientRole(newRole);
+// assertFlashMessageSuccess();
+//
+// clientRole.backToClientRolesViaBreadcrumb();
+// assertFalse(clientRoles.table().searchRoles(newRole.getName()).isEmpty());
+//
+// users.navigateTo();
+// createUser(newUser);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+// users.navigateTo();
+// users.findUser(testUsername);
+// users.clickUser(testUsername);
+//
+// user.tabs().roleMappings();
+// roleMappings.selectClientRole(newClient.getClientId());
+// roleMappings.addAvailableClientRole(newRole.getName());
+// //flashMessage.waitUntilPresent();
+// //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// //KEYCLOAK-1497
+// assertTrue(roleMappings.isAssignedClientRole(newRole.getName()));
+//
+// users.navigateTo();
+// users.deleteUser(testUsername);
+//
+// clients.navigateTo();
+// clients.deleteClient(newClient.getClientId());
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// assertNull(clients.findClient(newClient.getClientId()));
+// }
+//
+// @Test
+// @Jira("KEYCLOAK-1496, KEYCLOAK-1497")
+// @Ignore // TODO use REST to create test data (user/roles)
+// public void testAddCompositeRealmClientRoleToUser() {
+// ClientRepresentation newClient = createClientRepresentation("test-client3", "http://example.com/*");
+// RoleRepresentation clientCompositeRole = new RoleRepresentation("client-composite-role", "");
+// String testUsername = "test-user3";
+// UserRepresentation newUser = new UserRepresentation();
+// newUser.setUsername(testUsername);
+// newUser.credential(PASSWORD, "pass");
+//
+// RoleRepresentation subRole1 = new RoleRepresentation("sub-role1", "");
+// RoleRepresentation subRole2 = new RoleRepresentation("sub-role2", "");
+// List<RoleRepresentation> testRoles = new ArrayList<>();
+// clientCompositeRole.setComposite(true);
+// testRoles.add(subRole1);
+// testRoles.add(subRole2);
+//
+// //create sub-roles
+// configure().roles();
+// for (RoleRepresentation role : testRoles) {
+// realmRoles.addRole(role);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// configure().roles();
+// assertEquals(role.getName(), realmRoles.findRole(role.getName()).getName());
+// }
+//
+// //create client
+// clients.navigateTo();
+// createClient(newClient);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+// //add client role
+// configure().roles();
+// realmRoles.addRole(clientCompositeRole);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+// //add realm composite roles
+// realmRoles.setCompositeRole(clientCompositeRole);
+// roleMappings.addAvailableRole(subRole1.getName(), subRole2.getName());
+// //flashMessage.waitUntilPresent();
+// //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// //KEYCLOAK-1497
+//
+// //create user
+// users.navigateTo();
+// createUser(newUser);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+// //add client role to user and verify
+// users.navigateTo();
+// users.findUser(testUsername);
+// users.clickUser(testUsername);
+//
+// user.tabs().roleMappings();
+// roleMappings.selectClientRole(newClient.getClientId());
+// roleMappings.addAvailableClientRole(clientCompositeRole.getName());
+// //flashMessage.waitUntilPresent();
+// //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// //KEYCLOAK-1497
+// assertTrue(roleMappings.isAssignedClientRole(clientCompositeRole.getName()));
+// assertTrue(roleMappings.isEffectiveRealmRolesComplete(subRole1, subRole2)); //KEYCLOAK-1496
+// assertTrue(roleMappings.isEffectiveClientRolesComplete(clientCompositeRole));
+//
+// //delete everything
+// users.navigateTo();
+// users.deleteUser(testUsername);
+//
+// configure().roles();
+// realmRoles.deleteRole(subRole1);
+// configure().roles();
+// realmRoles.deleteRole(subRole2);
+//
+// clients.navigateTo();
+// clients.deleteClient(newClient.getClientId());
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// assertNull(clients.findClient(newClient.getClientId()));
+// }
+//
+// @Test
+// @Jira("KEYCLOAK-1504, KEYCLOAK-1497")
+// public void testAddCompositeClientRoleToUser() {
+// ClientRepresentation newClient = createClientRepresentation("test-client4", "http://example.com/*");
+// RoleRepresentation clientCompositeRole = new RoleRepresentation("client-composite-role2", "");
+// String testUsername = "test-user4";
+// UserRepresentation newUser = new UserRepresentation();
+// newUser.setUsername(testUsername);
+// newUser.credential(PASSWORD, "pass");
+//
+// RoleRepresentation subRole1 = new RoleRepresentation("client-sub-role1", "");
+// RoleRepresentation subRole2 = new RoleRepresentation("client-sub-role2", "");
+// List<RoleRepresentation> testRoles = new ArrayList<>();
+// clientCompositeRole.setComposite(true);
+// testRoles.add(clientCompositeRole);
+// testRoles.add(subRole1);
+// testRoles.add(subRole2);
+//
+// //create client
+// createClient(newClient);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+// //create sub-roles
+// configure().roles();
+// for (RoleRepresentation role : testRoles) {
+// clients.navigateTo();
+// clients.clickClient(newClient.getClientId());
+// configure().roles();
+// realmRoles.addRole(role);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// }
+//
+// //add client composite roles
+// clients.navigateTo();
+// clients.clickClient(newClient);
+// configure().roles();
+// realmRoles.clickRole(clientCompositeRole);
+// realmRoles.setCompositeRole(clientCompositeRole);
+// roleMappings.selectClientRole(newClient.getClientId());
+// roleMappings.addAvailableClientRole(subRole1.getName(), subRole2.getName());
+// //flashMessage.waitUntilPresent();
+// //assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// //KEYCLOAK-1504, KEYCLOAK-1497
+//
+// //create user
+// users.navigateTo();
+// createUser(newUser);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+// //add client role to user and verify
+// users.navigateTo();
+// users.findUser(testUsername);
+// users.clickUser(testUsername);
+//
+// user.tabs().roleMappings();
+// roleMappings.selectClientRole(newClient.getClientId());
+// roleMappings.addAvailableClientRole(clientCompositeRole.getName());
+// assertTrue(roleMappings.isAssignedClientRole(clientCompositeRole.getName()));
+// assertTrue(roleMappings.isEffectiveClientRolesComplete(clientCompositeRole, subRole1, subRole2));
+//
+// //delete everything
+// users.navigateTo();
+// users.deleteUser(testUsername);
+//
+// configure().roles();
+// realmRoles.deleteRole(subRole1);
+// configure().roles();
+// realmRoles.deleteRole(subRole2);
+//
+// clients.navigateTo();
+// clients.deleteClient(newClient.getClientId());
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// assertNull(clients.findClient(newClient.getClientId()));
+// }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
new file mode 100644
index 0000000..5229527
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
@@ -0,0 +1,163 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.clients;
+
+import javax.ws.rs.core.Response;
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+import org.keycloak.representations.idm.ClientRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.getCreatedId;
+import org.keycloak.testsuite.console.page.clients.ClientSettings;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsBooleanAttributes;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsListAttributes;
+import static org.keycloak.testsuite.util.AttributesAssert.assertEqualsStringAttributes;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class ClientSettingsTest extends AbstractClientTest {
+
+ @Page
+ private ClientSettings clientSettingsPage;
+
+ private ClientRepresentation newClient;
+
+ public void crudOIDCConfidential() {
+ newClient = createClientRepresentation("oidc-confidential", "http://example.test/app/*");
+ createClient(newClient);
+ assertFlashMessageSuccess();
+
+ clientPage.backToClientsViaBreadcrumb();
+ assertCurrentUrlEquals(clientsPage);
+ assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+
+ // read & verify
+ clientsPage.table().clickClient(newClient);
+ ClientRepresentation found = clientSettingsPage.form().getValues();
+ assertClientSettingsEqual(newClient, found);
+
+ // update & verify
+ // TODO change attributes, add redirect uris and weborigins
+ // delete
+ // TODO
+ clientPage.backToClientsViaBreadcrumb();
+ }
+
+ public void createOIDCPublic() {
+ newClient = createClientRepresentation("oidc-public", "http://example.test/app/*");
+ newClient.setPublicClient(true);
+ createClient(newClient);
+ assertFlashMessageSuccess();
+
+ clientPage.backToClientsViaBreadcrumb();
+ assertCurrentUrlEquals(clientsPage);
+ assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+ }
+
+ public void createOIDCBearerOnly() {
+ newClient = createClientRepresentation("oidc-bearer-only", "http://example.test/app/*");
+ newClient.setBearerOnly(true);
+ createClient(newClient);
+ assertFlashMessageSuccess();
+
+ clientPage.backToClientsViaBreadcrumb();
+ assertCurrentUrlEquals(clientsPage);
+ assertEquals(1, clientsPage.table().searchClients(newClient.getClientId()).size());
+ }
+
+ @Test
+ public void successfulCRUD() {
+ crudOIDCConfidential();
+ createOIDCPublic();
+ createOIDCBearerOnly();
+ }
+
+ @Test
+ public void invalidSettings() {
+ clientsPage.table().createClient();
+ createClientPage.form().save();
+ assertFlashMessageDanger();
+
+ createClientPage.form().setClientId("test-client");
+ createClientPage.form().save();
+ assertFlashMessageDanger();
+ }
+
+ public void assertClientSettingsEqual(ClientRepresentation c1, ClientRepresentation c2) {
+ assertEqualsStringAttributes(c1.getClientId(), c2.getClientId());
+ assertEqualsStringAttributes(c1.getName(), c2.getName());
+ assertEqualsBooleanAttributes(c1.isEnabled(), c2.isEnabled());
+ assertEqualsBooleanAttributes(c1.isConsentRequired(), c2.isConsentRequired());
+ assertEqualsBooleanAttributes(c1.isDirectGrantsOnly(), c2.isDirectGrantsOnly());
+ assertEqualsStringAttributes(c1.getProtocol(), c2.getProtocol());
+
+ assertEqualsBooleanAttributes(c1.isBearerOnly(), c2.isBearerOnly());
+ assertEqualsBooleanAttributes(c1.isPublicClient(), c2.isPublicClient());
+ assertEqualsBooleanAttributes(c1.isSurrogateAuthRequired(), c2.isSurrogateAuthRequired());
+
+ assertEqualsBooleanAttributes(c1.isFrontchannelLogout(), c2.isFrontchannelLogout());
+
+ assertEqualsBooleanAttributes(c1.isServiceAccountsEnabled(), c2.isServiceAccountsEnabled());
+ assertEqualsListAttributes(c1.getRedirectUris(), c2.getRedirectUris());
+ assertEqualsStringAttributes(c1.getBaseUrl(), c2.getBaseUrl());
+ assertEqualsStringAttributes(c1.getAdminUrl(), c2.getAdminUrl());
+ assertEqualsListAttributes(c1.getWebOrigins(), c2.getWebOrigins());
+ }
+
+// @Test
+ public void createInconsistentClient() {
+ ClientRepresentation c = createClientRepresentation("inconsistent_client");
+ c.setPublicClient(true);
+ c.setBearerOnly(true);
+
+ Response r = clientsPage.clientsResource().create(c);
+ r.close();
+ clientSettingsPage.setId(getCreatedId(r));
+
+ c = clientSettingsPage.clientResource().toRepresentation();
+ assertTrue(c.isBearerOnly());
+ assertTrue(c.isPublicClient());
+ }
+
+ public void createClients(String clientIdPrefix, int count) {
+ for (int i = 0; i < count; i++) {
+ String clientId = String.format("%s%02d", clientIdPrefix, i);
+ ClientRepresentation cr = createClientRepresentation(clientId, "http://example.test/*");
+ Timer.time();
+ Response r = testRealmResource().clients().create(cr);
+ r.close();
+ Timer.time("create client");
+ }
+ }
+
+// @Test
+ public void clientsPagination() {
+ createClients("test_client_", 100);
+ clientsPage.navigateTo();
+ pause(120000);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java
new file mode 100644
index 0000000..5b22ca4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java
@@ -0,0 +1,84 @@
+package org.keycloak.testsuite.console.events;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.clients.AbstractClientTest;
+import org.keycloak.testsuite.console.page.clients.Clients;
+import org.keycloak.testsuite.console.page.events.AdminEvents;
+import org.keycloak.testsuite.console.page.events.Config;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+
+/**
+ * @author mhajas
+ */
+public class AdminEventsTest extends AbstractConsoleTest {
+
+ @Page
+ private AdminEvents adminEventsPage;
+
+ @Page
+ private Config configPage;
+
+ @Page
+ private Clients clientsPage;
+
+ private ClientRepresentation newClient;
+
+ @Before
+ public void beforeAdminEventsTest() {
+ configPage.navigateTo();
+ configPage.form().setSaveAdminEvents(true);
+ configPage.form().setIncludeRepresentation(true);
+ configPage.form().save();
+ }
+
+ @Test
+ public void clientsAdminEventsTest() {
+ newClient = AbstractClientTest.createClientRepresentation("test_client", "http://example.test/test_client/*");
+ Response response = clientsPage.clientsResource().create(newClient);
+ String id = ApiUtil.getCreatedId(response);
+ response.close();
+ newClient.setClientId("test_client2");
+ clientsPage.clientsResource().get(id).update(newClient);
+ clientsPage.clientsResource().get(id).remove();
+
+ adminEventsPage.navigateTo();
+ adminEventsPage.table().filter();
+ adminEventsPage.table().filterForm().addOperationType("CREATE");
+ adminEventsPage.table().update();
+
+ List<WebElement> resultList = adminEventsPage.table().rows();
+ assertEquals(1, resultList.size());
+ resultList.get(0).findElement(By.xpath("//td[text()='CREATE']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
+
+ adminEventsPage.table().reset();
+ adminEventsPage.table().filterForm().addOperationType("UPDATE");
+ adminEventsPage.table().update();
+
+ resultList = adminEventsPage.table().rows();
+ assertEquals(1, resultList.size());
+ resultList.get(0).findElement(By.xpath("//td[text()='UPDATE']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
+
+ adminEventsPage.table().reset();
+ adminEventsPage.table().filterForm().addOperationType("DELETE");
+ adminEventsPage.table().update();
+
+ resultList = adminEventsPage.table().rows();
+ assertEquals(1, resultList.size());
+ resultList.get(0).findElement(By.xpath("//td[text()='DELETE']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
new file mode 100644
index 0000000..078c56d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
@@ -0,0 +1,85 @@
+package org.keycloak.testsuite.console.events;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.admin.Users;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.events.Config;
+import org.keycloak.testsuite.console.page.events.LoginEvents;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+
+/**
+ * @author mhajas
+ */
+public class LoginEventsTest extends AbstractConsoleTest {
+ @Page
+ private LoginEvents loginEventsPage;
+
+ @Page
+ private Config configPage;
+
+ @Before
+ public void beforeLoginEventsTest() {
+ configPage.navigateTo();
+ configPage.form().setSaveEvents(true);
+ configPage.form().addSaveType("LOGIN");
+ configPage.form().addSaveType("LOGIN_ERROR");
+ configPage.form().addSaveType("LOGOUT");
+ configPage.form().save();
+ }
+
+ @Test
+ public void userAccessEventsTest() {
+ testRealmAdminConsolePage.navigateTo();
+ Users.setPasswordFor(testUser, "Wrong_password");
+ testRealmLoginPage.form().login(testUser);
+ Users.setPasswordFor(testUser, PASSWORD);
+ testRealmLoginPage.form().login(testUser);
+ testRealmAdminConsolePage.logOut();
+
+ loginEventsPage.navigateTo();
+ loginEventsPage.table().filter();
+
+ loginEventsPage.table().filterForm().addEventType("LOGIN");
+ loginEventsPage.table().update();
+
+ List<WebElement> resultList = loginEventsPage.table().rows();
+
+ assertEquals(7, resultList.size());
+ resultList.get(0).findElement(By.xpath("//td[text()='LOGIN']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='Client']/../td[text()='security-admin-console']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
+
+ loginEventsPage.table().reset();
+ loginEventsPage.table().filterForm().addEventType("LOGOUT");
+ loginEventsPage.table().update();
+
+ resultList = loginEventsPage.table().rows();
+
+ assertEquals(2, resultList.size());
+ resultList.get(0).findElement(By.xpath("//td[text()='LOGOUT']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
+
+ loginEventsPage.table().reset();
+ loginEventsPage.table().filterForm().addEventType("LOGIN_ERROR");
+ loginEventsPage.table().update();
+
+ resultList = loginEventsPage.table().rows();
+
+ assertEquals(6, resultList.size());
+ resultList.get(0).findElement(By.xpath("//td[text()='LOGIN_ERROR']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='Client']/../td[text()='security-admin-console']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='Error']/../td[text()='invalid_user_credentials']"));
+ resultList.get(0).findElement(By.xpath("//td[text()='IP Address']/../td[text()='127.0.0.1']"));
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/federation/LdapUserFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/federation/LdapUserFederationTest.java
new file mode 100644
index 0000000..e70da46
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/federation/LdapUserFederationTest.java
@@ -0,0 +1,71 @@
+package org.keycloak.testsuite.console.federation;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.*;
+import org.keycloak.models.LDAPConstants;
+
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.federation.LdapUserProviderForm;
+import org.keycloak.testsuite.console.page.federation.UserFederation;
+import org.keycloak.testsuite.console.page.users.Users;
+import org.keycloak.testsuite.util.LDAPTestConfiguration;
+
+import java.util.Map;
+
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+
+/**
+ * Created by fkiss.
+ */
+public class LdapUserFederationTest extends AbstractConsoleTest {
+
+ @Page
+ private LdapUserProviderForm ldapUserProviderForm;
+
+ @Page
+ private UserFederation userFederationPage;
+
+ @Page
+ private Users usersPage;
+
+ @Before
+ public void beforeTestLdapUserFederation() {
+ //configure().userFederation();
+ }
+
+ @Ignore
+ @Test
+ public void addAndConfigureProvider() {
+ adminConsolePage.navigateTo();
+ testRealmLoginPage.form().login(testUser);
+
+ String name = "ldapname";
+
+ String LDAP_CONNECTION_PROPERTIES_LOCATION = "ldap/ldap-connection.properties";
+ LDAPTestConfiguration ldapTestConfiguration = LDAPTestConfiguration.readConfiguration(LDAP_CONNECTION_PROPERTIES_LOCATION);
+
+ UserRepresentation newUser = new UserRepresentation();
+ String testUsername = "defaultrole tester";
+ newUser.setUsername(testUsername);
+ setPasswordFor(newUser, PASSWORD);
+
+ Map<String,String> ldapConfig = ldapTestConfiguration.getLDAPConfig();
+
+ //addLdapProviderTest
+ configure().userFederation();
+ userFederationPage.addProvider("ldap");
+ ldapUserProviderForm.configureLdap(ldapConfig.get(LDAPConstants.LDAP_PROVIDER), ldapConfig.get(LDAPConstants.EDIT_MODE), ldapConfig.get(LDAPConstants.VENDOR), ldapConfig.get(LDAPConstants.CONNECTION_URL), ldapConfig.get(LDAPConstants.USERS_DN), ldapConfig.get(LDAPConstants.BIND_DN), ldapConfig.get(LDAPConstants.BIND_CREDENTIAL));
+ }
+
+ @Ignore
+ @Test
+ public void caseSensitiveSearch() {
+ // This should fail for now due to case-sensitivity
+ adminConsolePage.navigateTo();
+ testRealmLoginPage.form().login("johnKeycloak", "Password1");
+ assertTrue(flashMessage.getText(), flashMessage.isDanger());
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/AbstractRealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/AbstractRealmTest.java
new file mode 100644
index 0000000..84de989
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/AbstractRealmTest.java
@@ -0,0 +1,27 @@
+package org.keycloak.testsuite.console.realm;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.realm.RealmSettings;
+import org.keycloak.testsuite.console.page.realm.RealmSettings.RealmTabs;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractRealmTest extends AbstractConsoleTest {
+
+ @Page
+ protected RealmSettings realmSettingsPage;
+
+ public RealmTabs tabs() {
+ return realmSettingsPage.tabs();
+ }
+
+ @Before
+ public void beforeRealmTest() {
+// configure().realmSettings();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
new file mode 100644
index 0000000..eaae00c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
@@ -0,0 +1,78 @@
+package org.keycloak.testsuite.console.realm;
+
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertFalse;
+import org.junit.Before;
+import org.junit.Test;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.console.page.realm.LoginSettings;
+import org.keycloak.testsuite.auth.page.login.Registration;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class LoginSettingsTest extends AbstractRealmTest {
+
+ @Page
+ private LoginSettings loginSettingsPage;
+
+ @Page
+ private Registration testRealmRegistrationPage;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmRegistrationPage.setAuthRealm(TEST);
+ }
+
+ @Before
+ public void beforeLoginSettingsTest() {
+// tabs().login();
+ loginSettingsPage.navigateTo();
+ assertCurrentUrlEquals(loginSettingsPage);
+ }
+
+ @Test
+ public void userRegistration() {
+
+ log.info("enabling registration");
+ loginSettingsPage.form().setRegistrationAllowed(true);
+ loginSettingsPage.form().save();
+ log.debug("enabled");
+
+ testRealmAdminConsolePage.navigateTo();
+ testRealmLoginPage.form().register();
+ assertCurrentUrlStartsWith(testRealmRegistrationPage);
+ testRealmRegistrationPage.waitForUsernameInputPresent();
+ log.info("verified registration is enabled");
+
+ // test email as username
+ log.info("enabling email as username");
+ loginSettingsPage.navigateTo();
+ loginSettingsPage.form().setEmailAsUsername(true);
+ loginSettingsPage.form().save();
+ log.debug("enabled");
+
+ testRealmAdminConsolePage.navigateTo();
+ testRealmLoginPage.form().register();
+ assertCurrentUrlStartsWith(testRealmRegistrationPage);
+ testRealmRegistrationPage.waitForUsernameInputNotPresent();
+ log.info("verified email as username");
+
+ // test user reg. disabled
+ log.info("disabling registration");
+ loginSettingsPage.navigateTo();
+ loginSettingsPage.form().setRegistrationAllowed(false);
+ loginSettingsPage.form().save();
+ assertFalse(loginSettingsPage.form().isRegistrationAllowed());
+ log.debug("disabled");
+
+ testRealmAdminConsolePage.navigateTo();
+ testRealmLoginPage.form().waitForRegisterLinkNotPresent();
+ log.info("verified regisration is disabled");
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java
new file mode 100644
index 0000000..84a9930
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java
@@ -0,0 +1,255 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.realm;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.testsuite.auth.page.account.Account;
+import org.keycloak.testsuite.console.page.realm.SecurityDefenses;
+import org.keycloak.testsuite.console.page.users.UserAttributes;
+import org.keycloak.testsuite.console.page.users.Users;
+import org.openqa.selenium.By;
+
+import java.util.Date;
+
+import static org.jboss.arquillian.graphene.Graphene.waitGui;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ * @author Filip Kiss
+ * @author mhajas
+ */
+public class SecurityDefensesTest extends AbstractRealmTest {
+
+ @Page
+ private SecurityDefenses.BruteForceDetection bruteForceDetectionPage;
+
+ @Page
+ private Account testRealmAccountPage;
+
+ @Page
+ private Users usersPage;
+
+ @Page
+ private UserAttributes userAttributesPage;
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmAccountPage.setAuthRealm(TEST);
+ }
+
+ @Before
+ public void beforeSecurityDefensesTest() {
+ bruteForceDetectionPage.navigateTo();
+ }
+
+ @Test
+ public void maxLoginFailuresTest() {
+ int secondsToWait = 3;
+
+ bruteForceDetectionPage.form().setProtectionEnabled(true);
+ bruteForceDetectionPage.form().setMaxLoginFailures("1");
+ bruteForceDetectionPage.form().setWaitIncrementSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+ bruteForceDetectionPage.form().setWaitIncrementInput(String.valueOf(secondsToWait));
+ bruteForceDetectionPage.form().save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountPage.navigateTo();
+
+ setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+ testRealmLoginPage.form().login(testUser);
+ waitForFeedbackText("Invalid username or password.");
+ Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+
+ testRealmLoginPage.form().login(testUser);
+ waitGui().until().element(By.className("instruction"))
+ .text().contains("Account is temporarily disabled, contact admin or try again later.");
+ endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+ testRealmAccountPage.navigateTo();
+ testRealmLoginPage.form().login(testUser);
+ endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+
+ while (new Date().compareTo(endTime) < 0) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ setPasswordFor(testUser, PASSWORD);
+ testRealmLoginPage.form().login(testUser);
+ assertCurrentUrlStartsWith(testRealmAccountPage);
+ }
+
+ @Test
+ public void quickLoginCheck() {
+ int secondsToWait = 3;
+
+ bruteForceDetectionPage.form().setProtectionEnabled(true);
+ bruteForceDetectionPage.form().setMaxLoginFailures("100");
+ bruteForceDetectionPage.form().setQuickLoginCheckInput("1500");
+ bruteForceDetectionPage.form().setMinQuickLoginWaitSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+ bruteForceDetectionPage.form().setMinQuickLoginWaitInput(String.valueOf(secondsToWait));
+ bruteForceDetectionPage.form().save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountPage.navigateTo();
+
+ setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+ testRealmLoginPage.form().login(testUser);
+ testRealmLoginPage.form().login(testUser);
+ Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+ testRealmLoginPage.form().login(testUser);
+ waitGui().until().element(By.className("instruction"))
+ .text().contains("Account is temporarily disabled, contact admin or try again later.");
+ endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+
+ testRealmAccountPage.navigateTo();
+ testRealmLoginPage.form().login(testUser);
+ endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+
+ while (new Date().compareTo(endTime) < 0) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ setPasswordFor(testUser, PASSWORD);
+ testRealmLoginPage.form().login(testUser);
+ assertCurrentUrlStartsWith(testRealmAccountPage);
+ }
+
+ @Test
+ public void maxWaitLoginFailures() {
+ int secondsToWait = 5;
+
+ bruteForceDetectionPage.form().setProtectionEnabled(true);
+ bruteForceDetectionPage.form().setMaxLoginFailures("1");
+ bruteForceDetectionPage.form().setMaxWaitSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+ bruteForceDetectionPage.form().setMaxWaitInput(String.valueOf(secondsToWait));
+ bruteForceDetectionPage.form().save();
+
+ testRealmAccountPage.navigateTo();
+
+ setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+ testRealmLoginPage.form().login(testUser);
+ Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+ waitForFeedbackText("Invalid username or password.");
+
+ testRealmLoginPage.form().login(testUser);
+ endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+ waitGui().until().element(By.className("instruction"))
+ .text().contains("Account is temporarily disabled, contact admin or try again later.");
+ testRealmAccountPage.navigateTo();
+ testRealmLoginPage.form().login(testUser);
+ endTime = new Date(endTime.getTime() + secondsToWait * 1000);
+ waitForFeedbackText("Account is temporarily disabled, contact admin or try again later.");
+
+ while (new Date().compareTo(endTime) < 0) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ setPasswordFor(testUser, PASSWORD);
+ testRealmLoginPage.form().login(testUser);
+ assertCurrentUrlStartsWith(testRealmAccountPage);
+ }
+
+ @Test
+ public void failureResetTime() {
+ int secondsToWait = 3;
+
+ bruteForceDetectionPage.form().setProtectionEnabled(true);
+ bruteForceDetectionPage.form().setMaxLoginFailures("2");
+ bruteForceDetectionPage.form().setFailureResetTimeSelect(SecurityDefenses.TimeSelectValues.SECONDS);
+ bruteForceDetectionPage.form().setFailureResetTimeInput(String.valueOf(secondsToWait));
+ bruteForceDetectionPage.form().save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountPage.navigateTo();
+
+ setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+ testRealmLoginPage.form().login(testUser);
+ waitForFeedbackText("Invalid username or password.");
+ Date endTime = new Date(new Date().getTime() + secondsToWait * 1000);
+
+ while (new Date().compareTo(endTime) < 0) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ testRealmLoginPage.form().login(testUser);
+ waitForFeedbackText("Invalid username or password.");
+
+ setPasswordFor(testUser, PASSWORD);
+ testRealmLoginPage.form().login(testUser);
+ assertCurrentUrlStartsWith(testRealmAccountPage);
+ }
+
+ @Test
+ public void userUnlockTest() {
+ bruteForceDetectionPage.form().setProtectionEnabled(true);
+ bruteForceDetectionPage.form().setMaxLoginFailures("1");
+ bruteForceDetectionPage.form().setWaitIncrementSelect(SecurityDefenses.TimeSelectValues.MINUTES);
+ bruteForceDetectionPage.form().setWaitIncrementInput("10");
+ bruteForceDetectionPage.form().save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountPage.navigateTo();
+
+ setPasswordFor(testUser, PASSWORD + "-mismatch");
+
+ testRealmLoginPage.form().login(testUser);
+
+ usersPage.navigateTo();
+
+ usersPage.table().searchUsers(testUser.getUsername());
+ usersPage.table().editUser(testUser.getUsername());
+ userAttributesPage.form().unlockUser();
+
+ testRealmAccountPage.navigateTo();
+
+ setPasswordFor(testUser, PASSWORD);
+
+ testRealmLoginPage.form().login(testUser);
+ assertCurrentUrlStartsWith(testRealmAccountPage);
+ }
+
+ private void waitForFeedbackText(String text) {
+ waitGui().until().element(By.className("kc-feedback-text"))
+ .text().contains(text);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java
new file mode 100644
index 0000000..701e798
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java
@@ -0,0 +1,26 @@
+package org.keycloak.testsuite.console.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.roles.Roles;
+import org.keycloak.testsuite.console.page.users.User;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractRolesTest extends AbstractConsoleTest {
+
+ @Page
+ protected Roles rolesPage;
+
+ @Page
+ protected User userPage;
+
+ @Before
+ public void beforeRolesTest() {
+// configure().roles();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java
new file mode 100644
index 0000000..2f3bd8e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java
@@ -0,0 +1,61 @@
+package org.keycloak.testsuite.console.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
+import org.keycloak.testsuite.console.page.roles.DefaultRoles;
+import org.keycloak.testsuite.console.page.users.UserRoleMappings;
+import org.keycloak.testsuite.console.page.users.Users;
+
+/**
+ * Created by fkiss.
+ */
+public class DefaultRolesTest extends AbstractRolesTest {
+
+ @Page
+ private DefaultRoles defaultRolesPage;
+
+ @Page
+ private UserRoleMappings userRolesPage;
+
+ private RoleRepresentation defaultRoleRep;
+
+ @Page
+ private Users users;
+
+ @Before
+ public void beforeDefaultRolesTest() {
+ // create a role via admin client
+ defaultRoleRep = new RoleRepresentation("default-role", "");
+ rolesPage.rolesResource().create(defaultRoleRep);
+
+ defaultRolesPage.navigateTo();
+ // navigate to default roles page
+// rolesPage.tabs().defaultRoles();
+ }
+
+ @Test
+ public void defaultRoleAssignedToNewUser() {
+
+ String defaultRoleName = defaultRoleRep.getName();
+
+ defaultRolesPage.form().addAvailableRole(defaultRoleName);
+ assertFlashMessageSuccess();
+
+ UserRepresentation newUser = new UserRepresentation();
+ newUser.setUsername("new_user");
+
+ createUserWithAdminClient(testRealmResource(), newUser);
+ users.navigateTo();
+ users.table().search(newUser.getUsername());
+ users.table().clickUser(newUser.getUsername());
+
+ userPage.tabs().roleMappings();
+ assertTrue(userRolesPage.form().isAssignedRole(defaultRoleName));
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/RealmRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/RealmRolesTest.java
new file mode 100644
index 0000000..f92ccac
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/roles/RealmRolesTest.java
@@ -0,0 +1,229 @@
+package org.keycloak.testsuite.console.roles;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+import org.keycloak.testsuite.console.page.roles.RealmRoles;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.console.page.roles.CreateRole;
+import org.keycloak.testsuite.console.page.roles.Role;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class RealmRolesTest extends AbstractRolesTest {
+
+ @Page
+ private RealmRoles realmRolesPage;
+ @Page
+ private CreateRole createRolePage;
+ @Page
+ private Role rolePage;
+
+ private RoleRepresentation testRole;
+
+ @Before
+ public void beforeTestAddNewRole() {
+ testRole = new RoleRepresentation("test_role", "role description");
+ realmRolesPage.navigateTo();
+ }
+
+ public void addRole(RoleRepresentation roleRep) {
+ assertCurrentUrlEquals(realmRolesPage);
+ realmRolesPage.table().addRole();
+ assertCurrentUrlEquals(createRolePage);
+ createRolePage.form().setBasicAttributes(roleRep);
+ createRolePage.form().save();
+ assertFlashMessageSuccess();
+ createRolePage.form().setCompositeRoles(roleRep);
+ // TODO add verification of notification message when KEYCLOAK-1497 gets resolved
+ }
+
+ public void updateRole(RoleRepresentation roleRep) {
+ assertCurrentUrlEquals(realmRolesPage);
+ realmRolesPage.table().editRole(roleRep.getName());
+// assertCurrentUrl(role); // can't do this, role id needed as uri param
+ rolePage.form().setBasicAttributes(roleRep);
+ rolePage.form().save();
+ assertFlashMessageSuccess();
+ rolePage.form().setCompositeRoles(roleRep);
+ }
+
+ public void assertBasicRoleAttributesEqual(RoleRepresentation r1, RoleRepresentation r2) {
+ assertEquals(r1.getName(), r2.getName());
+ assertEquals(r1.getDescription(), r2.getDescription());
+ assertEquals(r1.isComposite(), r2.isComposite());
+ }
+
+ @Test
+ public void crudRole() {
+ addRole(testRole);
+
+ configure().roles();
+ RoleRepresentation foundRole = realmRolesPage.table().findRole(testRole.getName()); // search & get role from table
+ assertBasicRoleAttributesEqual(testRole, foundRole);
+ realmRolesPage.table().editRole(testRole.getName());
+ foundRole = rolePage.form().getBasicAttributes();
+ assertBasicRoleAttributesEqual(testRole, foundRole);
+
+ testRole.setDescription("updated role description");
+ rolePage.form().setDescription(testRole.getDescription());
+ rolePage.form().save();
+ assertFlashMessageSuccess();
+
+ configure().roles();
+ foundRole = realmRolesPage.table().findRole(testRole.getName()); // search & get role from table
+ assertBasicRoleAttributesEqual(testRole, foundRole);
+
+ // delete from table
+ realmRolesPage.table().deleteRole(testRole.getName());
+ modalDialog.cancel();
+ assertTrue(realmRolesPage.table().containsRole(testRole.getName()));
+ realmRolesPage.table().deleteRole(testRole.getName());
+ modalDialog.confirmDeletion();
+ pause(250);
+ assertFalse(realmRolesPage.table().containsRole(testRole.getName()));
+
+ // add again
+ addRole(testRole);
+ // delete from page
+ rolePage.form().delete();
+ modalDialog.confirmDeletion();
+ assertCurrentUrlEquals(realmRolesPage);
+ }
+
+ @Test
+ @Ignore
+ public void testAddRoleWithLongName() {
+ String name = "hjewr89y1894yh98(*&*&$jhjkashd)*(&y8934h*&@#hjkahsdj";
+ addRole(new RoleRepresentation(name, ""));
+ assertNotNull(realmRolesPage.table().findRole(name));
+ }
+
+ @Test
+ public void testAddExistingRole() {
+ addRole(testRole);
+ assertFlashMessageSuccess();
+
+ configure().roles();
+ realmRolesPage.table().addRole();
+ createRolePage.form().setBasicAttributes(testRole);
+ createRolePage.form().save();
+ assertFlashMessageDanger();
+ }
+
+ public void createTestRoles(String namePrefix, int count) {
+ Timer.time();
+ for (int i = 0; i < count; i++) {
+ String roleName = String.format("%s%02d", namePrefix, i);
+ RoleRepresentation rr = new RoleRepresentation(roleName, "");
+ testRealmResource().roles().create(rr);
+ }
+ Timer.time("create " + count + " roles");
+ }
+
+// @Test
+ public void rolesPagination() {
+ createTestRoles("test_role_", 100);
+ realmRolesPage.navigateTo();
+ pause(100000);
+ }
+
+// @Test
+// public void addAndRemoveUserAndAssignRole() {
+// roleMappings.form().addAvailableRole("create-realm");
+// assertFlashMessageSuccess();
+//
+// roleMappings.form().removeAssignedRole("create-realm");
+// assertFlashMessageSuccess();
+//
+// users.navigateTo();
+// users.table().deleteUser(testUsername);
+// }
+// @Test // this should be moved to users tests
+// public void testRoleIsAvailableForUsers() {
+// RoleRepresentation role = new RoleRepresentation("User role", "");
+// roles.addRole(role);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// users.navigateTo();
+// users.viewAllUsers();
+// users.clickUser("admin");
+// user.tabs().roleMappings();
+// Select rolesSelect = new Select(driver.findElement(id("available")));
+// assertEquals("User role should be present in admin role mapping",
+// role.getName(), rolesSelect.getOptions().get(0).getText());
+// roles.navigateTo();
+// roles.deleteRole(role);
+// }
+//
+// @Ignore//KEYCLOAK-1497
+// @Test
+// public void testAddCompositeRole() {
+// UserRepresentation testUserRep = new UserRepresentation();
+// testUserRep.setUsername("usercomposite");
+//
+// RoleRepresentation compositeRole = new RoleRepresentation("compositeRole", "");
+// RoleRepresentation subRole1 = new RoleRepresentation("subRole1", "");
+// RoleRepresentation subRole2 = new RoleRepresentation("subRole2", "");
+// List<RoleRepresentation> testRoles = new ArrayList<>();
+// compositeRole.setComposite(true);
+// testRoles.add(compositeRole);
+// testRoles.add(subRole1);
+// testRoles.add(subRole2);
+//
+// //create roles and user
+// for (RoleRepresentation role : testRoles) {
+// roles.addRole(role);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+// roles.navigateTo();
+// assertEquals(role.getName(), roles.findRole(role.getName()).getName());
+// }
+// users.navigateTo();
+// createUser(testUserRep);
+// flashMessage.waitUntilPresent();
+// assertTrue(flashMessage.getText(), flashMessage.isSuccess());
+//
+// //adding subroles to composite role
+// roles.navigateTo();
+// roles.findRole(compositeRole.getName());
+// roles.clickRole(compositeRole);
+// roles.setCompositeRole(compositeRole);
+// roleMappings.addAvailableRole(subRole1.getName(), subRole2.getName());
+// //flashMessage.waitUntilPresent();
+// //assertTrue(flashMessage.getText(), flashMessage.isSuccess()); KEYCLOAK-1497
+//
+// //check if subroles work as expected
+// users.navigateTo();
+// users.findUser(testUserRep.getUsername());
+// users.clickUser(testUserRep.getUsername());
+// user.tabs().roleMappings();
+// roleMappings.addAvailableRole(compositeRole.getName());
+// assertTrue(roleMappings.isEffectiveRealmRolesComplete(compositeRole, subRole1, subRole2));
+//
+// //delete everything
+// roles.navigateTo();
+// roles.deleteRole(compositeRole);
+// roles.navigateTo();
+// roles.deleteRole(subRole1);
+// roles.navigateTo();
+// roles.deleteRole(subRole2);
+// try {
+// Thread.sleep(2000);
+// } catch (InterruptedException e) {
+// e.printStackTrace();
+// }
+// users.navigateTo();
+// users.deleteUser(testUserRep.getUsername());
+// }
+//
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java
new file mode 100644
index 0000000..3ddf899
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.console.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.console.AbstractConsoleTest;
+import org.keycloak.testsuite.console.page.users.CreateUser;
+import org.keycloak.testsuite.console.page.users.Users;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public abstract class AbstractUserTest extends AbstractConsoleTest {
+
+ @Page
+ protected Users usersPage;
+ @Page
+ protected CreateUser createUserPage;
+
+ protected UserRepresentation newTestRealmUser;
+
+ @Before
+ public void beforeUserTest() {
+ newTestRealmUser = new UserRepresentation();
+// manage().users();
+ }
+
+ public void createUser(UserRepresentation user) {
+ assertCurrentUrlEquals(usersPage);
+ usersPage.table().addUser();
+ assertCurrentUrlStartsWith(createUserPage);
+ createUserPage.form().setValues(user);
+ createUserPage.form().save();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/RequiredUserActionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/RequiredUserActionsTest.java
new file mode 100644
index 0000000..9151698
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/RequiredUserActionsTest.java
@@ -0,0 +1,147 @@
+package org.keycloak.testsuite.console.users;
+
+import static org.jboss.arquillian.graphene.Graphene.waitGui;
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+import org.keycloak.testsuite.auth.page.account.Account;
+import org.keycloak.testsuite.auth.page.login.UpdateAccount;
+import org.keycloak.testsuite.auth.page.login.UpdatePassword;
+import org.keycloak.testsuite.console.page.authentication.RequiredActions;
+import org.keycloak.testsuite.console.page.users.UserAttributes;
+
+import static org.keycloak.testsuite.model.RequiredUserAction.TERMS_AND_CONDITIONS;
+import static org.keycloak.testsuite.model.RequiredUserAction.UPDATE_PASSWORD;
+import static org.keycloak.testsuite.model.RequiredUserAction.UPDATE_PROFILE;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ *
+ * @author tkyjovsk
+ * @author mhajas
+ */
+public class RequiredUserActionsTest extends AbstractUserTest {
+
+ @Page
+ private UserAttributes userAttributesPage;
+
+ @Page
+ private Account testRealmAccountPage;
+
+ @Page
+ private UpdateAccount testRealmUpdateAccountPage;
+
+ @Page
+ private UpdatePassword testRealmUpdatePasswordPage;
+
+ @Page
+ private RequiredActions requiredActionsPage;
+
+ @FindBy(css = "kc-feedback-text")
+ protected WebElement feedbackText;
+
+ public void waitForFeedbackText(String text) {
+ waitGui().until().element(By.className("kc-feedback-text"))
+ .text().contains(text);
+ }
+
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmAccountPage.setAuthRealm(TEST);
+ testRealmUpdateAccountPage.setAuthRealm(TEST);
+ testRealmUpdatePasswordPage.setAuthRealm(TEST);
+ }
+
+ @Before
+ public void beforeRequiredActionsTest() {
+// usersPage.table().viewAllUsers();
+// usersPage.table().clickUser(testUser.getUsername());
+ userAttributesPage.setId(testUser.getId());
+ userAttributesPage.navigateTo();
+ }
+
+ @Test
+ public void updatePassword() {
+ userAttributesPage.form().addRequiredAction(UPDATE_PASSWORD.getActionName());
+ userAttributesPage.form().save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountPage.navigateTo();
+
+ testRealmLoginPage.form().login(testUser);
+ waitForFeedbackText("You need to change your password to activate your account.");
+
+ testRealmUpdatePasswordPage.updatePasswords(null, null);
+ waitForFeedbackText("Please specify password.");
+
+ testRealmUpdatePasswordPage.updatePasswords(PASSWORD, null);
+ waitForFeedbackText("Passwords don't match.");
+
+ testRealmUpdatePasswordPage.updatePasswords(PASSWORD, PASSWORD + "-mismatch");
+ waitForFeedbackText("Passwords don't match.");
+
+ testRealmUpdatePasswordPage.updatePasswords(PASSWORD, PASSWORD);
+ assertCurrentUrlStartsWith(testRealmAccountPage);
+ }
+
+ @Test
+ public void updateProfile() {
+ userAttributesPage.form().addRequiredAction(UPDATE_PROFILE.getActionName());
+ userAttributesPage.form().save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountPage.navigateTo();
+
+ testRealmLoginPage.form().login(testUser);
+ waitForFeedbackText("You need to update your user profile to activate your account.");
+
+ testUser.setEmail(null);
+ testUser.setFirstName(null);
+ testUser.setLastName(null);
+ testRealmUpdateAccountPage.updateAccount(testUser);
+ waitForFeedbackText("Please specify email.");
+
+ testUser.setEmail("test@email.test");
+ testRealmUpdateAccountPage.updateAccount(testUser);
+ waitForFeedbackText("Please specify first name.");
+
+ testUser.setFirstName("test");
+ testRealmUpdateAccountPage.updateAccount(testUser);
+ waitForFeedbackText("Please specify last name.");
+
+ testUser.setLastName("user");
+ testRealmUpdateAccountPage.updateAccount(testUser);
+ assertCurrentUrlStartsWith(testRealmAccountPage);
+ }
+
+ @Test
+ public void termsAndConditions() {
+ requiredActionsPage.navigateTo();
+ requiredActionsPage.clickTermsAndConditionEnabled();
+
+ manage().users();
+ usersPage.table().viewAllUsers();
+ usersPage.table().clickUser(testUser.getUsername());
+
+ userAttributesPage.form().addRequiredAction(TERMS_AND_CONDITIONS.getActionName());
+ userAttributesPage.form().save();
+ assertFlashMessageSuccess();
+
+ testRealmAccountPage.navigateTo();
+
+ testRealmLoginPage.form().login(testUser);
+
+ driver.findElement(By.xpath("//div[@id='kc-header-wrapper' and text()[contains(.,'Terms and Conditions')]]"));
+ }
+
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UserAttributesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UserAttributesTest.java
new file mode 100644
index 0000000..9d99c85
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UserAttributesTest.java
@@ -0,0 +1,90 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.console.users;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.Users.setPasswordFor;
+import org.keycloak.testsuite.console.page.users.UserAttributes;
+
+/**
+ *
+ * @author Filip Kiss
+ * @author tkyjovsk
+ */
+public class UserAttributesTest extends AbstractUserTest {
+
+ @Page
+ private UserAttributes userAttributesPage;
+
+ @Before
+ public void beforeUserAttributesTest() {
+ usersPage.navigateTo();
+ }
+
+ @Test
+ public void invalidEmail() {
+ String testUsername = "testUserInvEmail";
+ String invalidEmail = "user.redhat.com";
+ newTestRealmUser.setUsername(testUsername);
+ setPasswordFor(newTestRealmUser, "pass");
+ newTestRealmUser.setEmail(invalidEmail);
+ createUser(newTestRealmUser);
+ assertFlashMessageDanger();
+
+ userAttributesPage.backToUsersViaBreadcrumb();
+ assertNull(usersPage.table().findUser(testUsername));
+ }
+
+ @Test
+ public void noUsername() {
+ createUser(newTestRealmUser);
+ assertFlashMessageDanger();
+ }
+
+ @Test
+ public void existingUser() {
+ String testUsername = "test_duplicated_user";
+ newTestRealmUser.setUsername(testUsername);
+ createUser(newTestRealmUser);
+ assertFlashMessageSuccess();
+
+ userAttributesPage.backToUsersViaBreadcrumb();
+ assertNotNull(usersPage.table().findUser(testUsername));
+
+ UserRepresentation testUser2 = new UserRepresentation();
+ testUser2.setUsername(testUsername);
+ createUser(testUser2);
+ assertFlashMessageDanger();
+ }
+
+ @Test
+ public void disabledUser() {
+ UserRepresentation disabledUser = new UserRepresentation();
+ disabledUser.setEnabled(false);
+ disabledUser.setUsername("disabled_user");
+ createUser(disabledUser);
+ assertFlashMessageSuccess();
+ // TODO try to log in
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UsersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UsersTest.java
new file mode 100644
index 0000000..ed4000d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/users/UsersTest.java
@@ -0,0 +1,52 @@
+package org.keycloak.testsuite.console.users;
+
+import javax.ws.rs.core.Response;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.keycloak.representations.idm.UserRepresentation;
+import static org.keycloak.testsuite.admin.ApiUtil.getCreatedId;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.keycloak.testsuite.util.Timer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class UsersTest extends AbstractUserTest {
+
+ @Before
+ public void beforeUserAttributesTest() {
+ usersPage.navigateTo();
+ }
+
+ public void createTestUsers(String usernamePrefix, int count) {
+// Timer.time();
+ for (int i = 0; i < count; i++) {
+ String username = String.format("%s%03d", usernamePrefix, i);
+ UserRepresentation u = createUserRepresentation(
+ username,
+ username + "@email.test",
+ "First",
+ "Last",
+ true);
+ Timer.time();
+ Response r = testRealmResource().users().create(u);
+ String id = getCreatedId(r);
+ r.close();
+ Timer.time("create user");
+ }
+// Timer.time("create " + count + " users");
+ }
+
+ @Test
+ @Ignore
+ public void usersPagination() {
+ createTestUsers("test_user_", 100);
+
+ usersPage.navigateTo();
+ usersPage.table().viewAllUsers();
+ pause(120000);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AttributesAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AttributesAssert.java
new file mode 100644
index 0000000..2974a90
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AttributesAssert.java
@@ -0,0 +1,42 @@
+package org.keycloak.testsuite.util;
+
+import java.util.List;
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class AttributesAssert {
+
+ public static void assertEqualsStringAttributes(String a1, String a2) {
+ if (a1 == null) {
+ a1 = "";
+ }
+ if (a2 == null) {
+ a2 = "";
+ }
+ assertEquals(a1, a2);
+ }
+
+ public static void assertEqualsBooleanAttributes(Boolean a1, Boolean a2) {
+ if (a1 == null) {
+ a1 = false;
+ }
+ if (a2 == null) {
+ a2 = false;
+ }
+ assertEquals(a1, a2);
+ }
+
+ public static void assertEqualsListAttributes(List a1, List a2) {
+ if (a1 == null || a1.isEmpty()) {
+ a1 = null;
+ }
+ if (a2 == null || a2.isEmpty()) {
+ a2 = null;
+ }
+ assertEquals(a1, a2);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java
new file mode 100644
index 0000000..4ade10b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java
@@ -0,0 +1,54 @@
+package org.keycloak.testsuite.util;
+
+import java.io.IOException;
+import javax.mail.MessagingException;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMessage.RecipientType;
+import javax.mail.internet.MimeMultipart;
+import org.jboss.logging.Logger;
+import static org.junit.Assert.*;
+
+public class MailAssert {
+
+ private static final Logger log = Logger.getLogger(MailAssert.class);
+
+ public static String assertEmailAndGetUrl(String from, String recipient, String content) {
+
+ try {
+ MimeMessage message = MailServer.getLastReceivedMessage();
+ assertNotNull("There is no received email.", message);
+ assertEquals(recipient, message.getRecipients(RecipientType.TO)[0].toString());
+ assertEquals(from, message.getFrom()[0].toString());
+
+ String messageContent;
+ if (message.getContent() instanceof MimeMultipart) {
+ MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
+
+ messageContent = String.valueOf(mimeMultipart.getBodyPart(0).getContent());
+ } else {
+ messageContent = String.valueOf(message.getContent());
+ }
+ logMessageContent(messageContent);
+ String errorMessage = "Email content should contains \"" + content
+ + "\", but it doesn't.\nEmail content:\n" + messageContent + "\n";
+
+ assertTrue(errorMessage, messageContent.contains(content));
+ for (String string : messageContent.split("\n")) {
+ if (string.contains("http://")) {
+ return string;
+ }
+ }
+ return null;
+ } catch (IOException | MessagingException | InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static void logMessageContent(String messageContent) {
+ log.debug("---------------------");
+ log.debug(messageContent);
+ log.debug("---------------------");
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java
new file mode 100644
index 0000000..972027d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java
@@ -0,0 +1,77 @@
+package org.keycloak.testsuite.util;
+
+import com.icegreen.greenmail.util.GreenMail;
+import com.icegreen.greenmail.util.ServerSetup;
+import java.io.IOException;
+import javax.mail.MessagingException;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMessage.RecipientType;
+import javax.mail.internet.MimeMultipart;
+import org.jboss.logging.Logger;
+import static org.keycloak.testsuite.util.MailServerConfiguration.*;
+
+public class MailServer {
+
+ private static final Logger log = Logger.getLogger(MailServer.class);
+
+ private static GreenMail greenMail;
+
+ public static void main(String[] args) throws Exception {
+ MailServer.start();
+ MailServer.createEmailAccount("test@email.test", "password");
+
+ try {
+ while (true) {
+ int c = greenMail.getReceivedMessages().length;
+
+ if (greenMail.waitForIncomingEmail(Long.MAX_VALUE, c + 1)) {
+ MimeMessage m = greenMail.getReceivedMessages()[c++];
+ log.info("-------------------------------------------------------");
+ log.info("Received mail to " + m.getRecipients(RecipientType.TO)[0]);
+ if (m.getContent() instanceof MimeMultipart) {
+ MimeMultipart mimeMultipart = (MimeMultipart) m.getContent();
+ for (int i = 0; i < mimeMultipart.getCount(); i++) {
+ log.info("----");
+ log.info(mimeMultipart.getBodyPart(i).getContentType() + ":\n");
+ log.info(mimeMultipart.getBodyPart(i).getContent());
+ }
+ } else {
+ log.info("\n" + m.getContent());
+ }
+ log.info("-------------------------------------------------------");
+ }
+ }
+ } catch (IOException | InterruptedException | MessagingException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static void start() {
+ ServerSetup setup = new ServerSetup(Integer.parseInt(PORT), HOST, "smtp");
+
+ greenMail = new GreenMail(setup);
+ greenMail.start();
+
+ log.info("--Started mail server (" + HOST + ":" + PORT + ")--");
+ }
+
+ public static void stop() {
+ if (greenMail != null) {
+ log.info("--Stopping mail server (localhost:3025)--");
+ greenMail.stop();
+ }
+ }
+
+ public static void createEmailAccount(String email, String password) {
+ log.debug("--Creating email account " + email + "--");
+ greenMail.setUser(email, password);
+ }
+
+ public static MimeMessage getLastReceivedMessage() throws InterruptedException {
+ if (greenMail.waitForIncomingEmail(1)) {
+ return greenMail.getReceivedMessages()[greenMail.getReceivedMessages().length - 1];
+ }
+ return null;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/TestEventsLogger.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/TestEventsLogger.java
new file mode 100644
index 0000000..249a19b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/TestEventsLogger.java
@@ -0,0 +1,44 @@
+package org.keycloak.testsuite.util;
+
+import org.jboss.logging.Logger;
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+/**
+ *
+ * @author Petr Mensik
+ * @author tkyjovsk
+ */
+public class TestEventsLogger extends RunListener {
+
+ private Logger log(Description d) {
+ return Logger.getLogger(d.getClassName());
+ }
+
+ private String getMessage(Description d, String status) {
+ return String.format("[%s] %s() %s", d.getTestClass().getSimpleName(), d.getMethodName(), status);
+ }
+
+ @Override
+ public void testStarted(Description d) throws Exception {
+ log(d).info(getMessage(d, "STARTED"));
+ }
+
+ @Override
+ public void testFailure(Failure f) throws Exception {
+ Description d = f.getDescription();
+ log(d).error(getMessage(d, "FAILED"));
+ }
+
+ @Override
+ public void testIgnored(Description d) throws Exception {
+ log(d).warn(getMessage(d, "IGNORED\n\n"));
+ }
+
+ @Override
+ public void testFinished(Description d) throws Exception {
+ log(d).info(getMessage(d, "FINISHED\n\n"));
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java
new file mode 100644
index 0000000..255e450
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java
@@ -0,0 +1,95 @@
+package org.keycloak.testsuite.util;
+
+import javax.ws.rs.core.UriBuilder;
+import org.keycloak.testsuite.page.AbstractPage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class URLAssert {
+
+ public static void assertCurrentUrlEquals(AbstractPage page) {
+ assertCurrentUrlEquals(page.getDriver(), page);
+ }
+
+ public static void assertCurrentUrlEquals(WebDriver driver, final AbstractPage page) {
+// WebDriverWait wait = new WebDriverWait(driver, 1);
+// ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
+//
+// @Override
+// public Boolean apply(WebDriver wd) {
+// return startsWithNormalized(wd.getCurrentUrl(), page.toString());
+// }
+// };
+// wait.until(urlStartsWith);
+ assertEqualsNormalized(driver.getCurrentUrl(), page.toString());
+ }
+
+ public static void assertCurrentUrlStartsWith(AbstractPage page) {
+ assertCurrentUrlStartsWith(page.getDriver(), page.toString());
+ }
+
+ public static void assertCurrentUrlStartsWith(WebDriver driver, final String url) {
+// WebDriverWait wait = new WebDriverWait(driver, 1);
+// ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
+//
+// @Override
+// public Boolean apply(WebDriver wd) {
+// return startsWithNormalized(wd.getCurrentUrl(), url);
+// }
+// };
+// wait.until(urlStartsWith);
+ assertTrue(startsWithNormalized(driver.getCurrentUrl(), url));
+ }
+
+ public static void assertCurrentUrlDoesntStartWith(AbstractPage page) {
+ assertCurrentUrlDoesntStartWith(page.getDriver(), page.toString());
+ }
+
+ public static void assertCurrentUrlDoesntStartWith(WebDriver driver, final String url) {
+// WebDriverWait wait = new WebDriverWait(driver, 1, 250);
+// ExpectedCondition<Boolean> urlDoesntStartWith = new ExpectedCondition<Boolean>() {
+//
+// @Override
+// public Boolean apply(WebDriver wd) {
+// return !startsWithNormalized(wd.getCurrentUrl(), url);
+// }
+// };
+// wait.until(urlDoesntStartWith);
+ assertFalse(startsWithNormalized(driver.getCurrentUrl(), url));
+ }
+
+ // this normalization is needed because of slash-encoding in uri fragment (the part after #)
+ public static String normalizeUri(String uri) {
+ return UriBuilder.fromUri(uri).build().toASCIIString();
+ }
+
+ public static boolean startsWithNormalized(String str1, String str2) {
+ String uri1 = normalizeUri(str1);
+ String uri2 = normalizeUri(str2);
+ return uri1.startsWith(uri2);
+ }
+
+ public static void assertEqualsNormalized(String str1, String str2) {
+ assertEquals(normalizeUri(str1), normalizeUri(str2));
+ }
+
+
+
+ public static void assertCurrentUrlStartsWithLoginUrlOf(PageWithLoginUrl page) {
+ assertCurrentUrlStartsWithLoginUrlOf(page.getDriver(), page);
+ }
+
+ public static void assertCurrentUrlStartsWithLoginUrlOf(WebDriver driver, PageWithLoginUrl page) {
+ assertCurrentUrlStartsWith(driver, page.getOIDCLoginUrl().toString());
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/context.xml
new file mode 100644
index 0000000..ef49048
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/context.xml
@@ -0,0 +1,3 @@
+<Context path="/%CONTEXT_PATH%">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <!--
+ <Set name="adapterConfig">
+ <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <Set name="realm">tomcat</Set>
+ <Set name="resource">customer-portal</Set>
+ <Set name="authServerUrl">http://localhost:8180/auth</Set>
+ <Set name="sslRequired">external</Set>
+ <Set name="credentials">
+ <Map>
+ <Entry>
+ <Item>secret</Item>
+ <Item>password</Item>
+ </Entry>
+ </Map>
+ </Set>
+ <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+ </New>
+ </Set>
+ -->
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
new file mode 100644
index 0000000..3620170
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "demo",
+ "resource" : "customer-db",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "bearer-only" : true,
+ "enable-cors" : true
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak-relative.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak-relative.json
new file mode 100644
index 0000000..c457468
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak-relative.json
@@ -0,0 +1,9 @@
+{
+ "realm" : "demo",
+ "resource" : "customer-db",
+ "auth-server-url": "/auth",
+ "ssl-required" : "external",
+ "bearer-only" : true,
+ "enable-cors" : true
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
new file mode 100644
index 0000000..8fbc2d2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>customer-db</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.CustomerDatabaseServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
new file mode 100644
index 0000000..aa10ca2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-db-error-page">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <!--
+ <Set name="adapterConfig">
+ <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <Set name="realm">tomcat</Set>
+ <Set name="resource">customer-portal</Set>
+ <Set name="authServerUrl">http://localhost:8180/auth</Set>
+ <Set name="sslRequired">external</Set>
+ <Set name="credentials">
+ <Map>
+ <Entry>
+ <Item>secret</Item>
+ <Item>password</Item>
+ </Entry>
+ </Map>
+ </Set>
+ <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+ </New>
+ </Set>
+ -->
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100644
index 0000000..3620170
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "demo",
+ "resource" : "customer-db",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "bearer-only" : true,
+ "enable-cors" : true
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100644
index 0000000..496490d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>customer-db-error-page</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.CustomerDatabaseServlet</servlet-class>
+ </servlet>
+ <servlet>
+ <servlet-name>Error Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>Error Servlet</servlet-name>
+ <url-pattern>/error.html</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Errors</web-resource-name>
+ <url-pattern>/error.html</url-pattern>
+ </web-resource-collection>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>demo</realm-name>
+ <form-login-config>
+ <form-login-page>/error.html</form-login-page>
+ <form-error-page>/error.html</form-error-page>
+ </form-login-config>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <!--
+ <Set name="adapterConfig">
+ <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <Set name="realm">tomcat</Set>
+ <Set name="resource">customer-portal</Set>
+ <Set name="authServerUrl">http://localhost:8180/auth</Set>
+ <Set name="sslRequired">external</Set>
+ <Set name="credentials">
+ <Map>
+ <Entry>
+ <Item>secret</Item>
+ <Item>password</Item>
+ </Entry>
+ </Map>
+ </Set>
+ <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+ </New>
+ </Set>
+ -->
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..b75c1d5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak.json
@@ -0,0 +1,11 @@
+{
+ "realm": "demo",
+ "resource": "customer-portal",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "expose-token": true,
+ "credentials": {
+ "secret": "password"
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-cookie.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-cookie.json
new file mode 100644
index 0000000..9d59c69
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-cookie.json
@@ -0,0 +1,12 @@
+{
+ "realm": "demo",
+ "resource": "customer-cookie-portal",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "expose-token": true,
+ "token-store": "cookie",
+ "credentials": {
+ "secret": "password"
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-relative.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-relative.json
new file mode 100644
index 0000000..a796d1a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/keycloak-relative.json
@@ -0,0 +1,9 @@
+{
+ "realm": "demo",
+ "resource": "customer-portal",
+ "auth-server-url": "/auth",
+ "ssl-required" : "external",
+ "credentials": {
+ "secret": "password"
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..285d226
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>customer-portal</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.CustomerServlet</servlet-class>
+ </servlet>
+ <servlet>
+ <servlet-name>Error Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>Error Servlet</servlet-name>
+ <url-pattern>/error.html</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Errors</web-resource-name>
+ <url-pattern>/error.html</url-pattern>
+ </web-resource-collection>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>demo</realm-name>
+ <form-login-config>
+ <form-login-page>/error.html</form-login-page>
+ <form-error-page>/error.html</form-error-page>
+ </form-login-config>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
new file mode 100644
index 0000000..5b82ec6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
@@ -0,0 +1,161 @@
+{
+ "id": "demo",
+ "realm": "demo",
+ "enabled": true,
+ "accessTokenLifespan": 3000,
+ "accessCodeLifespan": 10,
+ "accessCodeLifespanUserAction": 6000,
+ "sslRequired": "external",
+ "registrationAllowed": false,
+ "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+ "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "requiredCredentials": [ "password" ],
+ "users" : [
+ {
+ "username" : "bburke@redhat.com",
+ "enabled": true,
+ "email" : "bburke@redhat.com",
+ "firstName": "Bill",
+ "lastName": "Burke",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user", "admin" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
+ }
+ ],
+ "roles" : {
+ "realm" : [
+ {
+ "name": "user",
+ "description": "User privileges"
+ },
+ {
+ "name": "admin",
+ "description": "Administrator privileges"
+ }
+ ]
+ },
+ "scopeMappings": [
+ {
+ "client": "third-party",
+ "roles": ["user"]
+ },
+ {
+ "client": "customer-portal",
+ "roles": ["user"]
+ },
+ {
+ "client": "product-portal",
+ "roles": ["user"]
+ }
+
+ ],
+ "clients": [
+ {
+ "clientId": "customer-portal",
+ "enabled": true,
+ "adminUrl": "/customer-portal",
+ "baseUrl": "/customer-portal",
+ "redirectUris": [
+ "/customer-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "clientId": "customer-cookie-portal",
+ "enabled": true,
+ "baseUrl": "/customer-cookie-portal",
+ "redirectUris": [
+ "/customer-cookie-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "clientId": "customer-portal-js",
+ "enabled": true,
+ "publicClient": true,
+ "adminUrl": "/customer-portal-js",
+ "baseUrl": "/customer-portal-js",
+ "redirectUris": [
+ "/customer-portal-js/*"
+ ]
+ },
+ {
+ "clientId": "customer-portal-cli",
+ "enabled": true,
+ "publicClient": true,
+ "redirectUris": [
+ "urn:ietf:wg:oauth:2.0:oob",
+ "http://localhost"
+ ]
+ },
+ {
+ "clientId": "product-portal",
+ "enabled": true,
+ "adminUrl": "/product-portal",
+ "baseUrl": "/product-portal",
+ "redirectUris": [
+ "/product-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "clientId": "secure-portal",
+ "enabled": true,
+ "adminUrl": "/secure-portal",
+ "baseUrl": "/secure-portal",
+ "redirectUris": [
+ "/secure-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "clientId": "session-portal",
+ "enabled": true,
+ "adminUrl": "/session-portal",
+ "baseUrl": "/session-portal",
+ "redirectUris": [
+ "/session-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "clientId": "input-portal",
+ "enabled": true,
+ "adminUrl": "/input-portal",
+ "baseUrl": "/input-portal",
+ "redirectUris": [
+ "/input-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "clientId": "third-party",
+ "enabled": true,
+ "redirectUris": [
+ "/oauth-client/*",
+ "/oauth-client-cdi/*"
+ ],
+ "secret": "password"
+ }
+ ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <!--
+ <Set name="adapterConfig">
+ <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <Set name="realm">tomcat</Set>
+ <Set name="resource">customer-portal</Set>
+ <Set name="authServerUrl">http://localhost:8180/auth</Set>
+ <Set name="sslRequired">external</Set>
+ <Set name="credentials">
+ <Map>
+ <Entry>
+ <Item>secret</Item>
+ <Item>password</Item>
+ </Entry>
+ </Map>
+ </Set>
+ <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+ </New>
+ </Set>
+ -->
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..a934e97
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "demo",
+ "resource" : "input-portal",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://${my.host.name}:8180/auth",
+ "ssl-required" : "external",
+ "credentials" : {
+ "secret": "password"
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..81c4e28
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>input-portal</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/secured/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
new file mode 100644
index 0000000..af5341b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
@@ -0,0 +1,16 @@
+<jboss-deployment-structure>
+ <deployment>
+ <dependencies>
+ <!-- the Demo code uses classes in these modules. These are optional to import if you are not using
+ Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
+ <module name="org.apache.httpcomponents"/>
+
+ <!--These are needed when keycloak adapter libs are bundled in war.-->
+ <module name="org.codehaus.jackson.jackson-xc" />
+ <module name="org.codehaus.jackson.jackson-mapper-asl" />
+ <module name="org.bouncycastle" />
+ <module name="org.jboss.xnio" />
+
+ </dependencies>
+ </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant1-keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant1-keycloak.json
new file mode 100644
index 0000000..14b3f7b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant1-keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "tenant1",
+ "resource" : "multi-tenant",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "credentials" : {
+ "secret": "password"
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant2-keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant2-keycloak.json
new file mode 100644
index 0000000..bfb1814
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/classes/tenant2-keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "tenant2",
+ "resource" : "multi-tenant",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "credentials" : {
+ "secret": "password"
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/web.xml
new file mode 100644
index 0000000..6f830ae
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/multi-tenant/WEB-INF/web.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>multi-tenant</module-name>
+
+ <servlet>
+ <servlet-name>MultiTenantServlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.MultiTenantServlet</servlet-class>
+ </servlet>
+
+ <context-param>
+ <param-name>keycloak.config.resolver</param-name>
+ <param-value>org.keycloak.testsuite.adapter.servlet.MultiTenantResolver</param-value>
+ </context-param>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ </login-config>
+
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <!--
+ <Set name="adapterConfig">
+ <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <Set name="realm">tomcat</Set>
+ <Set name="resource">customer-portal</Set>
+ <Set name="authServerUrl">http://localhost:8180/auth</Set>
+ <Set name="sslRequired">external</Set>
+ <Set name="credentials">
+ <Map>
+ <Entry>
+ <Item>secret</Item>
+ <Item>password</Item>
+ </Entry>
+ </Map>
+ </Set>
+ <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+ </New>
+ </Set>
+ -->
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..7dbe680
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "demo",
+ "resource" : "product-portal",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "credentials" : {
+ "secret": "password"
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak-relative.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak-relative.json
new file mode 100644
index 0000000..9ef62ff
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak-relative.json
@@ -0,0 +1,9 @@
+{
+ "realm" : "demo",
+ "resource" : "product-portal",
+ "auth-server-url" : "/auth",
+ "ssl-required" : "external",
+ "credentials" : {
+ "secret": "password"
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..ebefac0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>product-portal</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.ProductServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <!--
+ <Set name="adapterConfig">
+ <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <Set name="realm">tomcat</Set>
+ <Set name="resource">customer-portal</Set>
+ <Set name="authServerUrl">http://localhost:8180/auth</Set>
+ <Set name="sslRequired">external</Set>
+ <Set name="credentials">
+ <Map>
+ <Entry>
+ <Item>secret</Item>
+ <Item>password</Item>
+ </Entry>
+ </Map>
+ </Set>
+ <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+ </New>
+ </Set>
+ -->
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..6b8d13f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "demo",
+ "resource" : "secure-portal",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "credentials" : {
+ "secret": "password"
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..4ee9cd1
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>secure-portal</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.CallAuthenticatedServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/META-INF/context.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/META-INF/context.xml
new file mode 100644
index 0000000..8e2c70d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-portal">
+ <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..5456b16
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <!--
+ <Set name="adapterConfig">
+ <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <Set name="realm">tomcat</Set>
+ <Set name="resource">customer-portal</Set>
+ <Set name="authServerUrl">http://localhost:8180/auth</Set>
+ <Set name="sslRequired">external</Set>
+ <Set name="credentials">
+ <Map>
+ <Entry>
+ <Item>secret</Item>
+ <Item>password</Item>
+ </Entry>
+ </Map>
+ </Set>
+ <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+ </New>
+ </Set>
+ -->
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..d07b738
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm" : "demo",
+ "resource" : "session-portal",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://${my.host.name}:8180/auth",
+ "ssl-required" : "external",
+ "credentials" : {
+ "secret": "password"
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..da08586
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>session-portal</module-name>
+
+ <servlet>
+ <servlet-name>Servlet</servlet-name>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.SessionServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Servlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Users</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant1-realm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant1-realm.json
new file mode 100644
index 0000000..b565c05
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant1-realm.json
@@ -0,0 +1,82 @@
+{
+ "id": "tenant1",
+ "realm": "tenant1",
+ "enabled": true,
+ "accessTokenLifespan": 3000,
+ "accessCodeLifespan": 10,
+ "accessCodeLifespanUserAction": 6000,
+ "sslRequired": "external",
+ "registrationAllowed": false,
+ "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+ "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "requiredCredentials": [ "password" ],
+ "users" : [
+ {
+ "username" : "bburke@redhat.com",
+ "enabled": true,
+ "email" : "bburke@redhat.com",
+ "firstName": "Bill",
+ "lastName": "Burke",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "multi-tenant": [ "user" ]
+ }
+ },
+ {
+ "username" : "user-tenant1",
+ "enabled": true,
+ "email" : "user-tenant1@redhat.com",
+ "firstName": "Bill",
+ "lastName": "Burke",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "user-tenant1" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "multi-tenant": [ "user" ]
+ }
+ }
+ ],
+ "roles" : {
+ "realm" : [
+ {
+ "name": "user",
+ "description": "User privileges"
+ }
+ ]
+ },
+ "scopeMappings": [
+ {
+ "client": "multi-tenant",
+ "roles": ["user"]
+ }
+
+ ],
+ "clients": [
+ {
+ "clientId": "multi-tenant",
+ "enabled": true,
+ "adminUrl": "/multi-tenant",
+ "baseUrl": "/multi-tenant",
+ "redirectUris": [
+ "/multi-tenant/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "clientId": "multitenant",
+ "enabled": true,
+ "adminUrl": "/multitenant/tenant1",
+ "baseUrl": "/multitenant/tenant1",
+ "redirectUris": [
+ "/multitenant/tenant1/*"
+ ],
+ "secret": "password"
+ }
+ ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant2-realm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant2-realm.json
new file mode 100644
index 0000000..54b28a4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/tenant2-realm.json
@@ -0,0 +1,72 @@
+{
+ "id": "tenant2",
+ "realm": "tenant2",
+ "enabled": true,
+ "accessTokenLifespan": 3000,
+ "accessCodeLifespan": 10,
+ "accessCodeLifespanUserAction": 6000,
+ "sslRequired": "external",
+ "registrationAllowed": false,
+ "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+ "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "requiredCredentials": [ "password" ],
+ "users" : [
+ {
+ "username" : "bburke@redhat.com",
+ "enabled": true,
+ "email" : "bburke@redhat.com",
+ "firstName": "Bill",
+ "lastName": "Burke",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "multi-tenant": [ "user" ]
+ }
+ },
+ {
+ "username" : "user-tenant2",
+ "enabled": true,
+ "email" : "user-tenant2@redhat.com",
+ "firstName": "Bill",
+ "lastName": "Burke",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "user-tenant2" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "multi-tenant": [ "user" ]
+ }
+ }
+ ],
+ "roles" : {
+ "realm" : [
+ {
+ "name": "user",
+ "description": "User privileges"
+ }
+ ]
+ },
+ "scopeMappings": [
+ {
+ "client": "multi-tenant",
+ "roles": ["user"]
+ }
+
+ ],
+ "clients": [
+ {
+ "clientId": "multi-tenant",
+ "enabled": true,
+ "adminUrl": "/multi-tenant",
+ "baseUrl": "/multi-tenant",
+ "redirectUris": [
+ "/multi-tenant/*"
+ ],
+ "secret": "password"
+ }
+ ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/web.xml
new file mode 100644
index 0000000..1b6dc5e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/web.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>%CONTEXT_PATH%</module-name>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
new file mode 100644
index 0000000..7b2713e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
@@ -0,0 +1,91 @@
+<arquillian xmlns="http://jboss.org/schema/arquillian"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.org/schema/arquillian
+ http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+
+ <defaultProtocol type="Servlet 3.0" />
+
+ <extension qualifier="webdriver">
+ <property name="browser">${browser}</property>
+ </extension>
+
+ <extension qualifier="graphene-secondbrowser">
+ <property name="browser">${browser}</property>
+ </extension>
+
+ <engine>
+ <!-- This allows manual inspection of deployed archives. -->
+ <property name="deploymentExportPath">target/deployments</property>
+ </engine>
+
+ <!-- PREVIOUS VERSIONS KEYCLOAK FOR MIGRATION TESTS -->
+ <!-- IT HAS TO BE LISTED ABOWE KEYCLOAK AUTH SERVERS -->
+
+ <container qualifier="keycloak-1.4.0.Final" mode="suite" >
+ <configuration>
+ <property name="enabled">${migration.kc14}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${keycloak-1.4.0.Final.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
+ <property name="managementPort">${auth.server.management.port}</property>
+ <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+ </configuration>
+ </container>
+
+ <container qualifier="keycloak-1.3.1.Final" mode="suite" >
+ <configuration>
+ <property name="enabled">${migration.kc13}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${keycloak-1.3.1.Final.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
+ <property name="managementPort">${auth.server.management.port}</property>
+ <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+ </configuration>
+ </container>
+
+ <container qualifier="keycloak-1.2.0.Final" mode="suite" >
+ <configuration>
+ <property name="enabled">${migration.kc12}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${keycloak-1.2.0.Final.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
+ <property name="managementPort">${auth.server.management.port}</property>
+ <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+ </configuration>
+ </container>
+
+ <!-- KEYCLOAK AUTH SERVERS -->
+
+ <container qualifier="auth-server-undertow" mode="suite" >
+ <configuration>
+ <property name="enabled">${auth.server.undertow}</property>
+ <property name="bindAddress">localhost</property>
+ <property name="adapterImplClass">org.keycloak.testsuite.arquillian.undertow.CustomUndertowContainer</property>
+ <property name="bindHttpPort">${auth.server.http.port}</property>
+ </configuration>
+ </container>
+
+ <container qualifier="auth-server-wildfly" mode="suite" >
+ <configuration>
+ <property name="enabled">${auth.server.wildfly}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${auth.server.wildfly.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+ <property name="managementPort">${auth.server.management.port}</property>
+ <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+ </configuration>
+ </container>
+
+ <container qualifier="auth-server-eap6" mode="suite" >
+ <configuration>
+ <property name="enabled">${auth.server.eap6}</property>
+ <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
+ <property name="jbossHome">${auth.server.eap6.home}</property>
+ <property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m ${adapter.test.props}</property>
+ <property name="managementAddress">localhost</property>
+ <property name="managementPort">${auth.server.management.port.jmx}</property>
+ <property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
+ </configuration>
+ </container>
+
+</arquillian>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties b/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties
new file mode 100644
index 0000000..50dab50
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/log4j.properties
@@ -0,0 +1,43 @@
+log4j.rootLogger=info, keycloak
+
+log4j.appender.keycloak=org.apache.log4j.ConsoleAppender
+log4j.appender.keycloak.layout=org.apache.log4j.PatternLayout
+log4j.appender.keycloak.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
+
+log4j.appender.testsuite=org.apache.log4j.ConsoleAppender
+log4j.appender.testsuite.layout=org.apache.log4j.PatternLayout
+log4j.appender.testsuite.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %m%n
+
+log4j.logger.org.keycloak=off, keycloak
+
+log4j.logger.org.keycloak.testsuite=debug, testsuite
+log4j.additivity.org.keycloak.testsuite=false
+
+# Enable to view events
+# log4j.logger.org.keycloak.events=debug
+
+# Enable to view loaded SPI and Providers
+# log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug
+# log4j.logger.org.keycloak.provider.ProviderManager=debug
+# log4j.logger.org.keycloak.provider.FileSystemProviderLoaderFactory=debug
+
+# Liquibase updates logged with "info" by default. Logging level can be changed by system property "keycloak.liquibase.logging.level"
+keycloak.liquibase.logging.level=info
+log4j.logger.org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider=${keycloak.liquibase.logging.level}
+
+# Enable to view database updates
+# log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
+# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
+# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
+
+# Enable to view kerberos/spnego logging
+# log4j.logger.org.keycloak.broker.kerberos=trace
+
+# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
+# log4j.logger.org.apache.directory.server.kerberos=debug
+
+log4j.logger.org.xnio=off
+log4j.logger.org.hibernate=off
+log4j.logger.org.jboss.resteasy=warn
+log4j.logger.org.apache.directory.api=warn
+log4j.logger.org.apache.directory.server.core=warn
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
new file mode 100644
index 0000000..c760152
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
@@ -0,0 +1,99 @@
+{
+ "admin": {
+ "realm": "master"
+ },
+
+ "eventsStore": {
+ "provider": "${keycloak.eventsStore.provider:jpa}"
+ },
+
+ "eventsListener": {
+ "jboss-logging" : {
+ "success-level": "debug",
+ "error-level": "warn"
+ }
+ },
+
+ "realm": {
+ "provider": "${keycloak.realm.provider:jpa}"
+ },
+
+ "user": {
+ "provider": "${keycloak.user.provider:jpa}"
+ },
+
+ "userSessions": {
+ "provider" : "${keycloak.userSessions.provider:infinispan}"
+ },
+
+ "realmCache": {
+ "provider": "${keycloak.realm.cache.provider:infinispan}"
+ },
+
+ "userCache": {
+ "provider": "${keycloak.user.cache.provider:infinispan}",
+ "mem": {
+ "maxSize": 20000
+ }
+ },
+
+ "timer": {
+ "provider": "basic"
+ },
+
+ "theme": {
+ "default": "keycloak",
+ "staticMaxAge": "${keycloak.theme.staticMaxAge:2592000}",
+ "cacheTemplates": "${keycloak.theme.cacheTemplates:true}",
+ "cacheThemes": "${keycloak.theme.cacheThemes:true}",
+ "folder": {
+ "dir": "${keycloak.theme.dir}"
+ }
+ },
+
+ "login": {
+ "provider": "freemarker"
+ },
+
+ "account": {
+ "provider": "freemarker"
+ },
+
+ "email": {
+ "provider": "freemarker"
+ },
+
+ "scheduled": {
+ "interval": 900
+ },
+
+ "connectionsHttpClient": {
+ "default": {
+ "disable-trust-manager": true
+ }
+ },
+
+
+ "connectionsJpa": {
+ "default": {
+ "url": "${keycloak.connectionsJpa.url:jdbc:h2:mem:test}",
+ "driver": "${keycloak.connectionsJpa.driver:org.h2.Driver}",
+ "driverDialect": "${keycloak.connectionsJpa.driverDialect:}",
+ "user": "${keycloak.connectionsJpa.user:sa}",
+ "password": "${keycloak.connectionsJpa.password:}",
+ "databaseSchema": "${keycloak.connectionsJpa.databaseSchema:update}",
+ "showSql": "${keycloak.connectionsJpa.showSql:false}",
+ "formatSql": "${keycloak.connectionsJpa.formatSql:true}"
+ }
+ },
+
+ "connectionsMongo": {
+ "default": {
+ "host": "${keycloak.connectionsMongo.host:127.0.0.1}",
+ "port": "${keycloak.connectionsMongo.port:27017}",
+ "db": "${keycloak.connectionsMongo.db:keycloak}",
+ "databaseSchema": "${keycloak.connectionsMongo.databaseSchema:update}",
+ "connectionsPerHost": "${keycloak.connectionsMongo.connectionsPerHost:100}"
+ }
+ }
+}
\ No newline at end of file
testsuite/integration-arquillian/tests/pom.xml 597(+597 -0)
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
new file mode 100644
index 0000000..2dd55cf
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -0,0 +1,597 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <parent>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian</artifactId>
+ <version>1.6.0.Final-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>integration-arquillian-tests</artifactId>
+ <packaging>pom</packaging>
+ <name>Tests</name>
+
+ <modules>
+ <module>base</module>
+ <module>adapters</module>
+ </modules>
+
+ <properties>
+ <containers.home>${project.build.directory}/containers</containers.home>
+ <examples.home>${project.build.directory}/examples</examples.home>
+
+ <auth.server.container>auth-server-undertow</auth.server.container>
+ <auth.server.port.offset>100</auth.server.port.offset>
+ <auth.server.http.port>8180</auth.server.http.port>
+ <auth.server.management.port>10090</auth.server.management.port>
+ <auth.server.management.port.jmx>10099</auth.server.management.port.jmx>
+ <startup.timeout.sec>60</startup.timeout.sec>
+
+ <browser>phantomjs</browser>
+
+ <arquillian-core.version>1.1.8.Final</arquillian-core.version>
+ <selenium.version>2.45.0</selenium.version>
+ <arquillian-drone.version>2.0.0.Alpha4</arquillian-drone.version>
+ <arquillian-graphene.version>2.1.0.Alpha2</arquillian-graphene.version>
+ <arquillian-wildfly-container.version>8.2.0.Final</arquillian-wildfly-container.version>
+ <version.shrinkwrap.resolvers>2.1.1</version.shrinkwrap.resolvers>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.arquillian.selenium</groupId>
+ <artifactId>selenium-bom</artifactId>
+ <version>${selenium.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.arquillian</groupId>
+ <artifactId>arquillian-bom</artifactId>
+ <version>${arquillian-core.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.arquillian.extension</groupId>
+ <artifactId>arquillian-drone-bom</artifactId>
+ <version>${arquillian-drone.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-arquillian-container-managed</artifactId>
+ <version>${arquillian-wildfly-container.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <browser>${browser}</browser>
+ <shouldDeploy>false</shouldDeploy>
+ <auth.server.container>${auth.server.container}</auth.server.container>
+ <auth.server.undertow>true</auth.server.undertow>
+ <auth.server.port.offset>${auth.server.port.offset}</auth.server.port.offset>
+ <auth.server.http.port>${auth.server.http.port}</auth.server.http.port>
+ <auth.server.management.port>${auth.server.management.port}</auth.server.management.port>
+ <auth.server.management.port.jmx>${auth.server.management.port.jmx}</auth.server.management.port.jmx>
+ <startup.timeout.sec>${startup.timeout.sec}</startup.timeout.sec>
+ </systemPropertyVariables>
+ <properties>
+ <property>
+ <name>listener</name>
+ <value>org.keycloak.testsuite.util.TestEventsLogger</value>
+ </property>
+ </properties>
+ <failIfNoTests>false</failIfNoTests>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <profiles>
+
+ <profile>
+ <id>common-for-tests</id>
+ <activation>
+ <file>
+ <exists>src</exists>
+ <!-- ^ only activate this profile in submodules that have actual tests -->
+ </file>
+ </activation>
+ <dependencies>
+ <!-- TEST DEPENDENCIES -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.arquillian.junit</groupId>
+ <artifactId>arquillian-junit-container</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.arquillian.graphene</groupId>
+ <artifactId>graphene-webdriver</artifactId>
+ <version>${arquillian-graphene.version}</version>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.arquillian.protocol</groupId>
+ <artifactId>arquillian-protocol-servlet</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.arquillian.extension</groupId>
+ <artifactId>arquillian-phantom-driver</artifactId>
+ </dependency>
+ <!-- TODO: investigate if we need this dependency
+ <dependency>
+ <groupId>org.jboss.arquillian.graphene</groupId>
+ <artifactId>arquillian-graphene-impl</artifactId>
+ <version>1.0.0.CR3</version>
+ </dependency>-->
+ <dependency>
+ <groupId>org.jboss.arquillian.graphene</groupId>
+ <artifactId>arquillian-browser-screenshooter</artifactId>
+ <version>2.1.0.Alpha2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.9.2</version>
+ <type>jar</type>
+ </dependency>
+
+ <!-- Email Test Server -->
+ <dependency>
+ <groupId>com.icegreen</groupId>
+ <artifactId>greenmail</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- Keycloak deps for tests -->
+
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-dependencies-server-all</artifactId>
+ <type>pom</type>
+ </dependency>
+
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-admin-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-services</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-core</artifactId>
+ </dependency>
+
+
+ <!-- Keycloak Server on Undertow -->
+
+ <dependency>
+ <groupId>org.jboss.arquillian.container</groupId>
+ <artifactId>undertow-embedded</artifactId>
+ <version>1.0.0.Alpha1-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>jaxrs-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>async-http-servlet-3.0</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-undertow</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-multipart-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jackson-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-xc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hibernate.javax.persistence</groupId>
+ <artifactId>hibernate-jpa-2.1-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-core</artifactId>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>auth-server-wildfly</id>
+ <properties>
+ <auth.server.container>auth-server-wildfly</auth.server.container>
+ <auth.server.wildfly.home>${containers.home}/keycloak-${project.version}</auth.server.wildfly.home>
+ <startup.timeout.sec>150</startup.timeout.sec>
+ <adapter.test.props/>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-arquillian-container-managed</artifactId>
+ </dependency>
+ </dependencies>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>unpack</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-server-wildfly</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${containers.home}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <auth.server.wildfly>true</auth.server.wildfly>
+ <auth.server.undertow>false</auth.server.undertow>
+ <auth.server.wildfly.home>${auth.server.wildfly.home}</auth.server.wildfly.home>
+ <adapter.test.props>${adapter.test.props}</adapter.test.props>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>auth-server-eap6</id>
+ <properties>
+ <auth.server.container>auth-server-eap6</auth.server.container>
+ <auth.server.eap6.home>${containers.home}/keycloak-${project.version}</auth.server.eap6.home>
+ <startup.timeout.sec>150</startup.timeout.sec>
+ <adapter.test.props/>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-arquillian-container-managed</artifactId>
+ <version>7.2.0.Final</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>unpack</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-server-eap6</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${containers.home}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <auth.server.eap6>true</auth.server.eap6>
+ <auth.server.undertow>false</auth.server.undertow>
+ <auth.server.eap6.home>${auth.server.eap6.home}</auth.server.eap6.home>
+ <adapter.test.props>${adapter.test.props}</adapter.test.props>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <!-- Profiles for migration tests-->
+
+ <profile>
+ <id>migration-kc14</id>
+ <properties>
+ <keycloak-1.4.0.Final.home>${containers.home}/keycloak-1.4.0.Final</keycloak-1.4.0.Final.home>
+ </properties>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>unpack-previous</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-server-wildfly-kc14</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${containers.home}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <migration>true</migration>
+ <migration.kc14>true</migration.kc14>
+ <keycloak-1.4.0.Final.home>${keycloak-1.4.0.Final.home}</keycloak-1.4.0.Final.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>migration-kc13</id>
+ <properties>
+ <keycloak-1.3.1.Final.home>${containers.home}/keycloak-1.3.1.Final</keycloak-1.3.1.Final.home>
+ </properties>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>unpack-previous</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-server-wildfly-kc13</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${containers.home}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <migration>true</migration>
+ <migration.kc13>true</migration.kc13>
+ <keycloak-1.3.1.Final.home>${keycloak-1.3.1.Final.home}</keycloak-1.3.1.Final.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>migration-kc12</id>
+ <properties>
+ <keycloak-1.2.0.Final.home>${containers.home}/keycloak-1.2.0.Final</keycloak-1.2.0.Final.home>
+ </properties>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>unpack-previous</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-server-wildfly-kc12</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </artifactItem>
+ </artifactItems>
+ <outputDirectory>${containers.home}</outputDirectory>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <migration>true</migration>
+ <migration.kc12>true</migration.kc12>
+ <keycloak-1.2.0.Final.home>${keycloak-1.2.0.Final.home}</keycloak-1.2.0.Final.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+ </profiles>
+
+</project>