keycloak-memoizeit
Changes
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java 4(+3 -1)
authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java 26(+23 -3)
authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java 7(+5 -2)
authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java 8(+8 -0)
distribution/api-docs-dist/pom.xml 116(+97 -19)
examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java 154(+0 -154)
examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl 14(+0 -14)
examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl 15(+0 -15)
examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl 14(+0 -14)
examples/authz/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl 15(+0 -15)
examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js 13(+0 -13)
examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js 14(+0 -14)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java 181(+0 -181)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java 67(+0 -67)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/SharedAlbum.java 47(+0 -47)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java 91(+0 -91)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java 81(+0 -81)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java 32(+0 -32)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java 12(+0 -12)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Resources.java 51(+0 -51)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/Transaction.java 33(+0 -33)
examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java 56(+0 -56)
examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json 152(+0 -152)
examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml 27(+0 -27)
examples/pom.xml 1(+0 -1)
integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java 5(+5 -0)
model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java 10(+9 -1)
model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java 9(+8 -1)
model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java 7(+7 -0)
model/infinispan/src/main/java/org/keycloak/connections/infinispan/RemoteCacheProvider.java 202(+202 -0)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java 2(+1 -1)
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java 23(+14 -9)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java 16(+11 -5)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java 2(+1 -1)
server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java 146(+146 -0)
server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java 7(+7 -0)
server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java 2(+1 -1)
server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Realm.java 114(+114 -0)
services/pom.xml 43(+22 -21)
services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java 4(+4 -0)
services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java 2(+2 -0)
services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java 60(+60 -0)
services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java 1(+1 -0)
services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java 50(+33 -17)
services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java 50(+35 -15)
services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java 17(+17 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli 4(+4 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore 0(+0 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/ca.cert.pem 35(+35 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user@localhost.key.pem 54(+54 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-san-email@localhost.cert.pem 38(+38 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr 1(+1 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old 0(+0 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/1 131(+131 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem 69(+69 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/intermediate.cert.pem 34(+34 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/crlnumber 1(+1 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/csr/intermediate.csr.pem 29(+29 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt 1(+1 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.attr 1(+1 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.old 0(+0 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/newcerts/1000.pem 38(+38 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl.cnf 135(+135 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl-san.cnf 139(+139 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/private/intermediate.key.pem 54(+54 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial 1(+1 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial.old 1(+1 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1000.pem 34(+34 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/openssl.cnf 131(+131 -0)
testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/private/ca.key.pem 54(+54 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/keycloak.js 1416(+1416 -0)
testsuite/integration-arquillian/servers/cache-server/jboss/common/cache-authorization.xsl 90(+90 -0)
testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html 1(+1 -0)
testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js 2(+2 -0)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java 59(+32 -27)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java 15(+13 -2)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java 3(+2 -1)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/unsecured/UnsecuredService.java 51(+22 -29)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java 2(+1 -1)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml 9(+0 -9)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml 4(+2 -2)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/beans.xml 0(+0 -0)
testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml 70(+38 -32)
testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json 28(+28 -0)
testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json 8(+8 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java 168(+123 -45)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java 30(+30 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java 4(+4 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java 40(+39 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java 889(+392 -497)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java 26(+26 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java 7(+7 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java 34(+22 -12)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java 65(+45 -20)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java 30(+25 -5)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java 6(+0 -6)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java 13(+0 -13)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java 17(+1 -16)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java 66(+33 -33)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java 7(+0 -7)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationTest.java 229(+229 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java 8(+4 -4)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationTest.java 578(+578 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java 4(+2 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java 24(+12 -12)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java 4(+2 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java 29(+26 -3)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java 6(+6 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java 6(+6 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java 279(+279 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java 11(+11 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java 30(+30 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginSubjectAltNameEmailTest.java 97(+97 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json 2(+1 -1)
testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java 8(+6 -2)
testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java 8(+6 -2)
testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java 8(+6 -2)
testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java 1(+0 -1)
testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java 2(+1 -1)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/helper/adapter/SamlAdapterTestStrategy.java 35(+24 -11)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/helper/adapter/SamlKeycloakRule.java 4(+2 -2)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/helper/adapter/SendUsernameServlet.java 2(+1 -1)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/InputPage.java 52(+0 -52)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/InputServlet.java 81(+0 -81)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java 242(+0 -242)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java 152(+0 -152)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlSPFacade.java 62(+0 -62)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java 6(+3 -3)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/samlfilter/SamlAdapterTest.java 168(+0 -168)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keycloak-saml.xml 64(+0 -64)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml 59(+0 -59)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml 64(+0 -64)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml 64(+0 -64)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml 44(+0 -44)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml 62(+0 -62)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml 62(+0 -62)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml 63(+0 -63)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml 63(+0 -63)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml 64(+0 -64)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml 59(+0 -59)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml 63(+0 -63)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml 64(+0 -64)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml 64(+0 -64)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks 0(+0 -0)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml 43(+0 -43)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml 43(+0 -43)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-post2/WEB-INF/keycloak-saml.xml 43(+0 -43)
testsuite/integration-deprecated/src/test/resources/keycloak-saml/simple-post-passive/WEB-INF/keycloak-saml.xml 44(+0 -44)
testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml 2(+1 -1)
testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml 2(+1 -1)
testsuite/performance/pom.xml 1(+1 -0)
testsuite/performance/README.md 155(+90 -65)
testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/cluster.properties 32(+32 -0)
testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/crossdc.properties 42(+42 -0)
testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/singlenode.properties 23(+23 -0)
testsuite/performance/tests/pom.xml 240(+88 -152)
Details
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
index 8e83de1..8bec840 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
@@ -95,7 +95,9 @@ class PathMatcher {
}
if (WILDCARD == expectedUri.charAt(expectedUri.length() - 1)) {
- matchingAnyPath = entry;
+ if (matchingAnyPath == null || matchingAnyPath.getPath().length() < matchingUri.length()) {
+ matchingAnyPath = entry;
+ }
} else {
int suffixIndex = expectedUri.indexOf(WILDCARD + ".");
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java b/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
index 1bf5c86..df24fdb 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
@@ -97,7 +97,7 @@ public class AuthzClient {
* @return a {@link ProtectionResource}
*/
public ProtectionResource protection() {
- return new ProtectionResource(this.http, this.serverConfiguration, createPatSupplier());
+ return new ProtectionResource(this.http, this.serverConfiguration, configuration, createPatSupplier());
}
/**
@@ -107,7 +107,7 @@ public class AuthzClient {
* @return a {@link ProtectionResource}
*/
public ProtectionResource protection(final String accessToken) {
- return new ProtectionResource(this.http, this.serverConfiguration, new TokenCallable(http, configuration, serverConfiguration) {
+ return new ProtectionResource(this.http, this.serverConfiguration, configuration, new TokenCallable(http, configuration, serverConfiguration) {
@Override
public String call() {
return accessToken;
@@ -128,7 +128,7 @@ public class AuthzClient {
* @return a {@link ProtectionResource}
*/
public ProtectionResource protection(String userName, String password) {
- return new ProtectionResource(this.http, this.serverConfiguration, createPatSupplier(userName, password));
+ return new ProtectionResource(this.http, this.serverConfiguration, configuration, createPatSupplier(userName, password));
}
/**
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
index cc92712..cf2e91a 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
@@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
+import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.util.Http;
@@ -38,11 +39,13 @@ public class ProtectedResource {
private final Http http;
private ServerConfiguration serverConfiguration;
+ private final Configuration configuration;
private final TokenCallable pat;
- ProtectedResource(Http http, ServerConfiguration serverConfiguration, TokenCallable pat) {
+ ProtectedResource(Http http, ServerConfiguration serverConfiguration, Configuration configuration, TokenCallable pat) {
this.http = http;
this.serverConfiguration = serverConfiguration;
+ this.configuration = configuration;
this.pat = pat;
}
@@ -119,13 +122,30 @@ public class ProtectedResource {
}
/**
- * Query the server for a resource given its <code>name</code>.
+ * Query the server for a resource given its <code>name</code> where the owner is the resource server itself.
*
* @param id the resource name
* @return a {@link ResourceRepresentation}
*/
public ResourceRepresentation findByName(String name) {
- String[] representations = find(null, name, null, null, null, null, null, null);
+ String[] representations = find(null, name, null, configuration.getResource(), null, null, null, null);
+
+ if (representations.length == 0) {
+ return null;
+ }
+
+ return findById(representations[0]);
+ }
+
+ /**
+ * Query the server for a resource given its <code>name</code> and a given <code>ownerId</code>.
+ *
+ * @param name the resource name
+ * @param ownerId the owner id
+ * @return a {@link ResourceRepresentation}
+ */
+ public ResourceRepresentation findByName(String name, String ownerId) {
+ String[] representations = find(null, name, null, ownerId, null, null, null, null);
if (representations.length == 0) {
return null;
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
index 7268fe9..03fa945 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
@@ -17,6 +17,7 @@
*/
package org.keycloak.authorization.client.resource;
+import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
import org.keycloak.authorization.client.util.Http;
@@ -31,15 +32,17 @@ public class ProtectionResource {
private final TokenCallable pat;
private final Http http;
+ private final Configuration configuration;
private ServerConfiguration serverConfiguration;
- public ProtectionResource(Http http, ServerConfiguration serverConfiguration, TokenCallable pat) {
+ public ProtectionResource(Http http, ServerConfiguration serverConfiguration, Configuration configuration, TokenCallable pat) {
if (pat == null) {
throw new RuntimeException("No access token was provided when creating client for Protection API.");
}
this.http = http;
this.serverConfiguration = serverConfiguration;
+ this.configuration = configuration;
this.pat = pat;
}
@@ -49,7 +52,7 @@ public class ProtectionResource {
* @return a {@link ProtectedResource}
*/
public ProtectedResource resource() {
- return new ProtectedResource(http, serverConfiguration, pat);
+ return new ProtectedResource(http, serverConfiguration, configuration, pat);
}
/**
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
index 3531f40..ed20a67 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
@@ -44,4 +44,12 @@ public class HttpResponseException extends RuntimeException {
public byte[] getBytes() {
return bytes;
}
+
+ @Override
+ public String toString() {
+ if (bytes != null) {
+ return new StringBuilder(super.toString()).append(" / Response from server: ").append(new String(bytes)).toString();
+ }
+ return super.toString();
+ }
}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java
index ae2eaf1..2b0b79a 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/Throwables.java
@@ -39,7 +39,7 @@ public final class Throwables {
*/
public static RuntimeException handleWrapException(String message, Throwable cause) {
if (cause instanceof HttpResponseException) {
- throw handleAndWrapHttpResponseException(message, HttpResponseException.class.cast(cause));
+ throw handleAndWrapHttpResponseException(HttpResponseException.class.cast(cause));
}
return new RuntimeException(message, cause);
@@ -91,19 +91,11 @@ public final class Throwables {
throw new RuntimeException(message, cause);
}
- private static RuntimeException handleAndWrapHttpResponseException(String message, HttpResponseException exception) {
- HttpResponseException hre = HttpResponseException.class.cast(exception);
- StringBuilder detail = new StringBuilder(message);
- byte[] bytes = hre.getBytes();
-
- if (bytes != null) {
- detail.append(". Server message: ").append(new String(bytes));
- }
-
+ private static RuntimeException handleAndWrapHttpResponseException(HttpResponseException exception) {
if (403 == exception.getStatusCode()) {
- throw new AuthorizationDeniedException(detail.toString(), exception);
+ throw new AuthorizationDeniedException(exception);
}
- return new RuntimeException(detail.toString(), exception);
+ return new RuntimeException(exception);
}
}
diff --git a/core/src/main/java/org/keycloak/representations/IDToken.java b/core/src/main/java/org/keycloak/representations/IDToken.java
index 51776f0..76842bf 100755
--- a/core/src/main/java/org/keycloak/representations/IDToken.java
+++ b/core/src/main/java/org/keycloak/representations/IDToken.java
@@ -51,6 +51,10 @@ public class IDToken extends JsonWebToken {
public static final String CLAIMS_LOCALES = "claims_locales";
public static final String ACR = "acr";
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ public static final String S_HASH = "s_hash";
+
// NOTE!!! WE used to use @JsonUnwrapped on a UserClaimSet object. This screws up otherClaims and the won't work
// anymore. So don't have any @JsonUnwrapped!
@JsonProperty(NONCE)
@@ -131,6 +135,11 @@ public class IDToken extends JsonWebToken {
@JsonProperty(ACR)
protected String acr;
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ @JsonProperty(S_HASH)
+ protected String stateHash;
+
public String getNonce() {
return nonce;
}
@@ -338,4 +347,14 @@ public class IDToken extends JsonWebToken {
public void setAcr(String acr) {
this.acr = acr;
}
+
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ public String getStateHash() {
+ return stateHash;
+ }
+
+ public void setStateHash(String stateHash) {
+ this.stateHash = stateHash;
+ }
}
diff --git a/distribution/api-docs-dist/assembly.xml b/distribution/api-docs-dist/assembly.xml
index f32d988..6e4ee6e 100755
--- a/distribution/api-docs-dist/assembly.xml
+++ b/distribution/api-docs-dist/assembly.xml
@@ -39,6 +39,7 @@
<file>
<source>src/index.html</source>
<outputDirectory></outputDirectory>
+ <filtered>true</filtered>
</file>
</files>
distribution/api-docs-dist/pom.xml 116(+97 -19)
diff --git a/distribution/api-docs-dist/pom.xml b/distribution/api-docs-dist/pom.xml
index 59b994e..88bcf69 100755
--- a/distribution/api-docs-dist/pom.xml
+++ b/distribution/api-docs-dist/pom.xml
@@ -29,13 +29,9 @@
<name>Keycloak Docs Distribution</name>
<description/>
- <dependencies>
- <dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-dependencies-server-all</artifactId>
- <type>pom</type>
- </dependency>
- </dependencies>
+ <properties>
+ <javadoc.branding>${product.name.full} ${product.version}</javadoc.branding>
+ </properties>
<build>
<finalName>keycloak-api-docs-${project.version}</finalName>
@@ -45,12 +41,9 @@
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<minmemory>128m</minmemory>
- <maxmemory>1024m</maxmemory>
- <dependencySourceIncludes>
- <dependencySourceInclude>org.keycloak:*</dependencySourceInclude>
- </dependencySourceIncludes>
+ <maxmemory>2400m</maxmemory>
+ <encoding>UTF-8</encoding>
<includeDependencySources>true</includeDependencySources>
- <includeTransitiveDependencySources>true</includeTransitiveDependencySources>
</configuration>
<executions>
<execution>
@@ -75,12 +68,6 @@
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
- <outputDirectory>
- target
- </outputDirectory>
- <workDirectory>
- target/assembly/work
- </workDirectory>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
@@ -89,7 +76,6 @@
</plugins>
</build>
-
<profiles>
<profile>
<id>community</id>
@@ -98,10 +84,32 @@
<name>!product</name>
</property>
</activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-dependencies-server-all</artifactId>
+ <type>pom</type>
+ </dependency>
+ </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>aggregate-javadoc</id>
+ <configuration>
+ <includeTransitiveDependencySources>true</includeTransitiveDependencySources>
+ <dependencySourceIncludes>
+ <dependencySourceInclude>org.keycloak:*</dependencySourceInclude>
+ </dependencySourceIncludes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
@@ -110,6 +118,76 @@
</plugins>
</build>
</profile>
+
+ <profile>
+ <id>product</id>
+ <activation>
+ <property>
+ <name>product</name>
+ </property>
+ </activation>
+ <!-- Make sure to keep this list in sync with <dependencySourceIncludes> -->
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-saml-core-public</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-saml-adapter-api-public</artifactId>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>aggregate-javadoc</id>
+ <configuration>
+ <windowtitle>${javadoc.branding} public API</windowtitle>
+ <doctitle>${javadoc.branding} public API</doctitle>
+ <header>${javadoc.branding}</header>
+ <footer>${javadoc.branding}</footer>
+ <includeTransitiveDependencySources>false</includeTransitiveDependencySources>
+ <!-- Make sure to keep this list in sync with <dependencies> -->
+ <dependencySourceIncludes>
+ <include>org.keycloak:keycloak-server-spi</include>
+ <include>org.keycloak:keycloak-common</include>
+ <include>org.keycloak:keycloak-core</include>
+ <include>org.keycloak:keycloak-saml-core-public</include>
+ <include>org.keycloak:keycloak-adapter-spi</include>
+ <include>org.keycloak:keycloak-adapter-core</include>
+ <include>org.keycloak:keycloak-saml-adapter-api-public</include>
+ </dependencySourceIncludes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
</profiles>
</project>
diff --git a/distribution/api-docs-dist/src/index.html b/distribution/api-docs-dist/src/index.html
index 38f86e9..97a8028 100755
--- a/distribution/api-docs-dist/src/index.html
+++ b/distribution/api-docs-dist/src/index.html
@@ -24,7 +24,7 @@
</head>
<body>
-<h1>Keyloak API Documentation</h1>
+<h1>${product.name.full} API Documentation</h1>
<table>
<tr>
<td>Admin REST API</td>
@@ -35,4 +35,4 @@
<td colspan="3"><a href="javadocs/index.html">HTML</a></td>
</tr>
</body>
-</html>
\ No newline at end of file
+</html>
examples/pom.xml 1(+0 -1)
diff --git a/examples/pom.xml b/examples/pom.xml
index 7572bc4..2313c39 100755
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -66,6 +66,5 @@
<module>themes</module>
<module>saml</module>
<module>ldap</module>
- <module>authz</module>
</modules>
</project>
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
index e7daaa1..7f2c394 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
@@ -62,5 +62,10 @@ public interface ResourcesResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
+ List<ResourceRepresentation> findByName(@QueryParam("name") String name, @QueryParam("owner") String owner);
+
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
List<ResourceRepresentation> resources();
}
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java
index 5513777..c1f8914 100644
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java
@@ -18,6 +18,7 @@
package org.keycloak.connections.infinispan;
import org.infinispan.Cache;
+import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.manager.EmbeddedCacheManager;
/**
@@ -26,11 +27,13 @@ import org.infinispan.manager.EmbeddedCacheManager;
public class DefaultInfinispanConnectionProvider implements InfinispanConnectionProvider {
private final EmbeddedCacheManager cacheManager;
+ private final RemoteCacheProvider remoteCacheProvider;
private final String siteName;
private final String nodeName;
- public DefaultInfinispanConnectionProvider(EmbeddedCacheManager cacheManager, String nodeName, String siteName) {
+ public DefaultInfinispanConnectionProvider(EmbeddedCacheManager cacheManager, RemoteCacheProvider remoteCacheProvider, String nodeName, String siteName) {
this.cacheManager = cacheManager;
+ this.remoteCacheProvider = remoteCacheProvider;
this.nodeName = nodeName;
this.siteName = siteName;
}
@@ -41,6 +44,11 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection
}
@Override
+ public <K, V> RemoteCache<K, V> getRemoteCache(String cacheName) {
+ return remoteCacheProvider.getRemoteCache(cacheName);
+ }
+
+ @Override
public String getNodeName() {
return nodeName;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index 7493cae..0053791 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -56,6 +56,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
protected EmbeddedCacheManager cacheManager;
+ protected RemoteCacheProvider remoteCacheProvider;
+
protected boolean containerManaged;
private String nodeName;
@@ -66,7 +68,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
public InfinispanConnectionProvider create(KeycloakSession session) {
lazyInit();
- return new DefaultInfinispanConnectionProvider(cacheManager, nodeName, siteName);
+ return new DefaultInfinispanConnectionProvider(cacheManager, remoteCacheProvider, nodeName, siteName);
}
@Override
@@ -74,6 +76,9 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
if (cacheManager != null && !containerManaged) {
cacheManager.stop();
}
+ if (remoteCacheProvider != null) {
+ remoteCacheProvider.stop();
+ }
cacheManager = null;
}
@@ -104,6 +109,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
}
logger.infof("Node name: %s, Site name: %s", nodeName, siteName);
+
+ remoteCacheProvider = new RemoteCacheProvider(config, cacheManager);
}
}
}
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
index 00f60a7..cb23b6f 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
@@ -18,6 +18,7 @@
package org.keycloak.connections.infinispan;
import org.infinispan.Cache;
+import org.infinispan.client.hotrod.RemoteCache;
import org.keycloak.provider.Provider;
/**
@@ -68,6 +69,12 @@ public interface InfinispanConnectionProvider extends Provider {
<K, V> Cache<K, V> getCache(String name);
/**
+ * Get remote cache of given name. Could just retrieve the remote cache from the remoteStore configured in given infinispan cache and/or
+ * alternatively return the secured remoteCache (remoteCache corresponding to secured hotrod endpoint)
+ */
+ <K, V> RemoteCache<K, V> getRemoteCache(String name);
+
+ /**
* @return Address of current node in cluster. In non-cluster environment, it returns some other non-null value (eg. hostname with some random value like "host-123456" )
*/
String getNodeName();
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/RemoteCacheProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/RemoteCacheProvider.java
new file mode 100644
index 0000000..055e89b
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/RemoteCacheProvider.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2017 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.infinispan;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.RealmCallback;
+
+import org.infinispan.client.hotrod.RemoteCache;
+import org.infinispan.client.hotrod.RemoteCacheManager;
+import org.infinispan.client.hotrod.configuration.Configuration;
+import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.common.util.reflections.Reflections;
+import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
+import java.util.stream.Collectors;
+import org.infinispan.client.hotrod.exceptions.HotRodClientException;
+
+/**
+ * Get either just remoteCache associated with remoteStore associated with infinispan cache of given name. If security is enabled, then
+ * return secured remoteCache based on the template provided by remoteStore configuration but with added "authentication" configuration
+ * of secured hotrod endpoint (RemoteStore doesn't yet allow to configure "security" of hotrod endpoints)
+ *
+ * TODO: Remove this class once we upgrade to infinispan version, which allows to configure security for remoteStore itself
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class RemoteCacheProvider {
+
+ public static final String SCRIPT_CACHE_NAME = "___script_cache";
+
+ protected static final Logger logger = Logger.getLogger(RemoteCacheProvider.class);
+
+ private final Config.Scope config;
+ private final EmbeddedCacheManager cacheManager;
+
+ private final Map<String, RemoteCache> availableCaches = new HashMap<>();
+
+ // Enlist secured managers, which are managed by us and should be shutdown on stop
+ private final Map<String, RemoteCacheManager> managedManagers = new HashMap<>();
+
+ public RemoteCacheProvider(Config.Scope config, EmbeddedCacheManager cacheManager) {
+ this.config = config;
+ this.cacheManager = cacheManager;
+ }
+
+ public RemoteCache getRemoteCache(String cacheName) {
+ if (availableCaches.get(cacheName) == null) {
+ synchronized (this) {
+ if (availableCaches.get(cacheName) == null) {
+ RemoteCache remoteCache = loadRemoteCache(cacheName);
+ availableCaches.put(cacheName, remoteCache);
+ }
+ }
+ }
+
+ return availableCaches.get(cacheName);
+ }
+
+ public void stop() {
+ logger.debugf("Shutdown %d registered secured remoteCache managers", managedManagers.size());
+
+ for (RemoteCacheManager mgr : managedManagers.values()) {
+ mgr.stop();
+ }
+ }
+
+
+ protected synchronized RemoteCache loadRemoteCache(String cacheName) {
+ RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cacheManager.getCache(cacheName));
+
+ Boolean remoteStoreSecurity = config.getBoolean("remoteStoreSecurityEnabled");
+ if (remoteStoreSecurity == null) {
+ try {
+ logger.debugf("Detecting remote security settings of HotRod server, cache %s. Disable by explicitly setting \"remoteStoreSecurityEnabled\" property in spi=connectionsInfinispan/provider=default", cacheName);
+ remoteStoreSecurity = false;
+ final RemoteCache<Object, Object> scriptCache = remoteCache.getRemoteCacheManager().getCache(SCRIPT_CACHE_NAME);
+ if (scriptCache == null) {
+ logger.debug("Cannot detect remote security settings of HotRod server, disabling.");
+ } else {
+ scriptCache.containsKey("");
+ }
+ } catch (HotRodClientException ex) {
+ logger.debug("Seems that HotRod server requires authentication, enabling.");
+ remoteStoreSecurity = true;
+ }
+ }
+
+ if (remoteStoreSecurity) {
+ logger.infof("Remote store security for cache %s is enabled. Disable by setting \"remoteStoreSecurityEnabled\" property to \"false\" in spi=connectionsInfinispan/provider=default", cacheName);
+ RemoteCacheManager securedMgr = getOrCreateSecuredRemoteCacheManager(config, cacheName, remoteCache.getRemoteCacheManager());
+ return securedMgr.getCache(remoteCache.getName());
+ } else {
+ logger.infof("Remote store security for cache %s is disabled. If server fails to connect to remote JDG server, enable it.", cacheName);
+ return remoteCache;
+ }
+ }
+
+
+ protected RemoteCacheManager getOrCreateSecuredRemoteCacheManager(Config.Scope config, String cacheName, RemoteCacheManager origManager) {
+ String serverName = config.get("remoteStoreSecurityServerName", "keycloak-jdg-server");
+ String realm = config.get("remoteStoreSecurityRealm", "AllowScriptManager");
+
+ String username = config.get("remoteStoreSecurityUsername", "___script_manager");
+ String password = config.get("remoteStoreSecurityPassword", "not-so-secret-password");
+
+ // Create configuration template from the original configuration provided at remoteStore level
+ Configuration origConfig = origManager.getConfiguration();
+
+ ConfigurationBuilder cfgBuilder = new ConfigurationBuilder()
+ .read(origConfig);
+
+ String securedHotRodEndpoint = origConfig.servers().stream()
+ .map(serverConfiguration -> serverConfiguration.host() + ":" + serverConfiguration.port())
+ .collect(Collectors.joining(";"));
+
+ if (managedManagers.containsKey(securedHotRodEndpoint)) {
+ return managedManagers.get(securedHotRodEndpoint);
+ }
+
+ logger.infof("Creating secured RemoteCacheManager for Server: '%s', Cache: '%s', Realm: '%s', Username: '%s', Secured HotRod endpoint: '%s'", serverName, cacheName, realm, username, securedHotRodEndpoint);
+
+ // Workaround as I need a way to override servers and it's not possible to remove existing :/
+ try {
+ Field serversField = cfgBuilder.getClass().getDeclaredField("servers");
+ Reflections.setAccessible(serversField);
+ List origServers = Reflections.getFieldValue(serversField, cfgBuilder, List.class);
+ origServers.clear();
+ } catch (NoSuchFieldException nsfe) {
+ throw new RuntimeException(nsfe);
+ }
+
+ // Create configuration based on the configuration template from remoteStore. Just add security and override secured endpoint
+ Configuration newConfig = cfgBuilder
+ .addServers(securedHotRodEndpoint)
+ .security()
+ .authentication()
+ .serverName(serverName) //define server name, should be specified in XML configuration on JDG side
+ .saslMechanism("DIGEST-MD5") // define SASL mechanism, in this example we use DIGEST with MD5 hash
+ .callbackHandler(new LoginHandler(username, password.toCharArray(), realm)) // define login handler, implementation defined
+ .enable()
+ .build();
+
+ final RemoteCacheManager remoteCacheManager = new RemoteCacheManager(newConfig);
+ managedManagers.put(securedHotRodEndpoint, remoteCacheManager);
+ return remoteCacheManager;
+ }
+
+
+ private static class LoginHandler implements CallbackHandler {
+ final private String login;
+ final private char[] password;
+ final private String realm;
+
+ private LoginHandler(String login, char[] password, String realm) {
+ this.login = login;
+ this.password = password;
+ this.realm = realm;
+ }
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (Callback callback : callbacks) {
+ if (callback instanceof NameCallback) {
+ ((NameCallback) callback).setName(login);
+ } else if (callback instanceof PasswordCallback) {
+ ((PasswordCallback) callback).setPassword(password);
+ } else if (callback instanceof RealmCallback) {
+ ((RealmCallback) callback).setText(realm);
+ } else {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+ }
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
index 0f245ee..e54316d 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
@@ -79,7 +79,7 @@ public class StoreFactoryCacheManager extends CacheManager {
public void resourceUpdated(String id, String name, String type, String uri, Set<String> scopes, String serverId, String owner, Set<String> invalidations) {
invalidations.add(id);
- invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
+ invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, owner, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, null));
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(id, serverId));
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
index c50cec1..5924573 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
@@ -336,8 +336,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
return "scope.name." + name + "." + serverId;
}
- public static String getResourceByNameCacheKey(String name, String serverId) {
- return "resource.name." + name + "." + serverId;
+ public static String getResourceByNameCacheKey(String name, String ownerId, String serverId) {
+ return "resource.name." + name + "." + ownerId + "." + serverId;
}
public static String getResourceByOwnerCacheKey(String owner, String serverId) {
@@ -580,17 +580,22 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
@Override
public Resource findByName(String name, String resourceServerId) {
+ return findByName(name, resourceServerId, resourceServerId);
+ }
+
+ @Override
+ public Resource findByName(String name, String ownerId, String resourceServerId) {
if (name == null) return null;
- String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
+ String cacheKey = getResourceByNameCacheKey(name, ownerId, resourceServerId);
List<Resource> result = cacheQuery(cacheKey, ResourceListQuery.class, () -> {
- Resource resource = getResourceStoreDelegate().findByName(name, resourceServerId);
+ Resource resource = getResourceStoreDelegate().findByName(name, ownerId, resourceServerId);
- if (resource == null) {
- return Collections.emptyList();
- }
+ if (resource == null) {
+ return Collections.emptyList();
+ }
- return Arrays.asList(resource);
- },
+ return Arrays.asList(resource);
+ },
(revision, resources) -> new ResourceListQuery(revision, cacheKey, resources.stream().map(resource -> resource.getId()).collect(Collectors.toSet()), resourceServerId), resourceServerId);
if (result.isEmpty()) {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java
index 4ecd445..53b294c 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remotestore/RemoteCacheSessionsLoader.java
@@ -27,12 +27,12 @@ import org.infinispan.commons.marshall.Marshaller;
import org.infinispan.context.Flag;
import org.jboss.logging.Logger;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.connections.infinispan.RemoteCacheProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.initializer.BaseCacheInitializer;
import org.keycloak.models.sessions.infinispan.initializer.OfflinePersistentUserSessionLoader;
import org.keycloak.models.sessions.infinispan.initializer.SessionLoader;
-import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -87,9 +87,9 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
@Override
public void init(KeycloakSession session) {
- RemoteCache remoteCache = InfinispanUtil.getRemoteCache(getCache(session));
+ RemoteCache remoteCache = getRemoteCache(session);
- RemoteCache<String, String> scriptCache = remoteCache.getRemoteCacheManager().getCache("___script_cache");
+ RemoteCache<String, String> scriptCache = remoteCache.getRemoteCacheManager().getCache(RemoteCacheProvider.SCRIPT_CACHE_NAME);
if (!scriptCache.containsKey("load-sessions.js")) {
scriptCache.put("load-sessions.js",
@@ -100,7 +100,7 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
@Override
public int getSessionsCount(KeycloakSession session) {
- RemoteCache remoteCache = InfinispanUtil.getRemoteCache(getCache(session));
+ RemoteCache remoteCache = getRemoteCache(session);
return remoteCache.size();
}
@@ -109,7 +109,7 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
Cache cache = getCache(session);
Cache decoratedCache = cache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD, Flag.SKIP_CACHE_STORE, Flag.IGNORE_RETURN_VALUES);
- RemoteCache<?, ?> remoteCache = InfinispanUtil.getRemoteCache(cache);
+ RemoteCache<?, ?> remoteCache = getRemoteCache(session);
log.debugf("Will do bulk load of sessions from remote cache '%s' . First: %d, max: %d", cache.getName(), first, max);
@@ -167,4 +167,10 @@ public class RemoteCacheSessionsLoader implements SessionLoader {
public void afterAllSessionsLoaded(BaseCacheInitializer initializer) {
}
+
+ // Get remoteCache, which may be secured
+ private RemoteCache getRemoteCache(KeycloakSession session) {
+ InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
+ return ispn.getRemoteCache(cacheName);
+ }
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
index e62fdd9..7bd7ec4 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
@@ -125,7 +125,7 @@ public class UserSessionAdapter implements UserSessionModel {
@Override
public void removeAuthenticatedClientSessions(Collection<String> removedClientUUIDS) {
- if (removedClientUUIDS == null || ! removedClientUUIDS.isEmpty()) {
+ if (removedClientUUIDS == null || removedClientUUIDS.isEmpty()) {
return;
}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
index 6031a6e..861853a 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
@@ -47,7 +47,7 @@ import java.util.List;
@NamedQuery(name="findResourceIdByOwner", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner"),
@NamedQuery(name="findAnyResourceIdByOwner", query="select r.id from ResourceEntity r where r.owner = :owner"),
@NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.uri = :uri"),
- @NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.name = :name"),
+ @NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :ownerId and r.name = :name"),
@NamedQuery(name="findResourceIdByType", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.type = :type"),
@NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId "),
@NamedQuery(name="findResourceIdByScope", query="select r.id from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
index c938afe..0c82dc0 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
@@ -237,11 +237,17 @@ public class JPAResourceStore implements ResourceStore {
@Override
public Resource findByName(String name, String resourceServerId) {
+ return findByName(name, resourceServerId, resourceServerId);
+ }
+
+ @Override
+ public Resource findByName(String name, String ownerId, String resourceServerId) {
TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByName", String.class);
query.setFlushMode(FlushModeType.COMMIT);
query.setParameter("serverId", resourceServerId);
query.setParameter("name", name);
+ query.setParameter("ownerId", ownerId);
try {
String id = query.getSingleResult();
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
index 0f58741..88c898b 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
@@ -285,7 +285,7 @@ public final class AuthorizationProvider implements Provider {
}
if (resource == null) {
- throw new RuntimeException("Resource [" + id + "] does not exist");
+ throw new RuntimeException("Resource [" + id + "] does not exist or is not owned by the resource server.");
}
return resource.getId();
@@ -460,6 +460,11 @@ public final class AuthorizationProvider implements Provider {
}
@Override
+ public Resource findByName(String name, String ownerId, String resourceServerId) {
+ return delegate.findByName(name, ownerId, resourceServerId);
+ }
+
+ @Override
public List<Resource> findByType(String type, String resourceServerId) {
return delegate.findByType(type, resourceServerId);
}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
index 74a2e07..cbf23cb 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
@@ -18,11 +18,26 @@
package org.keycloak.authorization.policy.evaluation;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.Decision;
import org.keycloak.authorization.Decision.Effect;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RoleUtils;
import org.keycloak.representations.idm.authorization.Logic;
/**
@@ -36,6 +51,7 @@ public class DefaultEvaluation implements Evaluation {
private final Policy policy;
private final Policy parentPolicy;
private final AuthorizationProvider authorizationProvider;
+ private final Realm realm;
private Effect effect;
public DefaultEvaluation(ResourcePermission permission, EvaluationContext executionContext, Policy parentPolicy, Policy policy, Decision decision, AuthorizationProvider authorizationProvider) {
@@ -45,6 +61,7 @@ public class DefaultEvaluation implements Evaluation {
this.policy = policy;
this.decision = decision;
this.authorizationProvider = authorizationProvider;
+ this.realm = createRealm();
}
@Override
@@ -85,6 +102,11 @@ public class DefaultEvaluation implements Evaluation {
}
@Override
+ public Realm getRealm() {
+ return realm;
+ }
+
+ @Override
public AuthorizationProvider getAuthorizationProvider() {
return authorizationProvider;
}
@@ -102,4 +124,128 @@ public class DefaultEvaluation implements Evaluation {
deny();
}
}
+
+ private Realm createRealm() {
+ return new Realm() {
+
+ @Override
+ public boolean isUserInGroup(String id, String groupId, boolean checkParent) {
+ KeycloakSession session = authorizationProvider.getKeycloakSession();
+ UserModel user = getUser(id, session);
+
+ if (Objects.isNull(user)) {
+ return false;
+ }
+
+ RealmModel realm = session.getContext().getRealm();
+ GroupModel group = KeycloakModelUtils.findGroupByPath(realm, groupId);
+
+ if (Objects.isNull(group)) {
+ return false;
+ }
+
+ if (checkParent) {
+ return RoleUtils.isMember(user.getGroups(), group);
+ }
+
+ return user.isMemberOf(group);
+ }
+
+ private UserModel getUser(String id, KeycloakSession session) {
+ RealmModel realm = session.getContext().getRealm();
+ UserModel user = session.users().getUserById(id, realm);
+
+ if (Objects.isNull(user)) {
+ user = session.users().getUserByUsername(id, realm);
+
+ if (Objects.isNull(user)) {
+ user = session.users().getUserByEmail(id, realm);
+ }
+ }
+
+ return user;
+ }
+
+ @Override
+ public boolean isUserInRealmRole(String id, String roleName) {
+ KeycloakSession session = authorizationProvider.getKeycloakSession();
+ UserModel user = getUser(id, session);
+
+ if (Objects.isNull(user)) {
+ return false;
+ }
+
+ Set<RoleModel> roleMappings = user.getRoleMappings().stream()
+ .filter(role -> !role.isClientRole())
+ .collect(Collectors.toSet());
+
+ return RoleUtils.hasRole(roleMappings, session.getContext().getRealm().getRole(roleName));
+ }
+
+ @Override
+ public boolean isUserInClientRole(String id, String clientId, String roleName) {
+ KeycloakSession session = authorizationProvider.getKeycloakSession();
+ RealmModel realm = session.getContext().getRealm();
+ UserModel user = getUser(id, session);
+
+ if (Objects.isNull(user)) {
+ return false;
+ }
+
+ Set<RoleModel> roleMappings = user.getRoleMappings().stream()
+ .filter(role -> role.isClientRole() && ClientModel.class.cast(role.getContainer()).getClientId().equals(clientId))
+ .collect(Collectors.toSet());
+
+ if (roleMappings.isEmpty()) {
+ return false;
+ }
+
+ RoleModel role = realm.getClientById(ClientModel.class.cast(roleMappings.iterator().next().getContainer()).getId()).getRole(roleName);
+
+ if (Objects.isNull(role)) {
+ return false;
+ }
+
+ return RoleUtils.hasRole(roleMappings, role);
+ }
+
+ @Override
+ public boolean isGroupInRole(String id, String role) {
+ KeycloakSession session = authorizationProvider.getKeycloakSession();
+ RealmModel realm = session.getContext().getRealm();
+ GroupModel group = KeycloakModelUtils.findGroupByPath(realm, id);
+
+ return RoleUtils.hasRoleFromGroup(group, realm.getRole(role), false);
+ }
+
+ @Override
+ public List<String> getUserRealmRoles(String id) {
+ return getUser(id, authorizationProvider.getKeycloakSession()).getRoleMappings().stream()
+ .filter(role -> !role.isClientRole())
+ .map(RoleModel::getName)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<String> getUserClientRoles(String id, String clientId) {
+ return getUser(id, authorizationProvider.getKeycloakSession()).getRoleMappings().stream()
+ .filter(role -> role.isClientRole())
+ .map(RoleModel::getName)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<String> getUserGroups(String id) {
+ return getUser(id, authorizationProvider.getKeycloakSession()).getGroups().stream()
+ .map(ModelToRepresentation::buildGroupPath)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Map<String, List<String>> getUserAttributes(String id) {
+ Map<String, List<String>> attributes = getUser(id, authorizationProvider.getKeycloakSession()).getAttributes();
+ return attributes;
+ }
+ };
+ }
}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
index 4ac0264..7fd6566 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
@@ -51,6 +51,13 @@ public interface Evaluation {
*/
Policy getPolicy();
+ /**
+ * Returns a {@link Realm} that can be used by policies to query information.
+ *
+ * @return a {@link Realm} instance
+ */
+ Realm getRealm();
+
AuthorizationProvider getAuthorizationProvider();
/**
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java
index 708f7e1..df7c705 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/PermissionTicketAwareDecisionResultCollector.java
@@ -117,7 +117,7 @@ public class PermissionTicketAwareDecisionResultCollector extends DecisionResult
Resource resource = resourceStore.findById(permission.getResourceId(), resourceServer.getId());
if (resource == null) {
- resource = resourceStore.findByName(permission.getResourceId(), resourceServer.getId());
+ resource = resourceStore.findByName(permission.getResourceId(), identity.getId(), resourceServer.getId());
}
if (!resource.isOwnerManagedAccess() || resource.getOwner().equals(identity.getId()) || resource.getOwner().equals(resourceServer.getId())) {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Realm.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Realm.java
new file mode 100644
index 0000000..b5d5dbb
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/Realm.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.evaluation;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This interface provides methods to query information from a realm.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Realm {
+
+ /**
+ * <p>Checks whether or not a user with the given <code>id</code> is a member of the given <code>group</code>.
+ *
+ * <p>This method will also consider memberships where the user is a member of any child group of the given <code>group</code>.
+ * For instance, if user is member of <code>/Group A/Group B</code> and this method is checking if user is a member of <code>/Group A</code>
+ * the result will be <code>true</code> given that the user is a member of a child group of <code>/Group A</code>.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @param group the group path. For instance, /Group A/Group B.
+ * @return true if user is a member of the given group. Otherwise returns false.
+ */
+ default boolean isUserInGroup(String id, String group) {
+ return isUserInGroup(id, group, true);
+ }
+
+ /**
+ * Checks whether or not a user with the given <code>id</code> is a member of the given <code>group</code>.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @param group the group path. For instance, /Group A/Group B.
+ * @param checkParent if true, this method returns true even though the user is not directly associated with the given group but a member of any child of the group.
+ * @return true if user is a member of the given group. Otherwise returns false.
+ */
+ boolean isUserInGroup(String id, String group, boolean checkParent);
+
+ /**
+ * Checks whether or not a user with the given <code>id</code> is granted with the given realm <code>role</code>.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @param role the role name
+ * @return true if the user is granted with the role. Otherwise, false.
+ */
+ boolean isUserInRealmRole(String id, String role);
+
+ /**
+ * Checks whether or not a user with the given <code>id</code> is granted with the given client <code>role</code>.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @param clientId the client id
+ * @param role the role name
+ * @return true if the user is granted with the role. Otherwise, false.
+ */
+ boolean isUserInClientRole(String id, String clientId, String role);
+
+ /**
+ * Checks whether or not a <code>group</code> is granted with the given realm <code>role</code>.
+ *
+ * @param group the group path. For instance, /Group A/Group B.
+ * @param role the role name
+ * @return true if the group is granted with the role. Otherwise, false.
+ */
+ boolean isGroupInRole(String group, String role);
+
+ /**
+ * Returns all realm roles granted for a user with the given <code>id</code>.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @return the roles granted to the user
+ */
+ List<String> getUserRealmRoles(String id);
+
+ /**
+ * Returns all client roles granted for a user with the given <code>id</code>.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @param clientId the client id
+ * @return the roles granted to the user
+ */
+ List<String> getUserClientRoles(String id, String clientId);
+
+ /**
+ * Returns all groups which the user with the given <code>id</code> is a member.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @return the groups which the user is a member
+ */
+ List<String> getUserGroups(String id);
+
+ /**
+ * Returns all attributes associated with the a user with the given <code>id</code>.
+ *
+ * @param id the user id. It can be the id, username or email
+ * @return a map with the attributes associated with the user
+ */
+ Map<String, List<String>> getUserAttributes(String id);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
index 9a2ac51..fd6f85c 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
@@ -97,7 +97,7 @@ public interface ResourceStore {
List<Resource> findByScope(List<String> id, String resourceServerId);
/**
- * Find a {@link Resource} by its name.
+ * Find a {@link Resource} by its name where the owner is the resource server itself.
*
* @param name the name of the resource
* @param resourceServerId the identifier of the resource server
@@ -106,6 +106,16 @@ public interface ResourceStore {
Resource findByName(String name, String resourceServerId);
/**
+ * Find a {@link Resource} by its name where the owner is the given <code>ownerId</code>.
+ *
+ * @param name the name of the resource
+ * @param ownerId the owner id
+ * @param resourceServerId the identifier of the resource server
+ * @return a resource with the given name
+ */
+ Resource findByName(String name, String ownerId, String resourceServerId);
+
+ /**
* Finds all {@link Resource} with the given type.
*
* @param type the type of the resource
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index c738b81..7324913 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -2275,7 +2275,7 @@ public class RepresentationToModel {
if (resource == null) {
resource = storeFactory.getResourceStore().findByName(resourceId, policy.getResourceServer().getId());
if (resource == null) {
- throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist");
+ throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist or is not owned by the resource server");
}
}
@@ -2303,28 +2303,6 @@ public class RepresentationToModel {
public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
- Resource existing;
-
- if (resource.getId() != null) {
- existing = resourceStore.findById(resource.getId(), resourceServer.getId());
- } else {
- existing = resourceStore.findByName(resource.getName(), resourceServer.getId());
- }
-
- if (existing != null) {
- existing.setName(resource.getName());
- existing.setDisplayName(resource.getDisplayName());
- existing.setType(resource.getType());
- existing.setUri(resource.getUri());
- existing.setIconUri(resource.getIconUri());
- existing.setOwnerManagedAccess(Boolean.TRUE.equals(resource.getOwnerManagedAccess()));
- existing.updateScopes(resource.getScopes().stream()
- .map((ScopeRepresentation scope) -> toModel(scope, resourceServer, authorization))
- .collect(Collectors.toSet()));
-
- return existing;
- }
-
ResourceOwnerRepresentation owner = resource.getOwner();
if (owner == null) {
@@ -2338,12 +2316,6 @@ public class RepresentationToModel {
throw new RuntimeException("No owner specified for resource [" + resource.getName() + "].");
}
- ClientModel clientModel = authorization.getRealm().getClientById(resourceServer.getId());
-
- if (ownerId.equals(clientModel.getClientId())) {
- ownerId = resourceServer.getId();
- }
-
if (!resourceServer.getId().equals(ownerId)) {
RealmModel realm = authorization.getRealm();
KeycloakSession keycloakSession = authorization.getKeycloakSession();
@@ -2361,6 +2333,28 @@ public class RepresentationToModel {
ownerId = ownerModel.getId();
}
+ Resource existing;
+
+ if (resource.getId() != null) {
+ existing = resourceStore.findById(resource.getId(), resourceServer.getId());
+ } else {
+ existing = resourceStore.findByName(resource.getName(), ownerId, resourceServer.getId());
+ }
+
+ if (existing != null) {
+ existing.setName(resource.getName());
+ existing.setDisplayName(resource.getDisplayName());
+ existing.setType(resource.getType());
+ existing.setUri(resource.getUri());
+ existing.setIconUri(resource.getIconUri());
+ existing.setOwnerManagedAccess(Boolean.TRUE.equals(resource.getOwnerManagedAccess()));
+ existing.updateScopes(resource.getScopes().stream()
+ .map((ScopeRepresentation scope) -> toModel(scope, resourceServer, authorization))
+ .collect(Collectors.toSet()));
+
+ return existing;
+ }
+
Resource model = resourceStore.create(resource.getName(), resourceServer, ownerId);
model.setDisplayName(resource.getDisplayName());
services/pom.xml 43(+22 -21)
diff --git a/services/pom.xml b/services/pom.xml
index 77e15c7..1f212e6 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -205,27 +205,6 @@
<profile>
<id>jboss-release</id>
- <repositories>
- <repository>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- <id>central</id>
- <name>bintray</name>
- <url>https://jcenter.bintray.com</url>
- </repository>
- </repositories>
- <pluginRepositories>
- <pluginRepository>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- <id>central</id>
- <name>bintray</name>
- <url>https://jcenter.bintray.com</url>
- </pluginRepository>
- </pluginRepositories>
-
<build>
<plugins>
<plugin>
@@ -289,6 +268,28 @@
<artifactId>swagger2markup-maven-plugin</artifactId>
<version>1.1.0</version>
+ <!-- Replace the dependencies that aren't in Maven Central -->
+ <dependencies>
+ <dependency>
+ <groupId>ca.szc.thirdparty.nl.jworks.markdown_to_asciidoc</groupId>
+ <artifactId>markdown_to_asciidoc</artifactId>
+ <!-- Keep in sync with markup-document-builder's dependency -->
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>io.github.swagger2markup</groupId>
+ <artifactId>swagger2markup</artifactId>
+ <!-- Keep in sync with swagger2markup-maven-plugin's dependency -->
+ <version>1.1.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>nl.jworks.markdown_to_asciidoc</groupId>
+ <artifactId>markdown_to_asciidoc</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+
<executions>
<execution>
<id>gen-asciidoc</id>
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
index d5c6b60..742454e 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
@@ -57,6 +57,7 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
public static final String MAPPING_SOURCE_SELECTION = "x509-cert-auth.mapping-source-selection";
public static final String MAPPING_SOURCE_CERT_SUBJECTDN = "Match SubjectDN using regular expression";
public static final String MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL = "Subject's e-mail";
+ public static final String MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL = "Subject's Alternative Name E-mail";
public static final String MAPPING_SOURCE_CERT_SUBJECTDN_CN = "Subject's Common Name";
public static final String MAPPING_SOURCE_CERT_ISSUERDN = "Match IssuerDN using regular expression";
public static final String MAPPING_SOURCE_CERT_ISSUERDN_EMAIL = "Issuer's e-mail";
@@ -146,6 +147,9 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
.either(UserIdentityExtractor.getX500NameExtractor(BCStyle.EmailAddress, subject))
.or(UserIdentityExtractor.getX500NameExtractor(BCStyle.E, subject));
break;
+ case SUBJECTALTNAME_EMAIL:
+ extractor = UserIdentityExtractor.getSubjectAltNameExtractor(1);
+ break;
case ISSUERDN_CN:
extractor = UserIdentityExtractor.getX500NameExtractor(BCStyle.CN, issuer);
break;
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
index 03601e2..29af551 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
@@ -43,6 +43,7 @@ import static org.keycloak.authentication.authenticators.x509.AbstractX509Client
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_ISSUERDN_CN;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_ISSUERDN_EMAIL;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SERIALNUMBER;
+import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTDN;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTDN_CN;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL;
@@ -68,6 +69,7 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
private static final String[] mappingSources = {
MAPPING_SOURCE_CERT_SUBJECTDN,
MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL,
+ MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL,
MAPPING_SOURCE_CERT_SUBJECTDN_CN,
MAPPING_SOURCE_CERT_ISSUERDN,
MAPPING_SOURCE_CERT_ISSUERDN_EMAIL,
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
index ef29aec..881fdb7 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
@@ -25,7 +25,11 @@ import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.keycloak.services.ServicesLogger;
+import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -92,6 +96,52 @@ public abstract class UserIdentityExtractor {
}
}
+ /**
+ * Extracts the subject identifier from the subjectAltName extension.
+ */
+ static class SubjectAltNameExtractor extends UserIdentityExtractor {
+
+ private final int generalName;
+
+ /**
+ * Creates a new instance
+ *
+ * @param generalName an integer representing the general name. See {@link X509Certificate#getSubjectAlternativeNames()}
+ */
+ SubjectAltNameExtractor(int generalName) {
+ this.generalName = generalName;
+ }
+
+ @Override
+ public Object extractUserIdentity(X509Certificate[] certs) {
+ if (certs == null || certs.length == 0) {
+ throw new IllegalArgumentException();
+ }
+
+ try {
+ Collection<List<?>> subjectAlternativeNames = certs[0].getSubjectAlternativeNames();
+
+ if (subjectAlternativeNames == null) {
+ return null;
+ }
+
+ Iterator<List<?>> iterator = subjectAlternativeNames.iterator();
+
+ while (iterator.hasNext()) {
+ List<?> next = iterator.next();
+
+ if (Integer.class.cast(next.get(0)) == generalName) {
+ return next.get(1);
+ }
+ }
+ } catch (CertificateParsingException cause) {
+ logger.errorf(cause, "Failed to obtain identity from subjectAltName extension");
+ }
+
+ return null;
+ }
+ }
+
static class PatternMatcher extends UserIdentityExtractor {
private final String _pattern;
private final Function<X509Certificate[],String> _f;
@@ -143,6 +193,16 @@ public abstract class UserIdentityExtractor {
return new X500NameRDNExtractor(identifier, x500Name);
}
+ /**
+ * Obtains the subjectAltName given a <code>generalName</code>.
+ *
+ * @param generalName an integer representing the general name. See {@link X509Certificate#getSubjectAlternativeNames()}
+ * @return the value from the subjectAltName extension
+ */
+ public static SubjectAltNameExtractor getSubjectAltNameExtractor(int generalName) {
+ return new SubjectAltNameExtractor(generalName);
+ }
+
public static OrBuilder either(UserIdentityExtractor extractor) {
return new OrBuilder(extractor);
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
index 87c60b4..a738f42 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
@@ -60,6 +60,7 @@ public class X509AuthenticatorConfigModel extends AuthenticatorConfigModel {
ISSUERDN(MAPPING_SOURCE_CERT_ISSUERDN),
SUBJECTDN_CN(MAPPING_SOURCE_CERT_SUBJECTDN_CN),
SUBJECTDN_EMAIL(MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL),
+ SUBJECTALTNAME_EMAIL(MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL),
SUBJECTDN(MAPPING_SOURCE_CERT_SUBJECTDN);
private String name;
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
index 0e4f911..04c9d74 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
@@ -118,7 +118,6 @@ public class ResourceSetService {
public Response create(ResourceRepresentation resource, Function<Resource, ?> toRepresentation) {
requireManage();
StoreFactory storeFactory = this.authorization.getStoreFactory();
- Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), this.resourceServer.getId());
ResourceOwnerRepresentation owner = resource.getOwner();
if (owner == null) {
@@ -132,7 +131,9 @@ public class ResourceSetService {
return ErrorResponse.error("You must specify the resource owner.", Status.BAD_REQUEST);
}
- if (existingResource != null && existingResource.getOwner().equals(ownerId)) {
+ Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), ownerId, this.resourceServer.getId());
+
+ if (existingResource != null) {
return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists.");
}
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
index a8075a0..989d228 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -172,13 +172,13 @@ public class AuthorizationTokenService {
private List<Result> evaluatePermissions(AuthorizationRequest authorizationRequest, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
return authorization.evaluators()
- .from(createPermissions(ticket, authorizationRequest, resourceServer, authorization), evaluationContext)
+ .from(createPermissions(ticket, authorizationRequest, resourceServer, identity, authorization), evaluationContext)
.evaluate();
}
private List<Result> evaluateUserManagedPermissions(AuthorizationRequest request, PermissionTicketToken ticket, ResourceServer resourceServer, KeycloakEvaluationContext evaluationContext, KeycloakIdentity identity) {
return authorization.evaluators()
- .from(createPermissions(ticket, request, resourceServer, authorization), evaluationContext)
+ .from(createPermissions(ticket, request, resourceServer, identity, authorization), evaluationContext)
.evaluate(new PermissionTicketAwareDecisionResultCollector(request, ticket, identity, resourceServer, authorization)).results();
}
@@ -276,7 +276,7 @@ public class AuthorizationTokenService {
return evaluationContextProvider.apply(authorizationRequest, authorization);
}
- private List<ResourcePermission> createPermissions(PermissionTicketToken ticket, AuthorizationRequest request, ResourceServer resourceServer, AuthorizationProvider authorization) {
+ private List<ResourcePermission> createPermissions(PermissionTicketToken ticket, AuthorizationRequest request, ResourceServer resourceServer, KeycloakIdentity identity, AuthorizationProvider authorization) {
StoreFactory storeFactory = authorization.getStoreFactory();
Map<String, Set<String>> permissionsToEvaluate = new LinkedHashMap<>();
ResourceStore resourceStore = storeFactory.getResourceStore();
@@ -294,17 +294,31 @@ public class AuthorizationTokenService {
requestedScopes = new HashSet<>();
}
- Resource existingResource = null;
+ List<Resource> existingResources = new ArrayList<>();
if (requestedResource.getResourceId() != null) {
- existingResource = resourceStore.findById(requestedResource.getResourceId(), resourceServer.getId());
+ Resource resource = resourceStore.findById(requestedResource.getResourceId(), resourceServer.getId());
- if (existingResource == null) {
- existingResource = resourceStore.findByName(requestedResource.getResourceId(), resourceServer.getId());
+ if (resource != null) {
+ existingResources.add(resource);
+ } else {
+ Resource ownerResource = resourceStore.findByName(requestedResource.getResourceId(), identity.getId(), resourceServer.getId());
+
+ if (ownerResource != null) {
+ existingResources.add(ownerResource);
+ }
+
+ if (!identity.isResourceServer()) {
+ Resource serverResource = resourceStore.findByName(requestedResource.getResourceId(), resourceServer.getId());
+
+ if (serverResource != null) {
+ existingResources.add(serverResource);
+ }
+ }
}
}
- if (existingResource == null && (requestedScopes == null || requestedScopes.isEmpty())) {
+ if (existingResources.isEmpty() && (requestedScopes == null || requestedScopes.isEmpty())) {
throw new CorsErrorResponseException(cors, "invalid_resource", "Resource with id [" + requestedResource.getResourceId() + "] does not exist.", Status.FORBIDDEN);
}
@@ -314,18 +328,20 @@ public class AuthorizationTokenService {
requestedScopes.addAll(Arrays.asList(clientAdditionalScopes.split(" ")));
}
- if (existingResource != null) {
- Set<String> scopes = permissionsToEvaluate.get(existingResource.getId());
+ if (!existingResources.isEmpty()) {
+ for (Resource resource : existingResources) {
+ Set<String> scopes = permissionsToEvaluate.get(resource.getId());
- if (scopes == null) {
- scopes = new HashSet<>();
- permissionsToEvaluate.put(existingResource.getId(), scopes);
- if (limit != null) {
- limit--;
+ if (scopes == null) {
+ scopes = new HashSet<>();
+ permissionsToEvaluate.put(resource.getId(), scopes);
+ if (limit != null) {
+ limit--;
+ }
}
- }
- scopes.addAll(requestedScopes);
+ scopes.addAll(requestedScopes);
+ }
} else {
List<Resource> resources = resourceStore.findByScope(new ArrayList<>(requestedScopes), ticket.getAudience()[0]);
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
index 58962b5..b2ea5d4 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
@@ -224,7 +224,7 @@ public class KeycloakIdentity implements Identity {
return this.accessToken;
}
- private boolean isResourceServer() {
+ public boolean isResourceServer() {
UserModel clientUser = null;
ClientModel clientModel = getTargetClient();
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java b/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
index 7a8e05e..7dd3496 100644
--- a/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
@@ -67,41 +67,61 @@ public class AbstractPermissionService {
private List<ResourceRepresentation> verifyRequestedResource(List<PermissionRequest> request) {
ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+ List<ResourceRepresentation> requestedResources = new ArrayList<>();
- return request.stream().map(permissionRequest -> {
+ for (PermissionRequest permissionRequest : request) {
String resourceSetId = permissionRequest.getResourceId();
- Resource resource = null;
+ List<Resource> resources = new ArrayList<>();
if (resourceSetId == null) {
if (permissionRequest.getScopes() == null || permissionRequest.getScopes().isEmpty()) {
throw new ErrorResponseException("invalid_resource_id", "Resource id or name not provided.", Response.Status.BAD_REQUEST);
}
} else {
- resource = resourceStore.findById(resourceSetId, resourceServer.getId());
+ Resource resource = resourceStore.findById(resourceSetId, resourceServer.getId());
- if (resource == null) {
- resource = resourceStore.findByName(resourceSetId, this.resourceServer.getId());
+ if (resource != null) {
+ resources.add(resource);
+ } else {
+ Resource userResource = resourceStore.findByName(resourceSetId, identity.getId(), this.resourceServer.getId());
+
+ if (userResource != null) {
+ resources.add(userResource);
+ }
+
+ if (!identity.isResourceServer()) {
+ Resource serverResource = resourceStore.findByName(resourceSetId, this.resourceServer.getId());
+
+ if (serverResource != null) {
+ resources.add(serverResource);
+ }
+ }
}
- if (resource == null) {
+ if (resources.isEmpty()) {
throw new ErrorResponseException("invalid_resource_id", "Resource set with id [" + resourceSetId + "] does not exists in this server.", Response.Status.BAD_REQUEST);
}
}
- Set<ScopeRepresentation> scopes = verifyRequestedScopes(permissionRequest, resource);
+ if (resources.isEmpty()) {
+ requestedResources.add(new ResourceRepresentation(null, verifyRequestedScopes(permissionRequest, null)));
- if (resource != null) {
- ResourceRepresentation representation = new ResourceRepresentation(resource.getName(), scopes);
+ } else {
+ for (Resource resource : resources) {
+ Set<ScopeRepresentation> scopes = verifyRequestedScopes(permissionRequest, resource);
- representation.setId(resource.getId());
- representation.setOwnerManagedAccess(resource.isOwnerManagedAccess());
- representation.setOwner(new ResourceOwnerRepresentation(resource.getOwner()));
+ ResourceRepresentation representation = new ResourceRepresentation(resource.getName(), scopes);
- return representation;
+ representation.setId(resource.getId());
+ representation.setOwnerManagedAccess(resource.isOwnerManagedAccess());
+ representation.setOwner(new ResourceOwnerRepresentation(resource.getOwner()));
+
+ requestedResources.add(representation);
+ }
}
+ }
- return new ResourceRepresentation(null, scopes);
- }).collect(Collectors.toList());
+ return requestedResources;
}
private Set<ScopeRepresentation> verifyRequestedScopes(PermissionRequest request, Resource resource) {
diff --git a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
index a722f8e..ef4cb85 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
@@ -59,6 +59,7 @@ import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.net.URI;
+import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -315,6 +316,13 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
uriBuilder.queryParam(OAuth2Constants.PROMPT, prompt);
}
+ String nonce = request.getAuthenticationSession().getClientNote(OIDCLoginProtocol.NONCE_PARAM);
+ if (nonce == null || nonce.isEmpty()) {
+ nonce = UUID.randomUUID().toString();
+ request.getAuthenticationSession().setClientNote(OIDCLoginProtocol.NONCE_PARAM, nonce);
+ }
+ uriBuilder.queryParam(OIDCLoginProtocol.NONCE_PARAM, nonce);
+
String acr = request.getAuthenticationSession().getClientNote(OAuth2Constants.ACR_VALUES);
if (acr != null) {
uriBuilder.queryParam(OAuth2Constants.ACR_VALUES, acr);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java
index 3562ed5..46a11a2 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java
@@ -23,6 +23,7 @@ import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.ErrorPageException;
import org.keycloak.services.ServicesLogger;
@@ -31,6 +32,9 @@ import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.io.InputStream;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_URI;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -50,6 +54,19 @@ public class AuthorizationEndpointRequestParserProcessor {
throw new RuntimeException("Illegal to use both 'request' and 'request_uri' parameters together");
}
+ String requestObjectRequired = OIDCAdvancedConfigWrapper.fromClientModel(client).getRequestObjectRequired();
+
+ if (REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI.equals(requestObjectRequired)
+ && requestParam == null && requestUriParam == null) {
+ throw new RuntimeException("Client is required to use 'request' or 'request_uri' parameter.");
+ } else if (REQUEST_OBJECT_REQUIRED_REQUEST.equals(requestObjectRequired)
+ && requestParam == null) {
+ throw new RuntimeException("Client is required to use 'request' parameter.");
+ } else if (REQUEST_OBJECT_REQUIRED_REQUEST_URI.equals(requestObjectRequired)
+ && requestUriParam == null) {
+ throw new RuntimeException("Client is required to use 'request_uri' parameter.");
+ }
+
if (requestParam != null) {
new AuthzEndpointRequestObjectParser(session, requestParam, client).parseRequest(request);
} else if (requestUriParam != null) {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java
index 6f4ff75..600214e 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java
@@ -31,6 +31,11 @@ public class OIDCAdvancedConfigWrapper {
private static final String USER_INFO_RESPONSE_SIGNATURE_ALG = "user.info.response.signature.alg";
private static final String REQUEST_OBJECT_SIGNATURE_ALG = "request.object.signature.alg";
+
+ private static final String REQUEST_OBJECT_REQUIRED = "request.object.required";
+ public static final String REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI = "request or request_uri";
+ public static final String REQUEST_OBJECT_REQUIRED_REQUEST = "request only";
+ public static final String REQUEST_OBJECT_REQUIRED_REQUEST_URI = "request_uri only";
private static final String JWKS_URL = "jwks.url";
@@ -79,6 +84,14 @@ public class OIDCAdvancedConfigWrapper {
String algStr = alg==null ? null : alg.toString();
setAttribute(REQUEST_OBJECT_SIGNATURE_ALG, algStr);
}
+
+ public String getRequestObjectRequired() {
+ return getAttribute(REQUEST_OBJECT_REQUIRED);
+ }
+
+ public void setRequestObjectRequired(String requestObjectRequired) {
+ setAttribute(REQUEST_OBJECT_REQUIRED, requestObjectRequired);
+ }
public boolean isUseJwksUrl() {
String useJwksUrl = getAttribute(USE_JWKS_URL);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 4da336c..56c0022 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -219,7 +219,11 @@ public class OIDCLoginProtocol implements LoginProtocol {
if (responseType.hasResponseType(OIDCResponseType.CODE)) {
responseBuilder.generateCodeHash(code);
}
-
+
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ if (state != null && !state.isEmpty())
+ responseBuilder.generateStateHash(state);
}
AccessTokenResponse res = responseBuilder.build();
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index e21f3ad..41b71a7 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -718,6 +718,10 @@ public class TokenManager {
boolean generateAccessTokenHash = false;
String codeHash;
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ String stateHash;
+
public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
this.realm = realm;
this.client = client;
@@ -819,6 +823,12 @@ public class TokenManager {
return this;
}
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ public AccessTokenResponseBuilder generateStateHash(String state) {
+ stateHash = HashProvider.oidcHash(jwsAlgorithm, state);
+ return this;
+ }
public AccessTokenResponse build() {
KeyManager.ActiveRsaKey activeRsaKey = session.keys().getActiveRsaKey(realm);
@@ -854,7 +864,11 @@ public class TokenManager {
if (codeHash != null) {
idToken.setCodeHash(codeHash);
}
-
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ if (stateHash != null) {
+ idToken.setStateHash(stateHash);
+ }
if (idToken != null) {
String encodedToken = new JWSBuilder().type(JWT).kid(activeRsaKey.getKid()).jsonContent(idToken).sign(jwsAlgorithm, activeRsaKey.getPrivateKey());
res.setIdToken(encodedToken);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 02063fa..a61dd05 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -32,8 +32,8 @@ import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserManager;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
@@ -573,13 +573,17 @@ public class ClientResource {
private void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
+ UserModel serviceAccount = this.session.users().getServiceAccount(client);
if (TRUE.equals(rep.isServiceAccountsEnabled())) {
- UserModel serviceAccount = this.session.users().getServiceAccount(client);
-
if (serviceAccount == null) {
new ClientManager(new RealmManager(session)).enableServiceAccount(client);
}
}
+ else {
+ if (serviceAccount != null) {
+ new UserManager(session).removeUser(realm, serviceAccount);
+ }
+ }
if (!rep.getClientId().equals(client.getClientId())) {
new ClientManager(new RealmManager(session)).clientIdChanged(client, rep.getClientId());
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli b/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli
index fd08666..2e50470 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/crossdc/cross-dc-setup.cli
@@ -139,4 +139,8 @@ echo *** Enable debug logging ***
echo *** Update undertow subsystem ***
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)
+echo *** Update keycloak-server subsystem, infinispan remoteStoreSecurity ***
+/subsystem=keycloak-server/spi=connectionsInfinispan/provider=default:map-put(name=properties,key=remoteStoreSecurityEnabled,value=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled:true})
+
+
echo **** End ****
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore
index 5253c8f..d461868 100644
Binary files a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore and b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore differ
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/README.md b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/README.md
new file mode 100644
index 0000000..9766cc3
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/README.md
@@ -0,0 +1,8 @@
+# Keycloak Arquillian Integration Testsuite
+
+This directory contains a OpenSSL CA and Intermediate CA that can be used to manage certificates.
+
+## Passwords
+
+Passwords for any key file is `password`.
+
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/ca.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/ca.cert.pem
new file mode 100644
index 0000000..123bef7
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/ca.cert.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+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
+SCc=
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user@localhost.key.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user@localhost.key.pem
new file mode 100644
index 0000000..20ff9ff
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user@localhost.key.pem
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,58507FBFA90F44D96D42E8ED4989032F
+
+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
+-----END RSA PRIVATE KEY-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-san-email@localhost.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-san-email@localhost.cert.pem
new file mode 100644
index 0000000..4a00a12
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-san-email@localhost.cert.pem
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt
new file mode 100644
index 0000000..6976f7c
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt
@@ -0,0 +1 @@
+V 450708195701Z 1000 unknown /C=US/ST=MA/O=Red Hat/OU=Keycloak/CN=Keycloak Intermediate CA/emailAddress=contact@keycloak.org
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr
new file mode 100644
index 0000000..8f7e63a
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/1 b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/1
new file mode 100644
index 0000000..b596754
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/1
@@ -0,0 +1,131 @@
+# OpenSSL root CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = Keycloak
+
+[ Keycloak ]
+# Directory and file locations.
+dir = ./
+certs = $dir/certs
+crl_dir = $dir/crl
+new_certs_dir = $dir/newcerts
+database = $dir/index.txt
+serial = $dir/serial
+RANDFILE = $dir/private/.rand
+
+# The root key and root certificate.
+private_key = $dir/private/ca.key.pem
+certificate = $dir/certs/ca.cert.pem
+
+# For certificate revocation lists.
+crlnumber = $dir/crlnumber
+crl = $dir/crl/ca.crl.pem
+crl_extensions = crl_ext
+default_crl_days = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 375
+preserve = no
+policy = policy_strict
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits = 2048
+distinguished_name = req_distinguished_name
+string_mask = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName = Country Name (2 letter code)
+stateOrProvinceName = State or Province Name
+localityName = Locality Name
+0.organizationName = Organization Name
+organizationalUnitName = Organizational Unit Name
+commonName = Common Name
+emailAddress = Email Address
+
+# Optionally, specify some defaults.
+countryName_default = US
+stateOrProvinceName_default = MA
+localityName_default = Boston
+0.organizationName_default = Red Hat
+organizationalUnitName_default = Keycloak
+emailAddress_default = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem
new file mode 100644
index 0000000..bcfaf61
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem
@@ -0,0 +1,69 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF/jCCA+agAwIBAgIJAOMEN39fZf7uMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJvc3RvbjEQMA4GA1UECgwH
+UmVkIEhhdDERMA8GA1UECwwIS2V5Y2xvYWsxFDASBgNVBAMMC0tleWNsb2FrIENB
+MSMwIQYJKoZIhvcNAQkBFhRjb250YWN0QGtleWNsb2FrLm9yZzAeFw0xODAyMjAx
+OTQ3NTFaFw00NTA3MDgxOTQ3NTFaMIGLMQswCQYDVQQGEwJVUzELMAkGA1UECAwC
+TUExDzANBgNVBAcMBkJvc3RvbjEQMA4GA1UECgwHUmVkIEhhdDERMA8GA1UECwwI
+S2V5Y2xvYWsxFDASBgNVBAMMC0tleWNsb2FrIENBMSMwIQYJKoZIhvcNAQkBFhRj
+b250YWN0QGtleWNsb2FrLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAJlGjg05FzCm3f3YdIbMHNYuORfiP2n6YhX7vQyDjF/4gh7EYEYgE7spJ864
+/DySQenJ55Jn22K/1MQ1rOHcqfTioIgN3eEAyyuMDx60KU3frMBRYeCgLJVZQHr0
+6x+Sh/+SbbIYq/558+g/6PSZjmPBindHsPzGuBPaLOW4Jz47CA73L/su2qnJGeAi
+UaK/tXmANs1bqJbiNRDr9IJFkdusx1mql2ElfknJT8U+LBPOOID/S7Xd83SKtpFI
+Q8Vikb6C0SKnopOJiG2uWg5g7CYlNYxJpAM25zhDqp71bl8zOsIL2tFfUAvvoBnh
+N31kDIl8RZJ5ELnh+t5SCfwbgdfMzS7uht8qVTeZ0/BG80Lzl1gfzNR8q45gsKC9
+7mg7Voj68kt2aZr+E3Ng1guK69gePMxCpqLyjwlKz187mNUme+zxg2gL2egs4M6u
+ffqsEd0c5QryrRSTcIXi8Bim6PDhL93dBsenAIg25DOJNA6Vt2LELoe9w0TkL48U
+wUvU6GYB7/zM/z3EW45ZkRhHWK+HZppqDAb05lgJeeKUxxdUSy+ot7ls6cSqACYo
+fVjPoVHPD5Ncx+6NGHPGM5N3FGvMMh64PYpChyVWDTEfrZIS7Yyj9Iz/2eCxV3cO
+cO4bU0K6kx/dWRic5B5ymVtRME93+Of/hQuta4uLhlo8ZxRpAgMBAAGjYzBhMB0G
+A1UdDgQWBBQiuPS7cwDHKT+TgKX2HFICast6UjAfBgNVHSMEGDAWgBQiuPS7cwDH
+KT+TgKX2HFICast6UjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAN
+BgkqhkiG9w0BAQsFAAOCAgEAVCVXdx79ooKyOaL+S49S4agP7mE4IxuDefDwQ2dm
+996wpk3nntg0y54Auu1Y2plJirBhTvYZ1RedLNBMVBypm6BQpNn37u5TI39/FYso
+GFPINu1EzLTYl0bFKc0w7UFlFusje9zXLWISm8uTNzxJ1RGLrcnv9gfiXPKxAmN0
+cz9WY0vm+0+OV50HvLyUyqGKxyWmt2ek4jV+oEhsMMSO/MVNNXHEo2MAGcA23XPe
+7FZkiFB1suDIMzzUFCrRBtoZjYSUeyN9Pd0Yg3twl96CLqld4xFjsKMIsz0ACGRI
+8OpzeHAsePH4yS94E6nLwWH9YTi6pgTtoXSaVBLvIYpVHi8UAyIBFNqLMCukoq0O
+BlOdkO0zescmpEtp8GiUWMuB7x+kkaSxmsujEfL3mRWshkqaz/ZHPKXaNtPBUtIM
+jQnTMBF/wQjZxCGAps8dOMZ9pYnZcmVz0KeXpBJe1j+47MhItgt1wQNoyr4iBaxE
+3fAF/Arr/IZtIf0erXOjc7P6dEQW+WiKWvEA5Mp+4tV3Zj2pwSSX5bKDKx4RAkoW
+1jLTE1KN5RWvF8phStLty83gTd5wgykFSl65Lu7KIBW9HH3LIK46fb+cOBOZfSn3
+mdQXrbuXNUXgbhrsetnBfPNMAkJjaBQLNTxebIvXndiTIEsWqHS7h1x+kBkDOKhw
+SCc=
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/intermediate.cert.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/intermediate.cert.pem
new file mode 100644
index 0000000..3521cbc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/certs/intermediate.cert.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/crlnumber b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/crlnumber
new file mode 100644
index 0000000..83b33d2
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/crlnumber
@@ -0,0 +1 @@
+1000
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/csr/intermediate.csr.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/csr/intermediate.csr.pem
new file mode 100644
index 0000000..0cc3a5b
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/csr/intermediate.csr.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIE3jCCAsYCAQAwgZgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE
+BwwGQm9zdG9uMRAwDgYDVQQKDAdSZWQgSGF0MREwDwYDVQQLDAhLZXljbG9hazEh
+MB8GA1UEAwwYS2V5Y2xvYWsgSW50ZXJtZWRpYXRlIENBMSMwIQYJKoZIhvcNAQkB
+FhRjb250YWN0QGtleWNsb2FrLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
+AgoCggIBANiLHXMlNrpNOyY+Ny1zVHnq9g+wiER7JGKzscvyz4RsVsGk7yNZJJJo
+mnQxaRqFS1aJ271xYrnI8LR7NQPcthyWS0bVjrPF5joblGc0JSBXwRiR4IkCaUZW
+GAWNT7uvoc2HUvawsl6NQ4oywpwjG3VOmJRumH/cnVOuo9YMPWMjAH3fft29l9d3
+AhrjmmGTVJvvCBHpoHiYk8oGl6SSH/laHlBFcj7b5W/UyGrpK3HUx0Tg/a7yVuUg
+I6WcJohaIjoHbvKi3bGFyJ7XC8XBrWKq0Gvi0gcsifRc0rCqh6igz5YeWTCMwX9i
+nXNgkkmaReOHVrdkhPntZ7VTdHEmst/ETQPgab9LtDfTbHGIC4N3JwfHqjPiphjA
+hhlWT7/yrgINdXKjRoJjh71+wA+Ym/LlPApk4qhyiP4EUDJHA93WJWtIZ4BBMkE9
+wyC7vSj3FUGdTw+CyJ87kfOlfD0tNGsNpNLgFn+tgD08MvN7ExWuBUKD5fV1F3dP
+0iws86Wj4cKl80aF+BGXCnz9JEaYG6JobmTqRpJw/maKZIZg6+GNEcs2Rj5GC2X6
+GswOfwMV3vk+Jsz3mEaJr2TWpuuOaP2BEYDjHPVAGp7B3ZNOACForEMWpB5z5wnX
+m9/kDEHgD8qoWaphdhcBCkpzNu3aChPJvYCeeGlrlYl7+xi9ipNTAgMBAAGgADAN
+BgkqhkiG9w0BAQsFAAOCAgEAtZp+hULw+DW9TCzW1Sm1+r4cb6QN/DpWe4lvbSoU
+ah0oiUAa/xF9AaDR2woHvMWXzMehc42Z+4F40L+XSdM1VAg6B36BKM7fYiyGQExo
+bJF0oUqeRD6WneZNCd4APnmzAiMCU6uWzgLbkoUXw9JtNr3uxhIXvg3E+BasU5/F
+pb9UqTHBsSc1yAxhMT9zLOXLpkvX+mrWzkkbc09Schus8wM6naf6oWhgW5uNVQaw
+M3ZemlVmY7LYUwJKamNr7CRpzSPnFed+a77ogOFY1IjfuknYLPKlAaPtBuV5kEWB
+Bx0JjMNoGoqL+FxUqpX6+8RzksSGCecje6q3+j4nm8p2RrhVf4/dfupSTDI3ijGl
+Z0Y+eV0H88EySvnw6TKi9QCHBEc4TVKKA4wD6nASzMK2GtuqdutLJpd3ADgV/p32
+BZ/NM8aB2iGo5S4nnDwjvGIzaHgamZbLkAuFBTQtjzghgwJK0D5FtFmWxn+0PpP4
+IKntdvJXQVMuLL/CYa0L9BFcUbSNbglykfggGAv/kU0tOmDNdW6wv8IlN1c34KOM
+W2GYKDmcn5LTSzRmvN8E9kjvMLYVyFf8TeBpo8K34dkMRODu6LTQVu3EhKN2OZt9
+QXf79Y5zjNQwfdm2s4GBDK/+fkL04Hg69sbOeOID8aYQxy8fyxELad1fYsnas6P6
+u1I=
+-----END CERTIFICATE REQUEST-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt
new file mode 100644
index 0000000..60d4030
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt
@@ -0,0 +1 @@
+V 450708200730Z 1000 unknown /C=US/ST=MA/L=Boston/O=Red Hat/OU=Keycloak/CN=test-user
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.attr b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.attr
new file mode 100644
index 0000000..8f7e63a
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.old
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/index.txt.old
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/newcerts/1000.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/newcerts/1000.pem
new file mode 100644
index 0000000..4a00a12
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/newcerts/1000.pem
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl.cnf b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl.cnf
new file mode 100644
index 0000000..acd341f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl.cnf
@@ -0,0 +1,135 @@
+# OpenSSL intermediate CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = KeycloakICA
+
+[ KeycloakICA ]
+# Directory and file locations.
+dir = ./intermediate
+certs = $dir/certs
+crl_dir = $dir/crl
+new_certs_dir = $dir/newcerts
+database = $dir/index.txt
+serial = $dir/serial
+RANDFILE = $dir/private/.rand
+
+# The root key and root certificate.
+private_key = $dir/private/intermediate.key.pem
+certificate = $dir/certs/intermediate.cert.pem
+
+# For certificate revocation lists.
+crlnumber = $dir/crlnumber
+crl = $dir/crl/intermediate.crl.pem
+crl_extensions = crl_ext
+default_crl_days = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 375
+preserve = no
+policy = policy_loose
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits = 2048
+distinguished_name = req_distinguished_name
+string_mask = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName = Country Name (2 letter code)
+stateOrProvinceName = State or Province Name
+localityName = Locality Name
+0.organizationName = Organization Name
+organizationalUnitName = Organizational Unit Name
+commonName = Common Name
+emailAddress = Email Address
+
+# Optionally, specify some defaults.
+countryName_default = US
+stateOrProvinceName_default = MA
+localityName_default = Boston
+0.organizationName_default = Red Hat
+organizationalUnitName_default =
+emailAddress_default = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+crlDistributionPoints = URI:http://localhost:8888/crl
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+crlDistributionPoints = URI:http://localhost:8888/crl
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl-san.cnf b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl-san.cnf
new file mode 100644
index 0000000..4bf6ffc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/openssl-san.cnf
@@ -0,0 +1,139 @@
+# OpenSSL intermediate CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = KeycloakICA
+
+[ KeycloakICA ]
+# Directory and file locations.
+dir = ./intermediate
+certs = $dir/certs
+crl_dir = $dir/crl
+new_certs_dir = $dir/newcerts
+database = $dir/index.txt
+serial = $dir/serial
+RANDFILE = $dir/private/.rand
+
+email_in_dn = no
+
+# The root key and root certificate.
+private_key = $dir/private/intermediate.key.pem
+certificate = $dir/certs/intermediate.cert.pem
+
+# For certificate revocation lists.
+crlnumber = $dir/crlnumber
+crl = $dir/crl/intermediate.crl.pem
+crl_extensions = crl_ext
+default_crl_days = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 375
+preserve = no
+policy = policy_loose
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits = 2048
+distinguished_name = req_distinguished_name
+string_mask = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName = Country Name (2 letter code)
+stateOrProvinceName = State or Province Name
+localityName = Locality Name
+0.organizationName = Organization Name
+organizationalUnitName = Organizational Unit Name
+commonName = Common Name
+emailAddress = Email Address
+
+# Optionally, specify some defaults.
+countryName_default = US
+stateOrProvinceName_default = MA
+localityName_default = Boston
+0.organizationName_default = Red Hat
+organizationalUnitName_default = Keycloak
+emailAddress_default = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+crlDistributionPoints = URI:http://localhost:8888/crl
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+subjectAltName=email:copy
+subjectAltName=email:move
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+crlDistributionPoints = URI:http://localhost:8888/crl
+authorityInfoAccess = OCSP;URI:http://localhost:8888/oscp
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/private/intermediate.key.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/private/intermediate.key.pem
new file mode 100644
index 0000000..3116bf9
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/private/intermediate.key.pem
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,55738491E62D25465F4122B4D81938FA
+
+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
+-----END RSA PRIVATE KEY-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial
new file mode 100644
index 0000000..dd11724
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial
@@ -0,0 +1 @@
+1001
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial.old
new file mode 100644
index 0000000..83b33d2
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/intermediate/serial.old
@@ -0,0 +1 @@
+1000
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1000.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1000.pem
new file mode 100644
index 0000000..3521cbc
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1000.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/openssl.cnf b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/openssl.cnf
new file mode 100644
index 0000000..b596754
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/openssl.cnf
@@ -0,0 +1,131 @@
+# OpenSSL root CA configuration file.
+
+[ ca ]
+# `man ca`
+default_ca = Keycloak
+
+[ Keycloak ]
+# Directory and file locations.
+dir = ./
+certs = $dir/certs
+crl_dir = $dir/crl
+new_certs_dir = $dir/newcerts
+database = $dir/index.txt
+serial = $dir/serial
+RANDFILE = $dir/private/.rand
+
+# The root key and root certificate.
+private_key = $dir/private/ca.key.pem
+certificate = $dir/certs/ca.cert.pem
+
+# For certificate revocation lists.
+crlnumber = $dir/crlnumber
+crl = $dir/crl/ca.crl.pem
+crl_extensions = crl_ext
+default_crl_days = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 375
+preserve = no
+policy = policy_strict
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits = 2048
+distinguished_name = req_distinguished_name
+string_mask = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName = Country Name (2 letter code)
+stateOrProvinceName = State or Province Name
+localityName = Locality Name
+0.organizationName = Organization Name
+organizationalUnitName = Organizational Unit Name
+commonName = Common Name
+emailAddress = Email Address
+
+# Optionally, specify some defaults.
+countryName_default = US
+stateOrProvinceName_default = MA
+localityName_default = Boston
+0.organizationName_default = Red Hat
+organizationalUnitName_default = Keycloak
+emailAddress_default = contact@keycloak.org
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/private/ca.key.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/private/ca.key.pem
new file mode 100644
index 0000000..9a51de0
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/private/ca.key.pem
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,0DB2418CD45582213A6DA1664904B74D
+
+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
+-----END RSA PRIVATE KEY-----
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial
new file mode 100644
index 0000000..dd11724
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial
@@ -0,0 +1 @@
+1001
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old
new file mode 100644
index 0000000..83b33d2
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old
@@ -0,0 +1 @@
+1000
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
index d66e09d..8160d26 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
@@ -245,6 +245,13 @@
<include>empty.crl</include>
</includes>
</resource>
+ <resource>
+ <directory>${common.resources}/pki/root/ca</directory>
+ <includes>
+ <include>certs/clients/test-user-san-email@localhost.cert.pem</include>
+ <include>certs/clients/test-user@localhost.key.pem</include>
+ </includes>
+ </resource>
</resources>
</configuration>
</execution>
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/keycloak.js b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/keycloak.js
new file mode 100644
index 0000000..80b4477
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/keycloak.js
@@ -0,0 +1,1416 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function( window, undefined ) {
+
+ var Keycloak = function (config) {
+ if (!(this instanceof Keycloak)) {
+ return new Keycloak(config);
+ }
+
+ var kc = this;
+ var adapter;
+ var refreshQueue = [];
+ var callbackStorage;
+
+ var loginIframe = {
+ enable: true,
+ callbackList: [],
+ interval: 5
+ };
+
+ var scripts = document.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ if ((scripts[i].src.indexOf('keycloak.js') !== -1 || scripts[i].src.indexOf('keycloak.min.js') !== -1) && scripts[i].src.indexOf('version=') !== -1) {
+ kc.iframeVersion = scripts[i].src.substring(scripts[i].src.indexOf('version=') + 8).split('&')[0];
+ }
+ }
+
+ var useNonce = true;
+
+ kc.init = function (initOptions) {
+ kc.authenticated = false;
+
+ callbackStorage = createCallbackStorage();
+
+ if (initOptions && initOptions.adapter === 'cordova') {
+ adapter = loadAdapter('cordova');
+ } else if (initOptions && initOptions.adapter === 'default') {
+ adapter = loadAdapter();
+ } else {
+ if (window.Cordova || window.cordova) {
+ adapter = loadAdapter('cordova');
+ } else {
+ adapter = loadAdapter();
+ }
+ }
+
+ if (initOptions) {
+ if (typeof initOptions.useNonce !== 'undefined') {
+ useNonce = initOptions.useNonce;
+ }
+
+ if (typeof initOptions.checkLoginIframe !== 'undefined') {
+ loginIframe.enable = initOptions.checkLoginIframe;
+ }
+
+ if (initOptions.checkLoginIframeInterval) {
+ loginIframe.interval = initOptions.checkLoginIframeInterval;
+ }
+
+ if (initOptions.onLoad === 'login-required') {
+ kc.loginRequired = true;
+ }
+
+ if (initOptions.responseMode) {
+ if (initOptions.responseMode === 'query' || initOptions.responseMode === 'fragment') {
+ kc.responseMode = initOptions.responseMode;
+ } else {
+ throw 'Invalid value for responseMode';
+ }
+ }
+
+ if (initOptions.flow) {
+ switch (initOptions.flow) {
+ case 'standard':
+ kc.responseType = 'code';
+ break;
+ case 'implicit':
+ kc.responseType = 'id_token token';
+ break;
+ case 'hybrid':
+ kc.responseType = 'code id_token token';
+ break;
+ default:
+ throw 'Invalid value for flow';
+ }
+ kc.flow = initOptions.flow;
+ }
+
+ if (initOptions.timeSkew != null) {
+ kc.timeSkew = initOptions.timeSkew;
+ }
+ }
+
+ if (!kc.responseMode) {
+ kc.responseMode = 'fragment';
+ }
+ if (!kc.responseType) {
+ kc.responseType = 'code';
+ kc.flow = 'standard';
+ }
+
+ var promise = createPromise();
+
+ var initPromise = createPromise();
+ initPromise.promise.success(function() {
+ kc.onReady && kc.onReady(kc.authenticated);
+ promise.setSuccess(kc.authenticated);
+ }).error(function(errorData) {
+ promise.setError(errorData);
+ });
+
+ var configPromise = loadConfig(config);
+
+ function onLoad() {
+ var doLogin = function(prompt) {
+ if (!prompt) {
+ options.prompt = 'none';
+ }
+ kc.login(options).success(function () {
+ initPromise.setSuccess();
+ }).error(function () {
+ initPromise.setError();
+ });
+ }
+
+ var options = {};
+ switch (initOptions.onLoad) {
+ case 'check-sso':
+ if (loginIframe.enable) {
+ setupCheckLoginIframe().success(function() {
+ checkLoginIframe().success(function () {
+ doLogin(false);
+ }).error(function () {
+ initPromise.setSuccess();
+ });
+ });
+ } else {
+ doLogin(false);
+ }
+ break;
+ case 'login-required':
+ doLogin(true);
+ break;
+ default:
+ throw 'Invalid value for onLoad';
+ }
+ }
+
+ function processInit() {
+ var callback = parseCallback(window.location.href);
+
+ if (callback) {
+ window.history.replaceState({}, null, callback.newUrl);
+ }
+
+ if (callback && callback.valid) {
+ return setupCheckLoginIframe().success(function() {
+ processCallback(callback, initPromise);
+ }).error(function (e) {
+ initPromise.setError();
+ });
+ } else if (initOptions) {
+ if (initOptions.token && initOptions.refreshToken) {
+ setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
+
+ if (loginIframe.enable) {
+ setupCheckLoginIframe().success(function() {
+ checkLoginIframe().success(function () {
+ kc.onAuthSuccess && kc.onAuthSuccess();
+ initPromise.setSuccess();
+ }).error(function () {
+ setToken(null, null, null);
+ initPromise.setSuccess();
+ });
+ });
+ } else {
+ kc.updateToken(-1).success(function() {
+ kc.onAuthSuccess && kc.onAuthSuccess();
+ initPromise.setSuccess();
+ }).error(function() {
+ kc.onAuthError && kc.onAuthError();
+ if (initOptions.onLoad) {
+ onLoad();
+ } else {
+ initPromise.setError();
+ }
+ });
+ }
+ } else if (initOptions.onLoad) {
+ onLoad();
+ } else {
+ initPromise.setSuccess();
+ }
+ } else {
+ initPromise.setSuccess();
+ }
+ }
+
+ configPromise.success(processInit);
+ configPromise.error(function() {
+ promise.setError();
+ });
+
+ return promise.promise;
+ }
+
+ kc.login = function (options) {
+ return adapter.login(options);
+ }
+
+ kc.createLoginUrl = function(options) {
+ var state = createUUID();
+ var nonce = createUUID();
+
+ var redirectUri = adapter.redirectUri(options);
+
+ var callbackState = {
+ state: state,
+ nonce: nonce,
+ redirectUri: encodeURIComponent(redirectUri)
+ }
+
+ if (options && options.prompt) {
+ callbackState.prompt = options.prompt;
+ }
+
+ callbackStorage.add(callbackState);
+
+ var baseUrl;
+ if (options && options.action == 'register') {
+ baseUrl = kc.endpoints.register();
+ } else {
+ baseUrl = kc.endpoints.authorize();
+ }
+
+ var scope = (options && options.scope) ? "openid " + options.scope : "openid";
+
+ var url = baseUrl
+ + '?client_id=' + encodeURIComponent(kc.clientId)
+ + '&redirect_uri=' + encodeURIComponent(redirectUri)
+ + '&state=' + encodeURIComponent(state)
+ + '&response_mode=' + encodeURIComponent(kc.responseMode)
+ + '&response_type=' + encodeURIComponent(kc.responseType)
+ + '&scope=' + encodeURIComponent(scope);
+ if (useNonce) {
+ url = url + '&nonce=' + encodeURIComponent(nonce);
+ }
+
+ if (options && options.prompt) {
+ url += '&prompt=' + encodeURIComponent(options.prompt);
+ }
+
+ if (options && options.maxAge) {
+ url += '&max_age=' + encodeURIComponent(options.maxAge);
+ }
+
+ if (options && options.loginHint) {
+ url += '&login_hint=' + encodeURIComponent(options.loginHint);
+ }
+
+ if (options && options.idpHint) {
+ url += '&kc_idp_hint=' + encodeURIComponent(options.idpHint);
+ }
+
+ if (options && options.locale) {
+ url += '&ui_locales=' + encodeURIComponent(options.locale);
+ }
+
+ return url;
+ }
+
+ kc.logout = function(options) {
+ return adapter.logout(options);
+ }
+
+ kc.createLogoutUrl = function(options) {
+ var url = kc.endpoints.logout()
+ + '?redirect_uri=' + encodeURIComponent(adapter.redirectUri(options, false));
+
+ return url;
+ }
+
+ kc.register = function (options) {
+ return adapter.register(options);
+ }
+
+ kc.createRegisterUrl = function(options) {
+ if (!options) {
+ options = {};
+ }
+ options.action = 'register';
+ return kc.createLoginUrl(options);
+ }
+
+ kc.createAccountUrl = function(options) {
+ var realm = getRealmUrl();
+ var url = undefined;
+ if (typeof realm !== 'undefined') {
+ url = realm
+ + '/account'
+ + '?referrer=' + encodeURIComponent(kc.clientId)
+ + '&referrer_uri=' + encodeURIComponent(adapter.redirectUri(options));
+ }
+ return url;
+ }
+
+ kc.accountManagement = function() {
+ return adapter.accountManagement();
+ }
+
+ kc.hasRealmRole = function (role) {
+ var access = kc.realmAccess;
+ return !!access && access.roles.indexOf(role) >= 0;
+ }
+
+ kc.hasResourceRole = function(role, resource) {
+ if (!kc.resourceAccess) {
+ return false;
+ }
+
+ var access = kc.resourceAccess[resource || kc.clientId];
+ return !!access && access.roles.indexOf(role) >= 0;
+ }
+
+ kc.loadUserProfile = function() {
+ var url = getRealmUrl() + '/account';
+ var req = new XMLHttpRequest();
+ req.open('GET', url, true);
+ req.setRequestHeader('Accept', 'application/json');
+ req.setRequestHeader('Authorization', 'bearer ' + kc.token);
+
+ var promise = createPromise();
+
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if (req.status == 200) {
+ kc.profile = JSON.parse(req.responseText);
+ promise.setSuccess(kc.profile);
+ } else {
+ promise.setError();
+ }
+ }
+ }
+
+ req.send();
+
+ return promise.promise;
+ }
+
+ kc.loadUserInfo = function() {
+ var url = kc.endpoints.userinfo();
+ var req = new XMLHttpRequest();
+ req.open('GET', url, true);
+ req.setRequestHeader('Accept', 'application/json');
+ req.setRequestHeader('Authorization', 'bearer ' + kc.token);
+
+ var promise = createPromise();
+
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if (req.status == 200) {
+ kc.userInfo = JSON.parse(req.responseText);
+ promise.setSuccess(kc.userInfo);
+ } else {
+ promise.setError();
+ }
+ }
+ }
+
+ req.send();
+
+ return promise.promise;
+ }
+
+ kc.isTokenExpired = function(minValidity) {
+ if (!kc.tokenParsed || (!kc.refreshToken && kc.flow != 'implicit' )) {
+ throw 'Not authenticated';
+ }
+
+ if (kc.timeSkew == null) {
+ console.info('[KEYCLOAK] Unable to determine if token is expired as timeskew is not set');
+ return true;
+ }
+
+ var expiresIn = kc.tokenParsed['exp'] - Math.ceil(new Date().getTime() / 1000) + kc.timeSkew;
+ if (minValidity) {
+ expiresIn -= minValidity;
+ }
+ return expiresIn < 0;
+ }
+
+ kc.updateToken = function(minValidity) {
+ var promise = createPromise();
+
+ if (!kc.refreshToken) {
+ promise.setError();
+ return promise.promise;
+ }
+
+ minValidity = minValidity || 5;
+
+ var exec = function() {
+ var refreshToken = false;
+ if (minValidity == -1) {
+ refreshToken = true;
+ console.info('[KEYCLOAK] Refreshing token: forced refresh');
+ } else if (!kc.tokenParsed || kc.isTokenExpired(minValidity)) {
+ refreshToken = true;
+ console.info('[KEYCLOAK] Refreshing token: token expired');
+ }
+
+ if (!refreshToken) {
+ promise.setSuccess(false);
+ } else {
+ var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
+ var url = kc.endpoints.token();
+
+ refreshQueue.push(promise);
+
+ if (refreshQueue.length == 1) {
+ var req = new XMLHttpRequest();
+ req.open('POST', url, true);
+ req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+ req.withCredentials = true;
+
+ if (kc.clientId && kc.clientSecret) {
+ req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
+ } else {
+ params += '&client_id=' + encodeURIComponent(kc.clientId);
+ }
+
+ var timeLocal = new Date().getTime();
+
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if (req.status == 200) {
+ console.info('[KEYCLOAK] Token refreshed');
+
+ timeLocal = (timeLocal + new Date().getTime()) / 2;
+
+ var tokenResponse = JSON.parse(req.responseText);
+
+ setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], timeLocal);
+
+ kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
+ for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
+ p.setSuccess(true);
+ }
+ } else {
+ console.warn('[KEYCLOAK] Failed to refresh token');
+
+ kc.onAuthRefreshError && kc.onAuthRefreshError();
+ for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
+ p.setError(true);
+ }
+ }
+ }
+ };
+
+ req.send(params);
+ }
+ }
+ }
+
+ if (loginIframe.enable) {
+ var iframePromise = checkLoginIframe();
+ iframePromise.success(function() {
+ exec();
+ }).error(function() {
+ promise.setError();
+ });
+ } else {
+ exec();
+ }
+
+ return promise.promise;
+ }
+
+ kc.clearToken = function() {
+ if (kc.token) {
+ setToken(null, null, null);
+ kc.onAuthLogout && kc.onAuthLogout();
+ if (kc.loginRequired) {
+ kc.login();
+ }
+ }
+ }
+
+ function getRealmUrl() {
+ if (typeof kc.authServerUrl !== 'undefined') {
+ if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
+ return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
+ } else {
+ return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
+ }
+ } else {
+ return undefined;
+ }
+ }
+
+ function getOrigin() {
+ if (!window.location.origin) {
+ return window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
+ } else {
+ return window.location.origin;
+ }
+ }
+
+ function processCallback(oauth, promise) {
+ var code = oauth.code;
+ var error = oauth.error;
+ var prompt = oauth.prompt;
+
+ var timeLocal = new Date().getTime();
+
+ if (error) {
+ if (prompt != 'none') {
+ var errorData = { error: error, error_description: oauth.error_description };
+ kc.onAuthError && kc.onAuthError(errorData);
+ promise && promise.setError(errorData);
+ } else {
+ promise && promise.setSuccess();
+ }
+ return;
+ } else if ((kc.flow != 'standard') && (oauth.access_token || oauth.id_token)) {
+ authSuccess(oauth.access_token, null, oauth.id_token, true);
+ }
+
+ if ((kc.flow != 'implicit') && code) {
+ var params = 'code=' + code + '&grant_type=authorization_code';
+ var url = kc.endpoints.token();
+
+ var req = new XMLHttpRequest();
+ req.open('POST', url, true);
+ req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+
+ if (kc.clientId && kc.clientSecret) {
+ req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
+ } else {
+ params += '&client_id=' + encodeURIComponent(kc.clientId);
+ }
+
+ params += '&redirect_uri=' + oauth.redirectUri;
+
+ req.withCredentials = true;
+
+ req.onreadystatechange = function() {
+ if (req.readyState == 4) {
+ if (req.status == 200) {
+
+ var tokenResponse = JSON.parse(req.responseText);
+ authSuccess(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], kc.flow === 'standard');
+ } else {
+ kc.onAuthError && kc.onAuthError();
+ promise && promise.setError();
+ }
+ }
+ };
+
+ req.send(params);
+ }
+
+ function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
+ timeLocal = (timeLocal + new Date().getTime()) / 2;
+
+ setToken(accessToken, refreshToken, idToken, timeLocal);
+
+ if (useNonce && ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
+ (kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
+ (kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce))) {
+
+ console.info('[KEYCLOAK] Invalid nonce, clearing token');
+ kc.clearToken();
+ promise && promise.setError();
+ } else {
+ if (fulfillPromise) {
+ kc.onAuthSuccess && kc.onAuthSuccess();
+ promise && promise.setSuccess();
+ }
+ }
+ }
+
+ }
+
+ function loadConfig(url) {
+ var promise = createPromise();
+ var configUrl;
+
+ if (!config) {
+ configUrl = 'keycloak.json';
+ } else if (typeof config === 'string') {
+ configUrl = config;
+ }
+
+ function setupOidcEndoints(oidcConfiguration) {
+ if (! oidcConfiguration) {
+ kc.endpoints = {
+ authorize: function() {
+ return getRealmUrl() + '/protocol/openid-connect/auth';
+ },
+ token: function() {
+ return getRealmUrl() + '/protocol/openid-connect/token';
+ },
+ logout: function() {
+ return getRealmUrl() + '/protocol/openid-connect/logout';
+ },
+ checkSessionIframe: function() {
+ var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
+ if (kc.iframeVersion) {
+ src = src + '?version=' + kc.iframeVersion;
+ }
+ return src;
+ },
+ register: function() {
+ return getRealmUrl() + '/protocol/openid-connect/registrations';
+ },
+ userinfo: function() {
+ return getRealmUrl() + '/protocol/openid-connect/userinfo';
+ }
+ };
+ } else {
+ kc.endpoints = {
+ authorize: function() {
+ return oidcConfiguration.authorization_endpoint;
+ },
+ token: function() {
+ return oidcConfiguration.token_endpoint;
+ },
+ logout: function() {
+ if (!oidcConfiguration.end_session_endpoint) {
+ throw "Not supported by the OIDC server";
+ }
+ return oidcConfiguration.end_session_endpoint;
+ },
+ checkSessionIframe: function() {
+ if (!oidcConfiguration.check_session_iframe) {
+ throw "Not supported by the OIDC server";
+ }
+ return oidcConfiguration.check_session_iframe;
+ },
+ register: function() {
+ throw 'Redirection to "Register user" page not supported in standard OIDC mode';
+ },
+ userinfo: function() {
+ if (!oidcConfiguration.userinfo_endpoint) {
+ throw "Not supported by the OIDC server";
+ }
+ return oidcConfiguration.userinfo_endpoint;
+ }
+ }
+ }
+ }
+
+ if (configUrl) {
+ var req = new XMLHttpRequest();
+ req.open('GET', configUrl, true);
+ req.setRequestHeader('Accept', 'application/json');
+
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if (req.status == 200 || fileLoaded(req)) {
+ var config = JSON.parse(req.responseText);
+
+ kc.authServerUrl = config['auth-server-url'];
+ kc.realm = config['realm'];
+ kc.clientId = config['resource'];
+ kc.clientSecret = (config['credentials'] || {})['secret'];
+ setupOidcEndoints(null);
+ promise.setSuccess();
+ } else {
+ promise.setError();
+ }
+ }
+ };
+
+ req.send();
+ } else {
+ if (!config.clientId) {
+ throw 'clientId missing';
+ }
+
+ kc.clientId = config.clientId;
+ kc.clientSecret = (config.credentials || {}).secret;
+
+ var oidcProvider = config['oidcProvider'];
+ if (!oidcProvider) {
+ if (!config['url']) {
+ var scripts = document.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.match(/.*keycloak\.js/)) {
+ config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
+ break;
+ }
+ }
+ }
+ if (!config.realm) {
+ throw 'realm missing';
+ }
+
+ kc.authServerUrl = config.url;
+ kc.realm = config.realm;
+ setupOidcEndoints(null);
+ promise.setSuccess();
+ } else {
+ if (typeof oidcProvider === 'string') {
+ var oidcProviderConfigUrl;
+ if (oidcProvider.charAt(oidcProvider.length - 1) == '/') {
+ oidcProviderConfigUrl = oidcProvider + '.well-known/openid-configuration';
+ } else {
+ oidcProviderConfigUrl = oidcProvider + '/.well-known/openid-configuration';
+ }
+ var req = new XMLHttpRequest();
+ req.open('GET', oidcProviderConfigUrl, true);
+ req.setRequestHeader('Accept', 'application/json');
+
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if (req.status == 200 || fileLoaded(req)) {
+ var oidcProviderConfig = JSON.parse(req.responseText);
+ setupOidcEndoints(oidcProviderConfig);
+ promise.setSuccess();
+ } else {
+ promise.setError();
+ }
+ }
+ };
+
+ req.send();
+ } else {
+ setupOidcEndoints(oidcProvider);
+ promise.setSuccess();
+ }
+ }
+ }
+
+ return promise.promise;
+ }
+
+ function fileLoaded(xhr) {
+ return xhr.status == 0 && xhr.responseText && xhr.responseURL.startsWith('file:');
+ }
+
+ function setToken(token, refreshToken, idToken, timeLocal) {
+ if (kc.tokenTimeoutHandle) {
+ clearTimeout(kc.tokenTimeoutHandle);
+ kc.tokenTimeoutHandle = null;
+ }
+
+ if (refreshToken) {
+ kc.refreshToken = refreshToken;
+ kc.refreshTokenParsed = decodeToken(refreshToken);
+ } else {
+ delete kc.refreshToken;
+ delete kc.refreshTokenParsed;
+ }
+
+ if (idToken) {
+ kc.idToken = idToken;
+ kc.idTokenParsed = decodeToken(idToken);
+ } else {
+ delete kc.idToken;
+ delete kc.idTokenParsed;
+ }
+
+ if (token) {
+ kc.token = token;
+ kc.tokenParsed = decodeToken(token);
+ kc.sessionId = kc.tokenParsed.session_state;
+ kc.authenticated = true;
+ kc.subject = kc.tokenParsed.sub;
+ kc.realmAccess = kc.tokenParsed.realm_access;
+ kc.resourceAccess = kc.tokenParsed.resource_access;
+
+ if (timeLocal) {
+ kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
+ }
+
+ if (kc.timeSkew != null) {
+ console.info('[KEYCLOAK] Estimated time difference between browser and server is ' + kc.timeSkew + ' seconds');
+
+ if (kc.onTokenExpired) {
+ var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
+ console.info('[KEYCLOAK] Token expires in ' + Math.round(expiresIn / 1000) + ' s');
+ if (expiresIn <= 0) {
+ kc.onTokenExpired();
+ } else {
+ kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
+ }
+ }
+ }
+ } else {
+ delete kc.token;
+ delete kc.tokenParsed;
+ delete kc.subject;
+ delete kc.realmAccess;
+ delete kc.resourceAccess;
+
+ kc.authenticated = false;
+ }
+ }
+
+ function decodeToken(str) {
+ str = str.split('.')[1];
+
+ str = str.replace('/-/g', '+');
+ str = str.replace('/_/g', '/');
+ switch (str.length % 4)
+ {
+ case 0:
+ break;
+ case 2:
+ str += '==';
+ break;
+ case 3:
+ str += '=';
+ break;
+ default:
+ throw 'Invalid token';
+ }
+
+ str = (str + '===').slice(0, str.length + (str.length % 4));
+ str = str.replace(/-/g, '+').replace(/_/g, '/');
+
+ str = decodeURIComponent(escape(atob(str)));
+
+ str = JSON.parse(str);
+ return str;
+ }
+
+ function createUUID() {
+ var s = [];
+ var hexDigits = '0123456789abcdef';
+ for (var i = 0; i < 36; i++) {
+ s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+ }
+ s[14] = '4';
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
+ s[8] = s[13] = s[18] = s[23] = '-';
+ var uuid = s.join('');
+ return uuid;
+ }
+
+ kc.callback_id = 0;
+
+ function createCallbackId() {
+ var id = '<id: ' + (kc.callback_id++) + (Math.random()) + '>';
+ return id;
+
+ }
+
+ function parseCallback(url) {
+ var oauth = parseCallbackUrl(url);
+ if (!oauth) {
+ return;
+ }
+
+ var oauthState = callbackStorage.get(oauth.state);
+
+ if (oauthState) {
+ oauth.valid = true;
+ oauth.redirectUri = oauthState.redirectUri;
+ oauth.storedNonce = oauthState.nonce;
+ oauth.prompt = oauthState.prompt;
+ }
+
+ return oauth;
+ }
+
+ function parseCallbackUrl(url) {
+ var supportedParams;
+ switch (kc.flow) {
+ case 'standard':
+ supportedParams = ['code', 'state', 'session_state'];
+ break;
+ case 'implicit':
+ supportedParams = ['access_token', 'id_token', 'state', 'session_state'];
+ break;
+ case 'hybrid':
+ supportedParams = ['access_token', 'id_token', 'code', 'state', 'session_state'];
+ break;
+ }
+
+ supportedParams.push('error');
+ supportedParams.push('error_description');
+ supportedParams.push('error_uri');
+
+ var queryIndex = url.indexOf('?');
+ var fragmentIndex = url.indexOf('#');
+
+ var newUrl;
+ var parsed;
+
+ if (kc.responseMode === 'query' && queryIndex !== -1) {
+ newUrl = url.substring(0, queryIndex);
+ parsed = parseCallbackParams(url.substring(queryIndex + 1, fragmentIndex !== -1 ? fragmentIndex : url.length), supportedParams);
+ if (parsed.paramsString !== '') {
+ newUrl += '?' + parsed.paramsString;
+ }
+ if (fragmentIndex !== -1) {
+ newUrl += url.substring(fragmentIndex);
+ }
+ } else if (kc.responseMode === 'fragment' && fragmentIndex !== -1) {
+ newUrl = url.substring(0, fragmentIndex);
+ parsed = parseCallbackParams(url.substring(fragmentIndex + 1), supportedParams);
+ if (parsed.paramsString !== '') {
+ newUrl += '#' + parsed.paramsString;
+ }
+ }
+
+ if (parsed && parsed.oauthParams) {
+ if (kc.flow === 'standard' || kc.flow === 'hybrid') {
+ if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {
+ parsed.oauthParams.newUrl = newUrl;
+ return parsed.oauthParams;
+ }
+ } else if (kc.flow === 'implicit') {
+ if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {
+ parsed.oauthParams.newUrl = newUrl;
+ return parsed.oauthParams;
+ }
+ }
+ }
+ }
+
+ function parseCallbackParams(paramsString, supportedParams) {
+ var p = paramsString.split('&');
+ var result = {
+ paramsString: '',
+ oauthParams: {}
+ }
+ for (var i = 0; i < p.length; i++) {
+ var t = p[i].split('=');
+ if (supportedParams.indexOf(t[0]) !== -1) {
+ result.oauthParams[t[0]] = t[1];
+ } else {
+ if (result.paramsString !== '') {
+ result.paramsString += '&';
+ }
+ result.paramsString += p[i];
+ }
+ }
+ return result;
+ }
+
+ function createPromise() {
+ if (typeof Promise === "function") {
+ return createNativePromise();
+ } else {
+ return createLegacyPromise();
+ }
+ }
+
+ function createNativePromise() {
+ // Need to create a native Promise which also preserves the
+ // interface of the custom promise type previously used by the API
+ var p = {
+ setSuccess: function(result) {
+ p.success = true;
+ p.resolve(result);
+ },
+
+ setError: function(result) {
+ p.success = false;
+ p.reject(result);
+ }
+ };
+ p.promise = new Promise(function(resolve, reject) {
+ p.resolve = resolve;
+ p.reject = reject;
+ });
+ p.promise.success = function(callback) {
+ p.promise.then(callback);
+ return p.promise;
+ }
+ p.promise.error = function(callback) {
+ p.promise.catch(callback);
+ return p.promise;
+ }
+ return p;
+ }
+
+ function createLegacyPromise() {
+ var p = {
+ setSuccess: function(result) {
+ p.success = true;
+ p.result = result;
+ if (p.successCallback) {
+ p.successCallback(result);
+ }
+ },
+
+ setError: function(result) {
+ p.error = true;
+ p.result = result;
+ if (p.errorCallback) {
+ p.errorCallback(result);
+ }
+ },
+
+ promise: {
+ success: function(callback) {
+ if (p.success) {
+ callback(p.result);
+ } else if (!p.error) {
+ p.successCallback = callback;
+ }
+ return p.promise;
+ },
+ error: function(callback) {
+ if (p.error) {
+ callback(p.result);
+ } else if (!p.success) {
+ p.errorCallback = callback;
+ }
+ return p.promise;
+ }
+ }
+ }
+ return p;
+ }
+
+ function setupCheckLoginIframe() {
+ var promise = createPromise();
+
+ if (!loginIframe.enable) {
+ promise.setSuccess();
+ return promise.promise;
+ }
+
+ if (loginIframe.iframe) {
+ promise.setSuccess();
+ return promise.promise;
+ }
+
+ var iframe = document.createElement('iframe');
+ loginIframe.iframe = iframe;
+
+ iframe.onload = function() {
+ var authUrl = kc.endpoints.authorize();
+ if (authUrl.charAt(0) === '/') {
+ loginIframe.iframeOrigin = getOrigin();
+ } else {
+ loginIframe.iframeOrigin = authUrl.substring(0, authUrl.indexOf('/', 8));
+ }
+ promise.setSuccess();
+
+ setTimeout(check, loginIframe.interval * 1000);
+ }
+
+ var src = kc.endpoints.checkSessionIframe();
+ iframe.setAttribute('src', src );
+ iframe.setAttribute('title', 'keycloak-session-iframe' );
+ iframe.style.display = 'none';
+ document.body.appendChild(iframe);
+
+ var messageCallback = function(event) {
+ if ((event.origin !== loginIframe.iframeOrigin) || (loginIframe.iframe.contentWindow !== event.source)) {
+ return;
+ }
+
+ if (!(event.data == 'unchanged' || event.data == 'changed' || event.data == 'error')) {
+ return;
+ }
+
+
+ if (event.data != 'unchanged') {
+ kc.clearToken();
+ }
+
+ var callbacks = loginIframe.callbackList.splice(0, loginIframe.callbackList.length);
+
+ for (var i = callbacks.length - 1; i >= 0; --i) {
+ var promise = callbacks[i];
+ if (event.data == 'unchanged') {
+ promise.setSuccess();
+ } else {
+ promise.setError();
+ }
+ }
+ };
+
+ window.addEventListener('message', messageCallback, false);
+
+ var check = function() {
+ checkLoginIframe();
+ if (kc.token) {
+ setTimeout(check, loginIframe.interval * 1000);
+ }
+ };
+
+ return promise.promise;
+ }
+
+ function checkLoginIframe() {
+ var promise = createPromise();
+
+ if (loginIframe.iframe && loginIframe.iframeOrigin ) {
+ var msg = kc.clientId + ' ' + kc.sessionId;
+ loginIframe.callbackList.push(promise);
+ var origin = loginIframe.iframeOrigin;
+ if (loginIframe.callbackList.length == 1) {
+ loginIframe.iframe.contentWindow.postMessage(msg, origin);
+ }
+ } else {
+ promise.setSuccess();
+ }
+
+ return promise.promise;
+ }
+
+ function loadAdapter(type) {
+ if (!type || type == 'default') {
+ return {
+ login: function(options) {
+ window.location.href = kc.createLoginUrl(options);
+ return createPromise().promise;
+ },
+
+ logout: function(options) {
+ window.location.href = kc.createLogoutUrl(options);
+ return createPromise().promise;
+ },
+
+ register: function(options) {
+ window.location.href = kc.createRegisterUrl(options);
+ return createPromise().promise;
+ },
+
+ accountManagement : function() {
+ var accountUrl = kc.createAccountUrl();
+ if (typeof accountUrl !== 'undefined') {
+ window.location.href = accountUrl;
+ } else {
+ throw "Not supported by the OIDC server";
+ }
+ return createPromise().promise;
+ },
+
+ redirectUri: function(options, encodeHash) {
+ if (arguments.length == 1) {
+ encodeHash = true;
+ }
+
+ if (options && options.redirectUri) {
+ return options.redirectUri;
+ } else if (kc.redirectUri) {
+ return kc.redirectUri;
+ } else {
+ return location.href;
+ }
+ }
+ };
+ }
+
+ if (type == 'cordova') {
+ loginIframe.enable = false;
+ var cordovaOpenWindowWrapper = function(loginUrl, target, options) {
+ if (window.cordova && window.cordova.InAppBrowser) {
+ // Use inappbrowser for IOS and Android if available
+ return window.cordova.InAppBrowser.open(loginUrl, target, options);
+ } else {
+ return window.open(loginUrl, target, options);
+ }
+ };
+ return {
+ login: function(options) {
+ var promise = createPromise();
+
+ var o = 'location=no';
+ if (options && options.prompt == 'none') {
+ o += ',hidden=yes';
+ }
+
+ var loginUrl = kc.createLoginUrl(options);
+ var ref = cordovaOpenWindowWrapper(loginUrl, '_blank', o);
+ var completed = false;
+
+ ref.addEventListener('loadstart', function(event) {
+ if (event.url.indexOf('http://localhost') == 0) {
+ var callback = parseCallback(event.url);
+ processCallback(callback, promise);
+ ref.close();
+ completed = true;
+ }
+ });
+
+ ref.addEventListener('loaderror', function(event) {
+ if (!completed) {
+ if (event.url.indexOf('http://localhost') == 0) {
+ var callback = parseCallback(event.url);
+ processCallback(callback, promise);
+ ref.close();
+ completed = true;
+ } else {
+ promise.setError();
+ ref.close();
+ }
+ }
+ });
+
+ return promise.promise;
+ },
+
+ logout: function(options) {
+ var promise = createPromise();
+
+ var logoutUrl = kc.createLogoutUrl(options);
+ var ref = cordovaOpenWindowWrapper(logoutUrl, '_blank', 'location=no,hidden=yes');
+
+ var error;
+
+ ref.addEventListener('loadstart', function(event) {
+ if (event.url.indexOf('http://localhost') == 0) {
+ ref.close();
+ }
+ });
+
+ ref.addEventListener('loaderror', function(event) {
+ if (event.url.indexOf('http://localhost') == 0) {
+ ref.close();
+ } else {
+ error = true;
+ ref.close();
+ }
+ });
+
+ ref.addEventListener('exit', function(event) {
+ if (error) {
+ promise.setError();
+ } else {
+ kc.clearToken();
+ promise.setSuccess();
+ }
+ });
+
+ return promise.promise;
+ },
+
+ register : function() {
+ var registerUrl = kc.createRegisterUrl();
+ var ref = cordovaOpenWindowWrapper(registerUrl, '_blank', 'location=no');
+ ref.addEventListener('loadstart', function(event) {
+ if (event.url.indexOf('http://localhost') == 0) {
+ ref.close();
+ }
+ });
+ },
+
+ accountManagement : function() {
+ var accountUrl = kc.createAccountUrl();
+ if (typeof accountUrl !== 'undefined') {
+ var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
+ ref.addEventListener('loadstart', function(event) {
+ if (event.url.indexOf('http://localhost') == 0) {
+ ref.close();
+ }
+ });
+ } else {
+ throw "Not supported by the OIDC server";
+ }
+ },
+
+ redirectUri: function(options) {
+ return 'http://localhost';
+ }
+ }
+ }
+
+ throw 'invalid adapter type: ' + type;
+ }
+
+ var LocalStorage = function() {
+ if (!(this instanceof LocalStorage)) {
+ return new LocalStorage();
+ }
+
+ localStorage.setItem('kc-test', 'test');
+ localStorage.removeItem('kc-test');
+
+ var cs = this;
+
+ function clearExpired() {
+ var time = new Date().getTime();
+ for (var i = 0; i < localStorage.length; i++) {
+ var key = localStorage.key(i);
+ if (key && key.indexOf('kc-callback-') == 0) {
+ var value = localStorage.getItem(key);
+ if (value) {
+ try {
+ var expires = JSON.parse(value).expires;
+ if (!expires || expires < time) {
+ localStorage.removeItem(key);
+ }
+ } catch (err) {
+ localStorage.removeItem(key);
+ }
+ }
+ }
+ }
+ }
+
+ cs.get = function(state) {
+ if (!state) {
+ return;
+ }
+
+ var key = 'kc-callback-' + state;
+ var value = localStorage.getItem(key);
+ if (value) {
+ localStorage.removeItem(key);
+ value = JSON.parse(value);
+ }
+
+ clearExpired();
+ return value;
+ };
+
+ cs.add = function(state) {
+ clearExpired();
+
+ var key = 'kc-callback-' + state.state;
+ state.expires = new Date().getTime() + (60 * 60 * 1000);
+ localStorage.setItem(key, JSON.stringify(state));
+ };
+ };
+
+ var CookieStorage = function() {
+ if (!(this instanceof CookieStorage)) {
+ return new CookieStorage();
+ }
+
+ var cs = this;
+
+ cs.get = function(state) {
+ if (!state) {
+ return;
+ }
+
+ var value = getCookie('kc-callback-' + state);
+ setCookie('kc-callback-' + state, '', cookieExpiration(-100));
+ if (value) {
+ return JSON.parse(value);
+ }
+ };
+
+ cs.add = function(state) {
+ setCookie('kc-callback-' + state.state, JSON.stringify(state), cookieExpiration(60));
+ };
+
+ cs.removeItem = function(key) {
+ setCookie(key, '', cookieExpiration(-100));
+ };
+
+ var cookieExpiration = function (minutes) {
+ var exp = new Date();
+ exp.setTime(exp.getTime() + (minutes*60*1000));
+ return exp;
+ };
+
+ var getCookie = function (key) {
+ var name = key + '=';
+ var ca = document.cookie.split(';');
+ for (var i = 0; i < ca.length; i++) {
+ var c = ca[i];
+ while (c.charAt(0) == ' ') {
+ c = c.substring(1);
+ }
+ if (c.indexOf(name) == 0) {
+ return c.substring(name.length, c.length);
+ }
+ }
+ return '';
+ };
+
+ var setCookie = function (key, value, expirationDate) {
+ var cookie = key + '=' + value + '; '
+ + 'expires=' + expirationDate.toUTCString() + '; ';
+ document.cookie = cookie;
+ }
+ };
+
+ function createCallbackStorage() {
+ try {
+ return new LocalStorage();
+ } catch (err) {
+ }
+
+ return new CookieStorage();
+ }
+ }
+
+ if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+ module.exports = Keycloak;
+ } else {
+ window.Keycloak = Keycloak;
+
+ if ( typeof define === "function" && define.amd ) {
+ define( "keycloak", [], function () { return Keycloak; } );
+ }
+ }
+})( window );
diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/common/cache-authorization.xsl b/testsuite/integration-arquillian/servers/cache-server/jboss/common/cache-authorization.xsl
new file mode 100644
index 0000000..26ce283
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/common/cache-authorization.xsl
@@ -0,0 +1,90 @@
+<!--
+ ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+ ~ and other contributors as indicated by the @author tags.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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 #all">
+
+ <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="nsCacheServer" select="'urn:infinispan:server:core:'"/>
+ <xsl:variable name="nsDomain" select="'urn:jboss:domain:'"/>
+ <xsl:variable name="nsEndpoint" select="'urn:infinispan:server:endpoint:'"/>
+
+ <!-- Configuration of infinispan caches in infinispan-subsystem -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsCacheServer)]
+ /*[local-name()='cache-container' and starts-with(namespace-uri(), $nsCacheServer) and @name='clustered']">
+ <xsl:copy>
+ <xsl:apply-templates select="@*" />
+
+ <security>
+ <authorization>
+ <identity-role-mapper/>
+ <role name="___script_manager" permissions="ALL"/>
+ </authorization>
+ </security>
+
+ <xsl:apply-templates select="node()" />
+
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Add "authentication" into HotRod connector configuration -->
+ <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsEndpoint)]
+ /*[local-name()='hotrod-connector' and starts-with(namespace-uri(), $nsEndpoint) and @cache-container='clustered']">
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()" />
+
+ <authentication security-realm="AllowScriptManager">
+ <sasl mechanisms="DIGEST-MD5" qop="auth" server-name="keycloak-jdg-server">
+ <policy>
+ <no-anonymous value="false" />
+ </policy>
+ </sasl>
+ </authentication>
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Add "AllowScriptManager" security-realm -->
+ <xsl:template match="//*[local-name()='management' and starts-with(namespace-uri(), $nsDomain)]
+ /*[local-name()='security-realms' and starts-with(namespace-uri(), $nsDomain)]">
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()" />
+
+ <xsl:element name="security-realm" namespace="{namespace-uri()}">
+ <xsl:attribute name="name">AllowScriptManager</xsl:attribute>
+ <xsl:element name="authentication" namespace="{namespace-uri()}">
+ <xsl:element name="users" namespace="{namespace-uri()}">
+ <xsl:element name="user" namespace="{namespace-uri()}">
+ <xsl:attribute name="username">___script_manager</xsl:attribute>
+ <xsl:element name="password" namespace="{namespace-uri()}">not-so-secret-password</xsl:element>
+ </xsl:element>
+ </xsl:element>
+ </xsl:element>
+ </xsl:element>
+ </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/cache-server/jboss/infinispan/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml
index a060fdd..82dbb2d 100644
--- a/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/infinispan/pom.xml
@@ -34,10 +34,11 @@
<cache.server.container>cache-server-${cache.server}</cache.server.container>
<cache.server.home>${containers.home}/${cache.server.container}</cache.server.home>
+ <cache.server.jboss.cache-authorization-disabled>true</cache.server.jboss.cache-authorization-disabled>
<cache.server.jboss.groupId>org.infinispan.server</cache.server.jboss.groupId>
<cache.server.jboss.artifactId>infinispan-server</cache.server.jboss.artifactId>
<cache.server.jboss.version>${infinispan.version}</cache.server.jboss.version>
- <cache.server.jboss.unpacked.folder.name>${cache.server.jboss.artifactId}-${infinispan.version}</cache.server.jboss.unpacked.folder.name>
+ <cache.server.jboss.unpacked.folder.name>${cache.server.jboss.artifactId}-${cache.server.jboss.version}</cache.server.jboss.unpacked.folder.name>
<cache.server.worker.io-threads>${cache.default.worker.io-threads}</cache.server.worker.io-threads>
<cache.server.worker.task-max-threads>${cache.default.worker.task-max-threads}</cache.server.worker.task-max-threads>
diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml
index f9780b7..16cfcbf 100644
--- a/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/jdg/pom.xml
@@ -34,6 +34,7 @@
<cache.server.container>cache-server-${cache.server}</cache.server.container>
<cache.server.home>${containers.home}/${cache.server.container}</cache.server.home>
+ <cache.server.jboss.cache-authorization-disabled>false</cache.server.jboss.cache-authorization-disabled>
<cache.server.jboss.groupId>org.infinispan.server</cache.server.jboss.groupId>
<cache.server.jboss.artifactId>infinispan-server</cache.server.jboss.artifactId>
<cache.server.jboss.version>${jdg.version}</cache.server.jboss.version>
diff --git a/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml
index 96c80d1..2e9e1fc 100644
--- a/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/cache-server/jboss/pom.xml
@@ -33,6 +33,7 @@
<common.resources>${project.parent.basedir}/common</common.resources>
<assembly.xml>${project.parent.basedir}/assembly.xml</assembly.xml>
<cache.server.jboss.home>${containers.home}/${cache.server.jboss.unpacked.folder.name}</cache.server.jboss.home>
+ <cache.server.jboss.cache-authorization-disabled>true</cache.server.jboss.cache-authorization-disabled>
<security.xslt>security.xsl</security.xslt>
</properties>
@@ -59,6 +60,7 @@
<rules>
<requireProperty>
<property>cache.server</property>
+ <property>cache.server.jboss.cache-authorization-enabled</property>
<property>cache.server.jboss.groupId</property>
<property>cache.server.jboss.artifactId</property>
<property>cache.server.jboss.version</property>
@@ -165,6 +167,29 @@
</execution>
<execution>
+ <id>configure-keycloak-authorization</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>transform</goal>
+ </goals>
+ <configuration>
+ <skip>${cache.server.jboss.cache-authorization-disabled}</skip>
+ <transformationSets>
+ <!-- Configure authorization in files clustered-__dc__.xml -->
+ <transformationSet>
+ <dir>${cache.server.jboss.home}/standalone/configuration</dir>
+ <includes>
+ <include>clustered-1.xml</include>
+ <include>clustered-2.xml</include>
+ </includes>
+ <stylesheet>${common.resources}/cache-authorization.xsl</stylesheet>
+ <outputDir>${cache.server.jboss.home}/standalone/configuration</outputDir>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </execution>
+
+ <execution>
<id>io-worker-threads</id>
<phase>process-resources</phase>
<goals>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
index 692e05d..a66fcdc 100755
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
@@ -31,6 +31,7 @@
<div id="content" ng-view/>
</div>
+<div style="display: none;" id="bearer"></div>
<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
</body>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
index 3d2ed43..f6df2cb 100755
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
@@ -166,8 +166,10 @@ module.factory('authInterceptor', function ($q, $injector, $timeout, Identity) {
if (Identity.authorization && Identity.authorization.rpt && request.url.indexOf('/authorize') == -1) {
retries = 0;
request.headers.Authorization = 'Bearer ' + Identity.authorization.rpt;
+ document.getElementById("bearer").innerHTML = 'rpt: Bearer ' + Identity.authorization.rpt;
} else {
request.headers.Authorization = 'Bearer ' + Identity.authc.token;
+ document.getElementById("bearer").innerHTML = 'authc: Bearer ' + Identity.authc.token;
}
return request;
},
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
index 9070416..94feb72 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
@@ -3,19 +3,14 @@ package org.keycloak.example.photoz.album;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.ClientAuthorizationContext;
-import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
import org.keycloak.authorization.client.representation.ScopeRepresentation;
import org.keycloak.authorization.client.resource.ProtectionResource;
-import org.keycloak.example.photoz.ErrorResponse;
import org.keycloak.example.photoz.entity.Album;
import org.keycloak.example.photoz.util.Transaction;
-import org.keycloak.representations.adapters.config.AdapterConfig;
-import org.keycloak.util.JsonSerialization;
import javax.inject.Inject;
import javax.persistence.EntityManager;
-import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -28,16 +23,16 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
-import java.security.Principal;
import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+import javax.ws.rs.core.HttpHeaders;
+import org.jboss.logging.Logger;
@Path("/album")
@Transaction
public class AlbumService {
- private static volatile long nextId = 0;
+ private final Logger log = Logger.getLogger(AlbumService.class);
public static final String SCOPE_ALBUM_VIEW = "album:view";
public static final String SCOPE_ALBUM_DELETE = "album:delete";
@@ -50,33 +45,35 @@ public class AlbumService {
@POST
@Consumes("application/json")
- public Response create(Album newAlbum, @QueryParam("user") String username) {
- newAlbum.setId(++nextId);
-
- if (username == null) {
- username = request.getUserPrincipal().getName();
+ public Response create(Album newAlbum, @QueryParam("user") String invalidUser, @Context HttpHeaders headers) {
+ printAuthHeaders(headers);
+
+ String userId = request.getUserPrincipal().getName();
+
+ if (invalidUser != null) {
+ userId = invalidUser;
}
+
+ newAlbum.setUserId(userId);
- newAlbum.setUserId(username);
- Query queryDuplicatedAlbum = this.entityManager.createQuery("from Album where name = :name and userId = :userId");
-
- queryDuplicatedAlbum.setParameter("name", newAlbum.getName());
- queryDuplicatedAlbum.setParameter("userId", username);
-
- if (!queryDuplicatedAlbum.getResultList().isEmpty()) {
- throw new ErrorResponse("Name [" + newAlbum.getName() + "] already taken. Choose another one.", Status.CONFLICT);
+ log.debug("PERSISTING " + newAlbum);
+ entityManager.persist(newAlbum);
+ try {
+ createProtectedResource(newAlbum);
+ } catch (RuntimeException e) {
+ log.debug("ERROR " + e);
+ entityManager.remove(newAlbum);
+ throw e;
}
- this.entityManager.persist(newAlbum);
-
- createProtectedResource(newAlbum);
-
return Response.ok(newAlbum).build();
}
@Path("{id}")
@DELETE
- public Response delete(@PathParam("id") String id) {
+ public Response delete(@PathParam("id") String id, @Context HttpHeaders headers) {
+ printAuthHeaders(headers);
+
Album album = this.entityManager.find(Album.class, Long.valueOf(id));
try {
@@ -113,6 +110,7 @@ public class AlbumService {
}
private void createProtectedResource(Album album) {
+ log.debug("Creating ProtectedResource for " + album);
try {
HashSet<ScopeRepresentation> scopes = new HashSet<>();
@@ -145,7 +143,7 @@ public class AlbumService {
}
protection.resource().delete(search.get(0).getId());
- } catch (Exception e) {
+ } catch (RuntimeException e) {
throw new RuntimeException("Could not search protected resource.", e);
}
}
@@ -161,4 +159,11 @@ public class AlbumService {
private KeycloakSecurityContext getKeycloakSecurityContext() {
return KeycloakSecurityContext.class.cast(request.getAttribute(KeycloakSecurityContext.class.getName()));
}
+
+ private void printAuthHeaders(HttpHeaders headers) {
+ log.debug("-----------------Authorization headers--------------------------");
+ for (String authHeader : headers.getRequestHeader(HttpHeaders.AUTHORIZATION)) {
+ log.debug(authHeader);
+ }
+ }
}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
index f887e2a..6eadcbf 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
@@ -17,24 +17,30 @@
*/
package org.keycloak.example.photoz.entity;
+import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
-import javax.persistence.GenerationType;
import javax.persistence.Transient;
import java.util.ArrayList;
import java.util.List;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@Entity
-public class Album {
+@Table(uniqueConstraints = {
+ @UniqueConstraint(columnNames = {"name", "userId"})
+})
+public class Album implements Serializable {
@Id
+ @GeneratedValue
private Long id;
@Column(nullable = false)
@@ -88,4 +94,9 @@ public class Album {
public void setUserManaged(boolean userManaged) {
this.userManaged = userManaged;
}
+
+ @Override
+ public String toString() {
+ return "Album{" + "id=" + id + ", name=" + name + ", userId=" + userId + '}';
+ }
}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
index 08b7495..1161807 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
@@ -17,6 +17,7 @@
*/
package org.keycloak.example.photoz.entity;
+import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -30,7 +31,7 @@ import javax.persistence.ManyToOne;
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@Entity
-public class Photo {
+public class Photo implements Serializable {
@Id
@GeneratedValue
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
index 36d35f3..be60248 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java
@@ -35,7 +35,7 @@ public class TransactionInterceptor {
private Instance<EntityManager> entityManager;
@AroundInvoke
- public Object aroundInvoke(InvocationContext context) {
+ public Object aroundInvoke(InvocationContext context) throws Exception {
EntityManager entityManager = this.entityManager.get();
EntityTransaction transaction = entityManager.getTransaction();
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
index 8b6d226..369d821 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
@@ -15,8 +15,8 @@
<property name="hibernate.connection.driver_class" value="org.h2.Driver" />
<property name="hibernate.connection.url" value="jdbc:h2:mem:test-keycloak-photoz-example" />
<property name="hibernate.connection.user" value="sa" />
- <property name="hibernate.flushMode" value="FLUSH_AUTO" />
- <property name="hibernate.hbm2ddl.auto" value="update" />
+ <property name="hibernate.flushMode" value="COMMIT" />
+ <property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
index 34cf6bd..508bc72 100644
--- a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
@@ -1,41 +1,47 @@
<?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">
+ 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>photoz-restful-api</module-name>
+ <module-name>photoz-restful-api</module-name>
- <security-constraint>
- <web-resource-collection>
- <web-resource-name>All Resources</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>All Resources</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>All Resources</web-resource-name>
- <url-pattern>/*</url-pattern>
- </web-resource-collection>
- <auth-constraint>
- <role-name>admin</role-name>
- </auth-constraint>
- </security-constraint>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>All Resources</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>admin</role-name>
+ </auth-constraint>
+ </security-constraint>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Unsecured</web-resource-name>
+ <url-pattern>/unsecured/*</url-pattern>
+ </web-resource-collection>
+ </security-constraint>
- <login-config>
- <auth-method>KEYCLOAK</auth-method>
- <realm-name>photoz</realm-name>
- </login-config>
+ <login-config>
+ <auth-method>KEYCLOAK</auth-method>
+ <realm-name>photoz</realm-name>
+ </login-config>
- <security-role>
- <role-name>admin</role-name>
- </security-role>
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
- <security-role>
- <role-name>user</role-name>
- </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
</web-app>
diff --git a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json
index 073dd80..bad1b25 100644
--- a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json
+++ b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json
@@ -107,6 +107,14 @@
{
"name": "Pattern 12",
"uri": "/realm_uri"
+ },
+ {
+ "name": "Pattern 13",
+ "uri": "/keycloak-6623/*"
+ },
+ {
+ "name": "Pattern 14",
+ "uri": "/keycloak-6623/sub-resource/*"
}
],
"policies": [
@@ -258,6 +266,26 @@
"resources": "[\"Pattern 12\"]",
"applyPolicies": "[\"Default Policy\"]"
}
+ },
+ {
+ "name": "Pattern 13 Permission",
+ "type": "resource",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "resources": "[\"Pattern 13\"]",
+ "applyPolicies": "[\"Default Policy\"]"
+ }
+ },
+ {
+ "name": "Pattern 14 Permission",
+ "type": "resource",
+ "logic": "POSITIVE",
+ "decisionStrategy": "UNANIMOUS",
+ "config": {
+ "resources": "[\"Pattern 14\"]",
+ "applyPolicies": "[\"Default Policy\"]"
+ }
}
],
"scopes": []
diff --git a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json
index 1dfcd7b..0dd6a14 100644
--- a/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json
+++ b/testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/src/main/webapp/WEB-INF/keycloak.json
@@ -60,6 +60,14 @@
{
"name": "Pattern 12",
"path": "/keycloak_json_uri"
+ },
+ {
+ "name": "Pattern 14",
+ "path": "/keycloak-6623/sub-resource/*"
+ },
+ {
+ "name": "Pattern 13",
+ "path": "/keycloak-6623/*"
}
]
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
index 1f61268..f87d481 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
@@ -27,10 +27,11 @@ import org.keycloak.testsuite.util.URLUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
-import org.openqa.selenium.support.ui.Select;
import java.net.URL;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
@@ -82,12 +83,26 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
}
public void createAlbum(String name, String buttonId) {
+ log.debugf("Creating album {0} with buttonId: {1}", name, buttonId);
navigateTo();
- this.driver.findElement(By.id("create-album")).click();
- Form.setInputValue(this.driver.findElement(By.id("album.name")), name);
+ WebElement createAlbum = driver.findElement(By.id("create-album"));
+ waitUntilElement(createAlbum).is().clickable();
+ createAlbum.click();
+ WebElement albumNameInput = driver.findElement(By.id("album.name"));
+ waitUntilElement(albumNameInput).is().present();
+ Form.setInputValue(albumNameInput, name);
pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
- this.driver.findElement(By.id(buttonId)).click();
+ waitUntilElement(albumNameInput).attribute(Form.VALUE).contains(name);
+ WebElement button = driver.findElement(By.id(buttonId));
+ waitUntilElement(button).is().clickable();
+ button.click();
pause(WAIT_AFTER_OPERATION);
+ if (buttonId.equals("save-album-invalid")) {
+ waitForPageToLoad();
+ assertThat(driver.getPageSource(), containsString("Could not register protected resource."));
+ } else {
+ waitUntilElement(albumNameInput).is().not().present();
+ }
}
public void createAlbumWithInvalidUser(String name) {
@@ -99,32 +114,51 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
return this.url;
}
- public void deleteAlbum(String name) {
- driver.findElements(By.xpath("//a[text()='" + name + "']/following-sibling::a[text()='X']")).forEach(WebElement::click);
+ public void deleteAlbum(String name, boolean shouldBeDenied) {
+ log.debugf("Deleting album {0}", name);
+ WebElement delete = driver.findElement(By.id("delete-" + name));
+ waitUntilElement(delete).is().clickable();
+ delete.click();
pause(WAIT_AFTER_OPERATION);
+ if (shouldBeDenied) {
+ waitForDenial();
+ } else {
+ waitUntilElement(delete).is().not().present();
+ }
}
- public void navigateToAdminAlbum() {
+ public void navigateToAdminAlbum(boolean shouldBeDenied) {
+ log.debug("Navigating to Admin Album");
URLUtils.navigateToUri(toString() + "/#/admin/album", true);
+
driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
waitForPageToLoad();
pause(WAIT_AFTER_OPERATION);
+ if (shouldBeDenied) {
+ waitForDenial();
+ } else {
+ waitUntilElement(output).text().equalTo("");
+ }
}
public void logOut() {
- waitUntilElement(signOutButton); // Sometimes doesn't work in PhantomJS!
+ waitUntilElement(signOutButton).is().clickable(); // Sometimes doesn't work in PhantomJS!
signOutButton.click();
pause(WAIT_AFTER_OPERATION);
}
public void requestEntitlement() {
+ waitUntilElement(entitlement).is().clickable();
entitlement.click();
+ waitForPageToLoad();
pause(WAIT_AFTER_OPERATION);
pause(WAIT_AFTER_OPERATION);
}
public void requestEntitlements() {
+ waitUntilElement(entitlements).is().clickable();
entitlements.click();
+ waitForPageToLoad();
pause(WAIT_AFTER_OPERATION);
pause(WAIT_AFTER_OPERATION);
}
@@ -168,7 +202,8 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
}
this.loginPage.form().login(username, password);
-
+ waitForPageToLoad();//guess
+
// simple check if we are at the consent page, if so just click 'Yes'
if (this.consentPage.isCurrent()) {
consentPage.confirm();
@@ -177,12 +212,8 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
pause(WAIT_AFTER_OPERATION);
}
- public boolean wasDenied() {
- return this.driver.findElement(By.id("output")).getText().contains("You can not access");
- }
-
- public void viewAlbum(String name) throws InterruptedException {
- viewAlbum(name, true);
+ private void waitForDenial() {
+ waitUntilElement(output).text().contains("You can not access");
}
public void viewAllAlbums() {
@@ -190,83 +221,130 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
pause(WAIT_AFTER_OPERATION);
}
- public void viewAlbum(String name, boolean refresh) throws InterruptedException {
- this.driver.findElement(By.xpath("//a[text() = '" + name + "']")).click();
+ public void viewAlbum(String name, boolean shouldBeDenied) {
+ WebElement viewalbum = driver.findElement(By.xpath("//a[text() = '" + name + "']"));
+ waitUntilElement(viewalbum).is().clickable();
+ viewalbum.click();
+ waitForPageToLoad();
+ if (shouldBeDenied) waitForDenial();
+ driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
waitForPageToLoad();
- if (refresh) {
- driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
- }
pause(WAIT_AFTER_OPERATION);
}
- public void accountPage() throws InterruptedException {
+ public void accountPage() {
navigateTo();
- this.driver.findElement(By.id("my-account")).click();
+ WebElement myAccount = driver.findElement(By.id("my-account"));
+ waitUntilElement(myAccount).is().clickable();
+ myAccount.click();
+ waitForPageToLoad();
pause(WAIT_AFTER_OPERATION);
}
- public void accountMyResources() throws InterruptedException {
+ public void accountMyResources() {
accountPage();
- this.driver.findElement(By.xpath("//a[text() = 'My Resources']")).click();
+ WebElement myResources = driver.findElement(By.xpath("//a[text() = 'My Resources']"));
+ waitUntilElement(myResources).is().clickable();
+ myResources.click();
waitForPageToLoad();
pause(WAIT_AFTER_OPERATION);
}
- public void accountMyResource(String name) throws InterruptedException {
+ public void accountMyResource(String name) {
accountMyResources();
- this.driver.findElement(By.id("detail-" + name)).click();
+ WebElement myResource = driver.findElement(By.id("detail-" + name));
+ waitUntilElement(myResource).is().clickable();
+ myResource.click();
waitForPageToLoad();
pause(WAIT_AFTER_OPERATION);
}
- public void accountGrantResource(String name, String requester) throws InterruptedException {
+ public void accountGrantResource(String name, String requester) {
accountMyResources();
- this.driver.findElement(By.id("grant-" + name + "-" + requester)).click();
+ WebElement grantResource = driver.findElement(By.id("grant-" + name + "-" + requester));
+ waitUntilElement(grantResource).is().clickable();
+ grantResource.click();
waitForPageToLoad();
+ pause(WAIT_AFTER_OPERATION);
}
- public void accountGrantRemoveScope(String name, String requester, String scope) throws InterruptedException {
+ public void accountGrantRemoveScope(String name, String requester, String scope) {
accountMyResources();
- this.driver.findElement(By.id("grant-remove-scope-" + name + "-" + requester + "-" + scope)).click();
+ WebElement grantRemoveScope = driver.findElement(By.id("grant-remove-scope-" + name + "-" + requester + "-" + scope));
+ waitUntilElement(grantRemoveScope).is().clickable();
+ grantRemoveScope.click();
waitForPageToLoad();
+ pause(WAIT_AFTER_OPERATION);
}
- public void accountRevokeResource(String name, String requester) throws InterruptedException {
+ public void accountRevokeResource(String name, String requester) {
accountMyResource(name);
- this.driver.findElement(By.id("revoke-" + name + "-" + requester)).click();
+ WebElement revokeResource = driver.findElement(By.id("revoke-" + name + "-" + requester));
+ waitUntilElement(revokeResource).is().clickable();
+ revokeResource.click();
waitForPageToLoad();
+ pause(WAIT_AFTER_OPERATION);
}
- public void accountShareResource(String name, String user) throws InterruptedException {
+ public void accountShareResource(String name, String user) {
accountMyResource(name);
- this.driver.findElement(By.id("user_id")).sendKeys(user);
- this.driver.findElement(By.id("share-button")).click();
+ WebElement userIdInput = driver.findElement(By.id("user_id"));
+ Form.setInputValue(userIdInput, user);
+ pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
+ waitUntilElement(userIdInput).attribute(Form.VALUE).contains(user);
+
+ WebElement shareButton = driver.findElement(By.id("share-button"));
+ waitUntilElement(shareButton).is().clickable();
+ shareButton.click();
waitForPageToLoad();
+ pause(WAIT_AFTER_OPERATION);
}
- public void accountShareRemoveScope(String name, String user, String scope) throws InterruptedException {
+ public void accountShareRemoveScope(String name, String user, String scope) {
accountMyResource(name);
- this.driver.findElement(By.id("user_id")).sendKeys(user);
- this.driver.findElement(By.id("share-remove-scope-" + name + "-" + scope)).click();
- this.driver.findElement(By.id("share-button")).click();
+
+ WebElement userIdInput = driver.findElement(By.id("user_id"));
+ Form.setInputValue(userIdInput, user);
+ pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
+ waitUntilElement(userIdInput).attribute(Form.VALUE).contains(user);
+
+ WebElement shareRemoveScope = driver.findElement(By.id("share-remove-scope-" + name + "-" + scope));
+ waitUntilElement(shareRemoveScope).is().clickable();
+ shareRemoveScope.click();
waitForPageToLoad();
+
+ WebElement shareButton = driver.findElement(By.id("share-button"));
+ waitUntilElement(shareButton).is().clickable();
+ shareButton.click();
+
+ waitForPageToLoad();
+ pause(WAIT_AFTER_OPERATION);
}
- public void accountDenyResource(String name) throws InterruptedException {
+ public void accountDenyResource(String name) {
accountMyResource(name);
- this.driver.findElement(By.xpath("//a[text() = 'Deny']")).click();
+ WebElement denyLink = driver.findElement(By.linkText("Deny"));
+ waitUntilElement(denyLink).is().clickable();
+ denyLink.click();
waitForPageToLoad();
+ pause(WAIT_AFTER_OPERATION);
}
- public void requestResourceProtectedAnyScope() throws InterruptedException {
+ public void requestResourceProtectedAnyScope(boolean shouldBeDenied) {
navigateTo();
- this.driver.findElement(By.id("requestPathWithAnyProtectedScope")).click();
+ WebElement requestPathWithAnyProtectedScope = driver.findElement(By.id("requestPathWithAnyProtectedScope"));
+ waitUntilElement(requestPathWithAnyProtectedScope).is().clickable();
+ requestPathWithAnyProtectedScope.click();
+ if (shouldBeDenied) waitForDenial();
pause(WAIT_AFTER_OPERATION);
}
- public void requestResourceProtectedAllScope() throws InterruptedException {
+ public void requestResourceProtectedAllScope(boolean shouldBeDenied) {
navigateTo();
- this.driver.findElement(By.id("requestPathWithAllProtectedScope")).click();
+ WebElement requestPathWithAllProtectedScope = driver.findElement(By.id("requestPathWithAllProtectedScope"));
+ waitUntilElement(requestPathWithAllProtectedScope).is().clickable();
+ requestPathWithAllProtectedScope.click();
+ if (shouldBeDenied) waitForDenial();
pause(WAIT_AFTER_OPERATION);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java
index f2f5528..fb0aa3d 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/drone/KeycloakWebDriverConfigurator.java
@@ -17,7 +17,10 @@
package org.keycloak.testsuite.drone;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
@@ -25,9 +28,11 @@ import org.jboss.arquillian.drone.spi.Configurator;
import org.jboss.arquillian.drone.spi.DronePoint;
import org.jboss.arquillian.drone.webdriver.configuration.WebDriverConfiguration;
import org.jboss.arquillian.drone.webdriver.factory.BrowserCapabilitiesList;
+import org.jboss.arquillian.drone.webdriver.factory.BrowserCapabilitiesList.PhantomJS;
import org.jboss.arquillian.drone.webdriver.factory.WebDriverFactory;
import org.jboss.logging.Logger;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.phantomjs.PhantomJSDriverService;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -47,11 +52,36 @@ public class KeycloakWebDriverConfigurator extends WebDriverFactory implements C
if (webDriverCfg.getBrowser().equals("htmlUnit")) {
updateCapabilities(webDriverCfg);
+ } else if (webDriverCfg.getBrowser().equals("phantomjs")) {
+ configurePhantomJSDriver(webDriverCfg);
}
return webDriverCfg;
}
+ private void configurePhantomJSDriver(WebDriverConfiguration webDriverCfg) {
+ webDriverCfg.setBrowserInternal(new PhantomJS() {
+ @Override
+ public Map<String, ?> getRawCapabilities() {
+ List<String> cliArgs = new ArrayList<>();
+ String cliArgsProperty = System.getProperty("keycloak.phantomjs.cli.args");
+
+ if (cliArgsProperty != null) {
+ cliArgs = Arrays.asList(cliArgsProperty.split(" "));
+ } else {
+ cliArgs.add("--ignore-ssl-errors=true");
+ cliArgs.add("--web-security=false");
+ }
+
+ Map<String, Object> mergedCapabilities = new HashMap<>(super.getRawCapabilities());
+
+ mergedCapabilities.put(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cliArgs.toArray(new String[cliArgs.size()]));
+
+ return mergedCapabilities;
+ }
+ });
+ }
+
// This is to ensure that default value of capabilities like "version" will be used just for the HtmlUnitDriver, but not for other drivers.
// Hence in configs we have "htmlUnit.version" instead of "version"
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java
index bb6f4ea..5a9ea86 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/social/MicrosoftLoginPage.java
@@ -17,6 +17,7 @@
package org.keycloak.testsuite.pages.social;
+import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@@ -35,9 +36,12 @@ public class MicrosoftLoginPage extends AbstractSocialLoginPage {
@Override
public void login(String user, String password) {
+ WaitUtils.pause(5000); // we need to take it a bit slower
usernameInput.clear();
usernameInput.sendKeys(user);
submitButton.click();
+
+ WaitUtils.pause(5000);
passwordInput.sendKeys(password);
submitButton.click();
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
index 84691be..ff8546c 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
@@ -122,6 +122,11 @@ public class SamlClient {
}
@Override
+ public HttpUriRequest createSamlSignedResponse(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey) {
+ return null;
+ }
+
+ @Override
public HttpPost createSamlSignedRequest(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey) {
return createSamlPostMessage(samlEndpoint, relayState, samlRequest, GeneralConstants.SAML_REQUEST_KEY, realmPrivateKey, realmPublicKey);
}
@@ -206,7 +211,38 @@ public class SamlClient {
@Override
public HttpUriRequest createSamlUnsignedResponse(URI samlEndpoint, String relayState, Document samlRequest) {
- return null;
+ try {
+ URI responseURI = new BaseSAML2BindingBuilder()
+ .relayState(relayState)
+ .redirectBinding(samlRequest)
+ .responseURI(samlEndpoint.toString());
+ return new HttpGet(responseURI);
+ } catch (ProcessingException | ConfigurationException | IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public HttpUriRequest createSamlSignedResponse(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey) {
+
+ try {
+ BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder();
+
+ if (realmPrivateKey != null && realmPublicKey != null) {
+ PrivateKey privateKey = org.keycloak.testsuite.util.KeyUtils.privateKeyFromString(realmPrivateKey);
+ PublicKey publicKey = org.keycloak.testsuite.util.KeyUtils.publicKeyFromString(realmPublicKey);
+ binding
+ .signatureAlgorithm(SignatureAlgorithm.RSA_SHA256)
+ .signWith(KeyUtils.createKeyId(privateKey), privateKey, publicKey)
+ .signDocument();
+ }
+
+ binding.relayState(relayState);
+
+ return new HttpGet(binding.redirectBinding(samlRequest).responseURI(samlEndpoint.toString()));
+ } catch (IOException | ConfigurationException | ProcessingException ex) {
+ throw new RuntimeException(ex);
+ }
}
@Override
@@ -224,6 +260,8 @@ public class SamlClient {
public abstract URI getBindingUri();
public abstract HttpUriRequest createSamlUnsignedResponse(URI samlEndpoint, String relayState, Document samlRequest);
+
+ public abstract HttpUriRequest createSamlSignedResponse(URI samlEndpoint, String relayState, Document samlRequest, String realmPrivateKey, String realmPublicKey);
}
private static final Logger LOG = Logger.getLogger(SamlClient.class);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
index a7cded4..4cc9d4a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
@@ -16,7 +16,11 @@
*/
package org.keycloak.testsuite.adapter.example.authorization;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.util.IOUtil.loadJson;
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
@@ -31,14 +35,18 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.function.Predicate;
import java.util.stream.Collectors;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.LaxRedirectStrategy;
import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -68,7 +76,7 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
private static final String REALM_NAME = "photoz";
private static final String RESOURCE_SERVER_ID = "photoz-restful-api";
- private static int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
+ private static final int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
@ArquillianResource
private Deployer deployer;
@@ -86,8 +94,19 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
public static void enabled() { ProfileAssume.assumePreview(); }
@Before
- public void beforePhotozExampleAdapterTest() throws FileNotFoundException {
+ public void beforePhotozExampleAdapterTest() throws Exception {
deleteAllCookiesForClientPage();
+ this.deployer.deploy(RESOURCE_SERVER_ID);
+
+ try (CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build()) {
+ HttpGet request = new HttpGet(clientPage.toString() + "/unsecured/clean");
+ httpClient.execute(request).close();
+ }
+ }
+
+ @After
+ public void afterPhotozExampleAdapterTest() {
+ this.deployer.undeploy(RESOURCE_SERVER_ID);
}
@Override
@@ -115,655 +134,530 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
importResourceServerSettings();
}
+ private List<ResourceRepresentation> getResourcesOfUser(String username) throws FileNotFoundException {
+ return getAuthorizationResource().resources().resources().stream().filter(resource -> resource.getOwner().getName().equals(username)).collect(Collectors.toList());
+ }
+
+ private void printUpdatedPolicies() throws FileNotFoundException {
+ log.debug("Check updated policies");
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ log.debugf("Policy: {0}", policy.getName());
+ for (String key : policy.getConfig().keySet()) {
+ log.debugf("-- key: {0}, value: {1}", key, policy.getConfig().get(key));
+ }
+ }
+ log.debug("------------------------------");
+ }
+
@Test
public void testUserCanCreateAndDeleteAlbum() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice Family Album");
+ loginToClientPage("alice", "alice");
- List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
- assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+ clientPage.createAlbum("Alice Family Album");
+ log.debug("Check if alice has resources stored");
+ assertThat(getResourcesOfUser("alice"), is(not(empty())));
- this.clientPage.deleteAlbum("Alice Family Album");
-
- resources = getAuthorizationResource().resources().resources();
- assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ clientPage.deleteAlbum("Alice Family Album", false);
+ log.debug("Check if alice has resources deleted");
+ assertThat(getResourcesOfUser("alice"), is(empty()));
}
@Test
public void createAlbumWithInvalidUser() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
+ loginToClientPage("alice", "alice");
- loginToClientPage("alice", "alice");
+ clientPage.createAlbumWithInvalidUser("Alice Family Album");
- clientPage.createAlbumWithInvalidUser("Alice Family Album");
-
- waitUntilElement(clientPage.getOutput()).text().not().contains("Request was successful");
- waitUntilElement(clientPage.getOutput()).text().contains("Could not register protected resource");
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ log.debug("Check if the album was not created.");
+ waitUntilElement(clientPage.getOutput()).text().not().contains("Request was successful");
+ waitUntilElement(clientPage.getOutput()).text().contains("Could not register protected resource");
}
@Test
public void testOnlyOwnerCanDeleteAlbum() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice-Family-Album");
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice-Family-Album");
- loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
+ loginToClientPage("admin", "admin");
+ clientPage.navigateToAdminAlbum(false);
- List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
- assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+ log.debug("Check if alice has resources stored");
+ assertThat(getResourcesOfUser("alice"), is(not(empty())));
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Delete Album Permission".equals(policy.getName())) {
- policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ log.debug("Adding applyPolicies \"Only Owner Policy\" to \"Delete Album Permission\" policies.");
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Delete Album Permission".equals(policy.getName())) {
+ policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
+ }
+ printUpdatedPolicies();
- loginToClientPage("admin", "admin");
+ loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
- resources = getAuthorizationResource().resources().resources();
- assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum("Alice-Family-Album", true);
+
+ log.debug("Check if alice has resources stored");
+ assertThat(getResourcesOfUser("alice"), is(not(empty())));
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Delete Album Permission".equals(policy.getName())) {
- policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ log.debug("Adding applyPolicies \"Only Owner and Administrators Policy\" to \"Delete Album Permission\" policies.");
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Delete Album Permission".equals(policy.getName())) {
+ policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
-
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertFalse(this.clientPage.wasDenied());
- resources = getAuthorizationResource().resources().resources();
- assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
}
- }
+ printUpdatedPolicies();
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum("Alice-Family-Album", false);
+
+ log.debug("Check if alice has resources deleted");
+ assertThat(getResourcesOfUser("alice"), is(empty()));
+ }
+
+
@Test
public void testRegularUserCanNotAccessAdminResources() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
- this.clientPage.navigateToAdminAlbum();
- assertTrue(this.clientPage.wasDenied());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ loginToClientPage("alice", "alice");
+ clientPage.navigateToAdminAlbum(true);
}
@Test
public void testAdminOnlyFromSpecificAddress() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- assertFalse(this.clientPage.wasDenied());
-
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Only From a Specific Client Address".equals(policy.getName())) {
- String code = policy.getConfig().get("code");
- policy.getConfig().put("code", code.replaceAll("127.0.0.1", "127.3.3.3"));
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ loginToClientPage("admin", "admin");
+ clientPage.navigateToAdminAlbum(false);
+
+ log.debug("Changing codes \"127.0.0.1\" to \"127.3.3.3\" of \"Only From a Specific Client Address\" policies.");
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Only From a Specific Client Address".equals(policy.getName())) {
+ String code = policy.getConfig().get("code");
+ policy.getConfig().put("code", code.replaceAll("127.0.0.1", "127.3.3.3"));
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
-
- this.clientPage.navigateToAdminAlbum();
- assertTrue(this.clientPage.wasDenied());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
}
+ printUpdatedPolicies();
+
+ clientPage.navigateToAdminAlbum(true);
}
@Test
public void testAdminWithoutPermissionsToTypedResource() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice Family Album");
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice Family Album");
+
+ loginToClientPage("admin", "admin");
+ clientPage.navigateToAdminAlbum(false);
+
+ clientPage.viewAlbum("Alice Family Album", false);
+
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Album Resource Permission".equals(policy.getName())) {
+ policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+ }
+ if ("Any User Policy".equals(policy.getName())) {
+ ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+ RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
+ RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
+ List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
- loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- assertFalse(this.clientPage.wasDenied());
+ roles = roles.stream().filter((Map map) -> !map.get("id").equals(roleRepresentation.getId())).collect(Collectors.toList());
- this.clientPage.viewAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
+ policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Album Resource Permission".equals(policy.getName())) {
- policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
- if ("Any User Policy".equals(policy.getName())) {
- ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
- RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
- RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
- List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
-
- roles = roles.stream().filter(new Predicate<Map>() {
- @Override
- public boolean test(Map map) {
- return !map.get("id").equals(roleRepresentation.getId());
- }
- }).collect(Collectors.toList());
-
- policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
-
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
+ }
+ printUpdatedPolicies();
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum("Alice Family Album");
- assertTrue(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum("Alice Family Album", true);
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Album Resource Permission".equals(policy.getName())) {
- policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Album Resource Permission".equals(policy.getName())) {
+ policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
+ }
+ printUpdatedPolicies();
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum("Alice Family Album", false);
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum("Alice Family Album");
- List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
- assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum("Alice Family Album", false);
+ assertThat(getResourcesOfUser("alice"), is(empty()));
}
@Test
public void testAdminWithoutPermissionsToDeleteAlbum() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice Family Album");
-
- loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- assertFalse(this.clientPage.wasDenied());
-
- this.clientPage.deleteAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
- List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
- assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
-
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Delete Album Permission".equals(policy.getName())) {
- policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice Family Album");
+
+ loginToClientPage("admin", "admin");
+ clientPage.navigateToAdminAlbum(false);
+
+ clientPage.deleteAlbum("Alice Family Album", false);
+ assertThat(getResourcesOfUser("alice"), is(empty()));
+
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Delete Album Permission".equals(policy.getName())) {
+ policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
+ }
+ printUpdatedPolicies();
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice Family Album");
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice Family Album");
- loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
- resources = getAuthorizationResource().resources().resources();
- assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+ loginToClientPage("admin", "admin");
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum("Alice Family Album", false);
+ assertThat(getResourcesOfUser("alice"), is(not(empty())));
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum("Alice Family Album");
- assertTrue(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum("Alice Family Album", true);
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Delete Album Permission".equals(policy.getName())) {
- policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Delete Album Permission".equals(policy.getName())) {
+ policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
-
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
- resources = getAuthorizationResource().resources().resources();
- assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
}
+ printUpdatedPolicies();
+
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum("Alice Family Album", false);
+ assertThat(getResourcesOfUser("alice"), is(empty()));
}
@Test
public void testClientRoleRepresentingUserConsent() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
- assertFalse(this.clientPage.wasDenied());
- this.clientPage.createAlbum("Alice Family Album");
- this.clientPage.viewAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice Family Album");
+ clientPage.viewAlbum("Alice Family Album", false);
- UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
- List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
+ UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
+ List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
- assertFalse(users.isEmpty());
+ assertFalse(users.isEmpty());
- UserRepresentation userRepresentation = users.get(0);
- UserResource userResource = usersResource.get(userRepresentation.getId());
+ UserRepresentation userRepresentation = users.get(0);
+ UserResource userResource = usersResource.get(userRepresentation.getId());
- ClientResource html5ClientApp = getClientResource("photoz-html5-client");
+ ClientResource html5ClientApp = getClientResource("photoz-html5-client");
- userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
+ userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
- ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
- RoleResource roleResource = resourceServerClient.roles().get("manage-albums");
- RoleRepresentation roleRepresentation = roleResource.toRepresentation();
+ ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+ RoleResource roleResource = resourceServerClient.roles().get("manage-albums");
+ RoleRepresentation roleRepresentation = roleResource.toRepresentation();
- roleRepresentation.setScopeParamRequired(true);
+ roleRepresentation.setScopeParamRequired(true);
- roleResource.update(roleRepresentation);
+ roleResource.update(roleRepresentation);
- loginToClientPage("alice", "alice");
- this.clientPage.viewAlbum("Alice Family Album");
- assertTrue(this.clientPage.wasDenied());
+ loginToClientPage("alice", "alice");
+ clientPage.viewAlbum("Alice Family Album", true);
- loginToClientPage("alice", "alice", RESOURCE_SERVER_ID + "/manage-albums");
- this.clientPage.viewAlbum("Alice Family Album", false);
- assertFalse(this.clientPage.wasDenied());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ loginToClientPage("alice", "alice", RESOURCE_SERVER_ID + "/manage-albums");
+ clientPage.viewAlbum("Alice Family Album", false);
}
@Test
public void testClientRoleNotRequired() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
+ loginToClientPage("alice", "alice");
- assertFalse(this.clientPage.wasDenied());
+ clientPage.createAlbum("Alice Family Album");
+ clientPage.viewAlbum("Alice Family Album", false);
- this.clientPage.createAlbum("Alice Family Album");
- this.clientPage.viewAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
+ UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
+ List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
- UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
- List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
+ assertFalse(users.isEmpty());
- assertFalse(users.isEmpty());
+ UserRepresentation userRepresentation = users.get(0);
+ UserResource userResource = usersResource.get(userRepresentation.getId());
- UserRepresentation userRepresentation = users.get(0);
- UserResource userResource = usersResource.get(userRepresentation.getId());
+ ClientResource html5ClientApp = getClientResource("photoz-html5-client");
- ClientResource html5ClientApp = getClientResource("photoz-html5-client");
+ userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
- userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
+ ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+ RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
+ RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
- ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
- RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
- RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
+ roleRepresentation.setScopeParamRequired(true);
- roleRepresentation.setScopeParamRequired(true);
+ manageAlbumRole.update(roleRepresentation);
- manageAlbumRole.update(roleRepresentation);
+ loginToClientPage("alice", "alice");
+ clientPage.viewAlbum("Alice Family Album", true);
- loginToClientPage("alice", "alice");
- this.clientPage.viewAlbum("Alice Family Album");
- assertTrue(this.clientPage.wasDenied());
+ for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+ if ("Any User Policy".equals(policy.getName())) {
+ List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
- for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
- if ("Any User Policy".equals(policy.getName())) {
- List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
-
- roles.forEach(role -> {
- String roleId = (String) role.get("id");
- if (roleId.equals(manageAlbumRole.toRepresentation().getId())) {
- role.put("required", false);
- }
- });
+ roles.forEach(role -> {
+ String roleId = (String) role.get("id");
+ if (roleId.equals(manageAlbumRole.toRepresentation().getId())) {
+ role.put("required", false);
+ }
+ });
- policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
- getAuthorizationResource().policies().policy(policy.getId()).update(policy);
- }
+ policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
+ getAuthorizationResource().policies().policy(policy.getId()).update(policy);
}
-
- loginToClientPage("alice", "alice");
- this.clientPage.viewAlbum("Alice Family Album");
- assertFalse(this.clientPage.wasDenied());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
}
+ printUpdatedPolicies();
+
+ loginToClientPage("alice", "alice");
+ clientPage.viewAlbum("Alice Family Album", false);
}
@Test
public void testOverridePermissionFromResourceParent() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
- String resourceName = "My Resource Instance";
- this.clientPage.createAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ loginToClientPage("alice", "alice");
+ String resourceName = "My Resource Instance";
+ clientPage.createAlbum(resourceName);
- this.clientPage.viewAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.viewAlbum(resourceName, false);
- this.clientPage.navigateTo();
- this.clientPage.deleteAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateTo();
+ clientPage.deleteAlbum(resourceName, false);
- this.clientPage.createAlbum(resourceName);
+ clientPage.createAlbum(resourceName);
- this.clientPage.logOut();
- loginToClientPage("admin", "admin");
+ clientPage.logOut();
+ loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum(resourceName, false);
- this.clientPage.navigateToAdminAlbum();;
- this.clientPage.deleteAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum(resourceName, false);
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum(resourceName);
- getAuthorizationResource().resources().resources().forEach(resource -> {
- if (resource.getName().equals(resourceName)) {
- try {
- PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
+ getAuthorizationResource().resources().resources().forEach(resource -> {
+ if (resource.getName().equals(resourceName)) {
+ try {
+ PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
- resourceInstancePermission.setName(resourceName + "Permission");
- resourceInstancePermission.setType("resource");
+ resourceInstancePermission.setName(resourceName + "Permission");
+ resourceInstancePermission.setType("resource");
- Map<String, String> config = new HashMap<>();
+ Map<String, String> config = new HashMap<>();
- config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
- config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
+ config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
+ config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
- resourceInstancePermission.setConfig(config);
- getAuthorizationResource().policies().create(resourceInstancePermission);
- } catch (Exception e) {
- throw new RuntimeException("Error creating policy.", e);
- }
+ resourceInstancePermission.setConfig(config);
+ getAuthorizationResource().policies().create(resourceInstancePermission);
+ } catch (IOException e) {
+ throw new RuntimeException("Error creating policy.", e);
}
- });
+ }
+ });
+ printUpdatedPolicies();
- loginToClientPage("admin", "admin");
+ loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum(resourceName);
- assertTrue(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum(resourceName, true);
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum(resourceName);
- assertTrue(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum(resourceName, true);
- loginToClientPage("alice", "alice");
- this.clientPage.deleteAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ loginToClientPage("alice", "alice");
+ clientPage.deleteAlbum(resourceName, false);
- ResourcesResource resourcesResource = getAuthorizationResource().resources();
- List<ResourceRepresentation> resources = resourcesResource.resources();
- assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ assertThat(getResourcesOfUser("alice"), is(empty()));
}
@Test
public void testInheritPermissionFromResourceParent() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- loginToClientPage("alice", "alice");
+ loginToClientPage("alice", "alice");
- String resourceName = "My Resource Instance";
- this.clientPage.createAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ String resourceName = "My Resource Instance";
+ clientPage.createAlbum(resourceName);
- this.clientPage.viewAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.viewAlbum(resourceName, false);
- this.clientPage.navigateTo();
- this.clientPage.deleteAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateTo();
+ clientPage.deleteAlbum(resourceName, false);
- this.clientPage.createAlbum(resourceName);
+ clientPage.createAlbum(resourceName);
- loginToClientPage("admin", "admin");
+ loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum(resourceName, false);
- this.clientPage.navigateToAdminAlbum();;
- this.clientPage.deleteAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum(resourceName, false);
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum(resourceName);
- ResourcesResource resourcesResource = getAuthorizationResource().resources();
- resourcesResource.resources().forEach(resource -> {
- if (resource.getName().equals(resourceName)) {
- try {
- PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
+ ResourcesResource resourcesResource = getAuthorizationResource().resources();
+ resourcesResource.resources().forEach(resource -> {
+ if (resource.getName().equals(resourceName)) {
+ try {
+ PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
- resourceInstancePermission.setName(resourceName + "Permission");
- resourceInstancePermission.setType("resource");
+ resourceInstancePermission.setName(resourceName + "Permission");
+ resourceInstancePermission.setType("resource");
- Map<String, String> config = new HashMap<>();
+ Map<String, String> config = new HashMap<>();
- config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
- config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
+ config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
+ config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
- resourceInstancePermission.setConfig(config);
- getAuthorizationResource().policies().create(resourceInstancePermission);
- } catch (Exception e) {
- throw new RuntimeException("Error creating policy.", e);
- }
+ resourceInstancePermission.setConfig(config);
+ getAuthorizationResource().policies().create(resourceInstancePermission);
+ } catch (IOException e) {
+ throw new RuntimeException("Error creating policy.", e);
}
- });
+ }
+ });
- loginToClientPage("admin", "admin");
+ loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum(resourceName);
- assertTrue(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum(resourceName, true);
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum(resourceName);
- assertTrue(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum(resourceName, true);
- resourcesResource.resources().forEach(resource -> {
- if (resource.getName().equals(resourceName)) {
- resource.setScopes(resource.getScopes().stream().filter(scope -> !scope.getName().equals("album:view")).collect(Collectors.toSet()));
- resourcesResource.resource(resource.getId()).update(resource);
- }
- });
+ resourcesResource.resources().forEach(resource -> {
+ if (resource.getName().equals(resourceName)) {
+ resource.setScopes(resource.getScopes().stream().filter(scope -> !scope.getName().equals("album:view")).collect(Collectors.toSet()));
+ resourcesResource.resource(resource.getId()).update(resource);
+ }
+ });
- loginToClientPage("admin", "admin");
+ loginToClientPage("admin", "admin");
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.viewAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.viewAlbum(resourceName, false);
- this.clientPage.navigateToAdminAlbum();
- this.clientPage.deleteAlbum(resourceName);
- assertTrue(this.clientPage.wasDenied());
+ clientPage.navigateToAdminAlbum(false);
+ clientPage.deleteAlbum(resourceName, true);
- loginToClientPage("alice", "alice");
- this.clientPage.deleteAlbum(resourceName);
- assertFalse(this.clientPage.wasDenied());
- List<ResourceRepresentation> resources = resourcesResource.resources();
- assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+ loginToClientPage("alice", "alice");
+ clientPage.deleteAlbum(resourceName, false);
+ List<ResourceRepresentation> resources = resourcesResource.resources();
+ assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
- resourcesResource.resources().forEach(resource -> {
- if (resource.getName().equals(resourceName)) {
- resource.setScopes(Collections.emptySet());
- resourcesResource.resource(resource.getId()).update(resource);
- }
- });
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ resourcesResource.resources().forEach(resource -> {
+ if (resource.getName().equals(resourceName)) {
+ resource.setScopes(Collections.emptySet());
+ resourcesResource.resource(resource.getId()).update(resource);
+ }
+ });
}
//KEYCLOAK-3777
@Test
public void testEntitlementRequest() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
-
- clientPage.navigateTo();
- loginToClientPage("admin", "admin");
-
- clientPage.requestEntitlements();
- assertTrue(driver.getPageSource().contains("admin:manage"));
-
- clientPage.requestEntitlement();
- String pageSource = driver.getPageSource();
- assertTrue(pageSource.contains("album:view"));
- assertTrue(pageSource.contains("album:delete"));
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ clientPage.navigateTo();
+ loginToClientPage("admin", "admin");
+
+ clientPage.requestEntitlements();
+ assertTrue(driver.getPageSource().contains("admin:manage"));
+
+ clientPage.requestEntitlement();
+ String pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("album:view"));
+ assertTrue(pageSource.contains("album:delete"));
}
@Test
public void testResourceProtectedWithAnyScope() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
- loginToClientPage("alice", "alice");
- this.clientPage.requestResourceProtectedAllScope();
- assertTrue(this.clientPage.wasDenied());
- this.clientPage.requestResourceProtectedAnyScope();
- assertFalse(this.clientPage.wasDenied());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ loginToClientPage("alice", "alice");
+ clientPage.requestResourceProtectedAllScope(true);
+ clientPage.requestResourceProtectedAnyScope(false);
}
@Test
public void testRequestResourceToOwner() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice-Family-Album", true);
-
- loginToClientPage("jdoe", "jdoe");
- this.clientPage.viewAllAlbums();
- this.clientPage.viewAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
- this.clientPage.navigateTo();
- this.clientPage.viewAllAlbums();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
-
- loginToClientPage("alice", "alice");
- this.clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
-
- loginToClientPage("jdoe", "jdoe");
- this.clientPage.viewAllAlbums();
- this.clientPage.viewAlbum("Alice-Family-Album");
- assertFalse(this.clientPage.wasDenied());
- this.clientPage.navigateTo();
- this.clientPage.viewAllAlbums();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertFalse(this.clientPage.wasDenied());
-
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice-Family-Album", true);
-
- loginToClientPage("jdoe", "jdoe");
- this.clientPage.viewAllAlbums();
- this.clientPage.viewAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
- this.clientPage.navigateTo();
- this.clientPage.viewAllAlbums();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
-
- loginToClientPage("alice", "alice");
- this.clientPage.accountGrantRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
- this.clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
-
- loginToClientPage("jdoe", "jdoe");
- this.clientPage.viewAllAlbums();
- this.clientPage.viewAlbum("Alice-Family-Album");
- assertFalse(this.clientPage.wasDenied());
- this.clientPage.navigateTo();
- this.clientPage.viewAllAlbums();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice-Family-Album", true);
+
+ loginToClientPage("jdoe", "jdoe");
+ clientPage.viewAllAlbums();
+ clientPage.viewAlbum("Alice-Family-Album", true);
+ clientPage.navigateTo();
+ clientPage.viewAllAlbums();
+ clientPage.deleteAlbum("Alice-Family-Album", true);
+
+ loginToClientPage("alice", "alice");
+ clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
+
+ loginToClientPage("jdoe", "jdoe");
+ clientPage.viewAllAlbums();
+ clientPage.viewAlbum("Alice-Family-Album", false);
+ clientPage.navigateTo();
+ clientPage.viewAllAlbums();
+ clientPage.deleteAlbum("Alice-Family-Album", false);
+
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice-Family-Album", true);
+
+ loginToClientPage("jdoe", "jdoe");
+ clientPage.viewAllAlbums();
+ clientPage.viewAlbum("Alice-Family-Album", true);
+ clientPage.navigateTo();
+ clientPage.viewAllAlbums();
+ clientPage.deleteAlbum("Alice-Family-Album", true);
+
+ loginToClientPage("alice", "alice");
+ clientPage.accountGrantRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
+ clientPage.accountGrantResource("Alice-Family-Album", "jdoe");
+
+ loginToClientPage("jdoe", "jdoe");
+ clientPage.viewAllAlbums();
+ clientPage.viewAlbum("Alice-Family-Album", false);
+ clientPage.navigateTo();
+ clientPage.viewAllAlbums();
+ clientPage.deleteAlbum("Alice-Family-Album", true);
}
@Test
public void testOwnerSharingResource() throws Exception {
- try {
- this.deployer.deploy(RESOURCE_SERVER_ID);
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice-Family-Album", true);
- this.clientPage.accountShareResource("Alice-Family-Album", "jdoe");
-
- loginToClientPage("jdoe", "jdoe");
- this.clientPage.viewAllAlbums();
- this.clientPage.viewAlbum("Alice-Family-Album");
- assertFalse(this.clientPage.wasDenied());
- this.clientPage.navigateTo();
- this.clientPage.viewAllAlbums();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertFalse(this.clientPage.wasDenied());
-
- loginToClientPage("alice", "alice");
- this.clientPage.createAlbum("Alice-Family-Album", true);
- this.clientPage.accountShareRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
-
- loginToClientPage("jdoe", "jdoe");
- this.clientPage.viewAllAlbums();
- this.clientPage.viewAlbum("Alice-Family-Album");
- assertFalse(this.clientPage.wasDenied());
- this.clientPage.navigateTo();
- this.clientPage.viewAllAlbums();
- this.clientPage.deleteAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
-
- loginToClientPage("alice", "alice");
- this.clientPage.accountRevokeResource("Alice-Family-Album", "jdoe");
-
- loginToClientPage("jdoe", "jdoe");
- this.clientPage.viewAllAlbums();
- this.clientPage.viewAlbum("Alice-Family-Album");
- assertTrue(this.clientPage.wasDenied());
- } finally {
- this.deployer.undeploy(RESOURCE_SERVER_ID);
- }
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice-Family-Album", true);
+ clientPage.accountShareResource("Alice-Family-Album", "jdoe");
+
+ loginToClientPage("jdoe", "jdoe");
+ clientPage.viewAllAlbums();
+ clientPage.viewAlbum("Alice-Family-Album", false);
+ clientPage.navigateTo();
+ clientPage.viewAllAlbums();
+ clientPage.deleteAlbum("Alice-Family-Album", false);
+
+ loginToClientPage("alice", "alice");
+ clientPage.createAlbum("Alice-Family-Album", true);
+ clientPage.accountShareRemoveScope("Alice-Family-Album", "jdoe", "album:delete");
+
+ loginToClientPage("jdoe", "jdoe");
+ clientPage.viewAllAlbums();
+ clientPage.viewAlbum("Alice-Family-Album", false);
+ clientPage.navigateTo();
+ clientPage.viewAllAlbums();
+ clientPage.deleteAlbum("Alice-Family-Album", true);
+
+ loginToClientPage("alice", "alice");
+ clientPage.accountRevokeResource("Alice-Family-Album", "jdoe");
+
+ loginToClientPage("jdoe", "jdoe");
+ clientPage.viewAllAlbums();
+ clientPage.viewAlbum("Alice-Family-Album", true);
}
private void importResourceServerSettings() throws FileNotFoundException {
@@ -791,6 +685,7 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
}
private void loginToClientPage(String username, String password, String... scopes) throws InterruptedException {
+ log.debugf("--logging in as {0} with password: {1}; scopes: {2}", username, password, Arrays.toString(scopes));
// We need to log out by deleting cookies because the log out button sometimes doesn't work in PhantomJS
deleteAllCookiesForTestRealm();
clientPage.navigateTo();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java
index 2661185..5c6b0eb 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletPolicyEnforcerTest.java
@@ -379,6 +379,32 @@ public abstract class AbstractServletPolicyEnforcerTest extends AbstractExampleA
});
}
+ @Test
+ public void testPathOrderWithAllPaths() {
+ performTests(() -> {
+ login("alice", "alice");
+ navigateTo("/keycloak-6623");
+ assertFalse(wasDenied());
+ navigateTo("/keycloak-6623/sub-resource");
+ assertFalse(wasDenied());
+
+ updatePermissionPolicies("Pattern 13 Permission", "Deny Policy");
+
+ login("alice", "alice");
+ navigateTo("/keycloak-6623");
+ assertTrue(wasDenied());
+ navigateTo("/keycloak-6623/sub-resource");
+ assertFalse(wasDenied());
+
+ updatePermissionPolicies("Pattern 14 Permission", "Deny Policy");
+
+ login("alice", "alice");
+ navigateTo("/keycloak-6623");
+ assertTrue(wasDenied());
+ navigateTo("/keycloak-6623/sub-resource/resource");
+ assertTrue(wasDenied());
+ });
+ }
private void navigateTo(String path) {
this.driver.navigate().to(getResourceServerUrl() + path);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
index 70ef820..9d3b5ec 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
@@ -81,4 +81,11 @@ public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLS
public void testErrorHandlingUnsigned() {
}
+
+ @Test
+ @Override
+ @Ignore
+ public void testErrorHandlingSigned() {
+
+ }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
index 7d0d43e..1459cf4 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
@@ -109,6 +109,8 @@ import static org.keycloak.testsuite.AbstractAuthTest.createUserRepresentation;
import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWithAdminClient;
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO;
+import static org.keycloak.testsuite.saml.AbstractSamlTest.REALM_PRIVATE_KEY;
+import static org.keycloak.testsuite.saml.AbstractSamlTest.REALM_PUBLIC_KEY;
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
import static org.keycloak.testsuite.util.IOUtil.loadXML;
import static org.keycloak.testsuite.util.IOUtil.modifyDocElementAttribute;
@@ -978,22 +980,30 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
@Test
public void testErrorHandlingUnsigned() throws Exception {
- Client client = ClientBuilder.newClient();
- // make sure
- Response response = client.target(employeeServletPage.toString()).request().get();
- response.close();
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
- .destination(employeeServletPage.toString() + "/saml")
+ .destination(employeeSigServletPage.toString() + "/saml")
.issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
.status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
- BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder()
- .relayState(null);
Document document = builder.buildDocument();
- URI uri = binding.redirectBinding(document).generateURI(employeeServletPage.toString() + "/saml", false);
- response = client.target(uri).request().get();
- String errorPage = response.readEntity(String.class);
- response.close();
- Assert.assertEquals(403, response.getStatus());
+
+ new SamlClientBuilder()
+ .addStep((client, currentURI, currentResponse, context) ->
+ Binding.REDIRECT.createSamlUnsignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document))
+ .execute(closeableHttpResponse -> assertThat(closeableHttpResponse, bodyHC(containsString("INVALID_SIGNATURE"))));
+ }
+
+ @Test
+ public void testErrorHandlingSigned() throws Exception {
+ SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
+ .destination(employeeSigServletPage.toString() + "/saml")
+ .issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
+ .status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
+ Document document = builder.buildDocument();
+
+ new SamlClientBuilder()
+ .addStep((client, currentURI, currentResponse, context) ->
+ Binding.REDIRECT.createSamlSignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document, REALM_PRIVATE_KEY, REALM_PUBLIC_KEY))
+ .execute(closeableHttpResponse -> assertThat(closeableHttpResponse, bodyHC(containsString("ERROR_STATUS"))));
}
@Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
index 51a2cae..8546c2a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
@@ -18,22 +18,26 @@
package org.keycloak.testsuite.admin.client.authorization;
import org.junit.After;
-import org.junit.Before;
import org.junit.BeforeClass;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ResourceScopeResource;
import org.keycloak.admin.client.resource.ResourceScopesResource;
import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.admin.client.AbstractClientTest;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
import javax.ws.rs.core.Response;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+
+import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@@ -42,24 +46,32 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
protected static final String RESOURCE_SERVER_CLIENT_ID = "resource-server-test";
+ @Override
+ public void setDefaultPageUriParameters() {
+ super.setDefaultPageUriParameters();
+ testRealmPage.setAuthRealm("authz-test");
+ }
+
+ @Override
+ protected String getRealmId() {
+ return "authz-test";
+ }
+
@BeforeClass
public static void enabled() {
ProfileAssume.assumePreview();
}
- @Before
- public void onBeforeAuthzTests() {
- createOidcClient(RESOURCE_SERVER_CLIENT_ID);
-
- ClientRepresentation resourceServer = getResourceServer();
-
- assertEquals(RESOURCE_SERVER_CLIENT_ID, resourceServer.getName());
- assertFalse(resourceServer.getAuthorizationServicesEnabled());
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ testRealms.add(createTestRealm().build());
+ super.addTestRealms(testRealms);
}
@After
- public void onAfterAuthzTests() {
- getClientResource().remove();
+ public void onAfterReenableAuthorization() {
+ enableAuthorizationServices(false);
+ enableAuthorizationServices(true);
}
protected ClientResource getClientResource() {
@@ -70,22 +82,22 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
return findClientRepresentation(RESOURCE_SERVER_CLIENT_ID);
}
- protected void enableAuthorizationServices() {
+ protected void enableAuthorizationServices(boolean enable) {
ClientRepresentation resourceServer = getResourceServer();
- resourceServer.setAuthorizationServicesEnabled(true);
+ resourceServer.setAuthorizationServicesEnabled(enable);
resourceServer.setServiceAccountsEnabled(true);
resourceServer.setPublicClient(false);
resourceServer.setSecret("secret");
getClientResource().update(resourceServer);
- AuthorizationResource authorization = getClientResource().authorization();
- ResourceServerRepresentation settings = authorization.exportSettings();
-
- settings.setAllowRemoteResourceManagement(true);
-
- authorization.update(settings);
+ if (enable) {
+ AuthorizationResource authorization = getClientResource().authorization();
+ ResourceServerRepresentation settings = authorization.exportSettings();
+ settings.setAllowRemoteResourceManagement(true);
+ authorization.update(settings);
+ }
}
protected ResourceScopeResource createDefaultScope() {
@@ -108,4 +120,17 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
return resources.scope(stored.getId());
}
+
+ private RealmBuilder createTestRealm() {
+ return RealmBuilder.create().name("authz-test")
+ .user(UserBuilder.create().username("marta").password("password"))
+ .user(UserBuilder.create().username("kolo").password("password"))
+ .client(ClientBuilder.create().clientId(RESOURCE_SERVER_CLIENT_ID)
+ .name(RESOURCE_SERVER_CLIENT_ID)
+ .secret("secret")
+ .authorizationServicesEnabled(true)
+ .redirectUris("http://localhost/" + RESOURCE_SERVER_CLIENT_ID)
+ .defaultRoles("uma_protection")
+ .directAccessGrants());
+ }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
index 2d549de..f642979 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
@@ -24,6 +24,7 @@ import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
@@ -44,17 +45,38 @@ public class AuthorizationTest extends AbstractAuthorizationTest {
ClientResource clientResource = getClientResource();
ClientRepresentation resourceServer = getResourceServer();
- enableAuthorizationServices();
+ enableAuthorizationServices(false);
+ enableAuthorizationServices(true);
+
+ clientResource.authorization().resources().create(new ResourceRepresentation("Should be removed"));
+
+ JSPolicyRepresentation policy = new JSPolicyRepresentation();
+
+ policy.setName("should be removed");
+ policy.setCode("");
+
+ clientResource.authorization().policies().js().create(policy);
+
+ List<ResourceRepresentation> defaultResources = clientResource.authorization().resources().resources();
+
+ assertEquals(2, defaultResources.size());
+
+ List<PolicyRepresentation> defaultPolicies = clientResource.authorization().policies().policies();
+
+ assertEquals(3, defaultPolicies.size());
+
+ enableAuthorizationServices(false);
+ enableAuthorizationServices(true);
ResourceServerRepresentation settings = clientResource.authorization().getSettings();
assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
assertEquals(resourceServer.getId(), settings.getClientId());
- List<ResourceRepresentation> defaultResources = clientResource.authorization().resources().resources();
+ defaultResources = clientResource.authorization().resources().resources();
assertEquals(1, defaultResources.size());
- List<PolicyRepresentation> defaultPolicies = clientResource.authorization().policies().policies();
+ defaultPolicies = clientResource.authorization().policies().policies();
assertEquals(2, defaultPolicies.size());
}
@@ -72,8 +94,6 @@ public class AuthorizationTest extends AbstractAuthorizationTest {
ClientResource clientResource = getClientResource();
ClientRepresentation resourceServer = getResourceServer();
- enableAuthorizationServices();
-
ResourceServerRepresentation settings = clientResource.authorization().getSettings();
assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java
index c71d12f..59d655a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ExportAuthorizationSettingsTest.java
@@ -46,8 +46,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
String permissionName = "resource-based-permission";
ClientResource clientResource = getClientResource();
-
- enableAuthorizationServices();
AuthorizationResource authorizationResource = clientResource.authorization();
//get Default Resource
@@ -89,8 +87,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
@Test
public void testRoleBasedPolicy() {
ClientResource clientResource = getClientResource();
-
- enableAuthorizationServices();
AuthorizationResource authorizationResource = clientResource.authorization();
ClientRepresentation account = testRealmResource().clients().findByClientId("account").get(0);
@@ -121,8 +117,6 @@ public class ExportAuthorizationSettingsTest extends AbstractAuthorizationTest {
@Test
public void testRoleBasedPolicyWithMultipleRoles() {
ClientResource clientResource = getClientResource();
-
- enableAuthorizationServices();
AuthorizationResource authorizationResource = clientResource.authorization();
testRealmResource().clients().create(ClientBuilder.create().clientId("test-client-1").defaultRoles("client-role").build()).close();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
index bd4d973..322492d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
@@ -54,19 +54,6 @@ public class GenericPolicyManagementTest extends AbstractAuthorizationTest {
private static final String[] EXPECTED_BUILTIN_POLICY_PROVIDERS = {"test", "user", "role", "rules", "js", "time", "aggregate", "scope", "resource"};
- @Before
- @Override
- public void onBeforeAuthzTests() {
- super.onBeforeAuthzTests();
- enableAuthorizationServices();
- }
-
- @After
- @Override
- public void onAfterAuthzTests() {
- super.onAfterAuthzTests();
- }
-
@Test
public void testCreate() {
PolicyRepresentation newPolicy = createTestingPolicy().toRepresentation();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
index a308ec0..0524111 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ImportAuthorizationSettingsTest.java
@@ -48,24 +48,9 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
testRealmResource().users().create(UserBuilder.create().username("alice").build());
}
- @After
- public void onAfterAuthzTests() {
- ClientResource clientResource = getClientResource();
-
- // Needed to disable authz first. TODO: Looks like a bug. Check later...
- ClientRepresentation client = clientResource.toRepresentation();
- client.setAuthorizationServicesEnabled(false);
- clientResource.update(client);
-
- getClientResource().remove();
- }
-
@Test
public void testImportUnorderedSettings() throws Exception {
ClientResource clientResource = getClientResource();
-
- enableAuthorizationServices();
-
ResourceServerRepresentation toImport = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/import-authorization-unordered-settings.json"), ResourceServerRepresentation.class);
realmsResouce().realm(getRealmId()).roles().create(new RoleRepresentation("user", null, false));
@@ -75,6 +60,6 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
authorizationResource.importSettings(toImport);
- assertEquals(15, authorizationResource.policies().policies().size());
+ assertEquals(13, authorizationResource.policies().policies().size());
}
}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
index 3c1a2f1..41fcb66 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
@@ -18,12 +18,11 @@
package org.keycloak.testsuite.admin.client.authorization;
-import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ResourceResource;
import org.keycloak.admin.client.resource.ResourcesResource;
import org.keycloak.authorization.client.util.HttpResponseException;
-import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
@@ -35,6 +34,7 @@ import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -45,33 +45,6 @@ import static org.junit.Assert.fail;
*/
public class ResourceManagementTest extends AbstractAuthorizationTest {
- @Before
- @Override
- public void onBeforeAuthzTests() {
- super.onBeforeAuthzTests();
- enableAuthorizationServices();
- }
-
- @Override
- public void addTestRealms(List<RealmRepresentation> testRealms) {
- RealmRepresentation testRealmRep = new RealmRepresentation();
- testRealmRep.setId("authz-test");
- testRealmRep.setRealm("authz-test");
- testRealmRep.setEnabled(true);
- testRealms.add(testRealmRep);
- }
-
- @Override
- public void setDefaultPageUriParameters() {
- super.setDefaultPageUriParameters();
- testRealmPage.setAuthRealm("authz-test");
- }
-
- @Override
- protected String getRealmId() {
- return "authz-test";
- }
-
@Test
public void testCreate() {
ResourceRepresentation newResource = createResource();
@@ -103,6 +76,28 @@ public class ResourceManagementTest extends AbstractAuthorizationTest {
}
@Test
+ public void failCreateWithSameNameDifferentOwner() {
+ ResourceRepresentation martaResource = createResource("Resource A", "marta", null, null, null);
+ ResourceRepresentation koloResource = createResource("Resource A", "kolo", null, null, null);
+
+ assertNotNull(martaResource.getId());
+ assertNotNull(koloResource.getId());
+ assertNotEquals(martaResource.getId(), koloResource.getId());
+
+ assertEquals(2, getClientResource().authorization().resources().findByName(martaResource.getName()).size());
+
+ List<ResourceRepresentation> martaResources = getClientResource().authorization().resources().findByName(martaResource.getName(), "marta");
+
+ assertEquals(1, martaResources.size());
+ assertEquals(martaResource.getId(), martaResources.get(0).getId());
+
+ List<ResourceRepresentation> koloResources = getClientResource().authorization().resources().findByName(martaResource.getName(), "kolo");
+
+ assertEquals(1, koloResources.size());
+ assertEquals(koloResource.getId(), koloResources.get(0).getId());
+ }
+
+ @Test
public void testUpdate() {
ResourceRepresentation resource = createResource();
@@ -198,12 +193,17 @@ public class ResourceManagementTest extends AbstractAuthorizationTest {
}
private ResourceRepresentation createResource() {
+ return createResource("Test Resource", null, "/test/*", "test-resource", "icon-test-resource");
+ }
+
+ private ResourceRepresentation createResource(String name, String owner, String uri, String type, String iconUri) {
ResourceRepresentation newResource = new ResourceRepresentation();
- newResource.setName("Test Resource");
- newResource.setUri("/test/*");
- newResource.setType("test-resource");
- newResource.setIconUri("icon-test-resource");
+ newResource.setName(name);
+ newResource.setUri(uri);
+ newResource.setType(type);
+ newResource.setIconUri(iconUri);
+ newResource.setOwner(owner != null ? new ResourceOwnerRepresentation(owner) : null);
return doCreateResource(newResource);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
index 53c68ed..a784566 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/RulesPolicyManagementTest.java
@@ -95,7 +95,7 @@ public class RulesPolicyManagementTest extends AbstractPolicyManagementTest {
representation.setDescription("description");
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
representation.setLogic(Logic.NEGATIVE);
- representation.setArtifactGroupId("org.keycloak");
+ representation.setArtifactGroupId("org.keycloak.testsuite");
representation.setArtifactId("photoz-authz-policy");
representation.setArtifactVersion(System.getProperty("project.version"));
representation.setModuleName("PhotozAuthzOwnerPolicy");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
index bcb8b1b..9590078 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
@@ -33,13 +33,6 @@ import static org.junit.Assert.assertEquals;
*/
public class ScopeManagementTest extends AbstractAuthorizationTest {
- @Before
- @Override
- public void onBeforeAuthzTests() {
- super.onBeforeAuthzTests();
- enableAuthorizationServices();
- }
-
@Test
public void testCreate() {
ScopeRepresentation newScope = createDefaultScope().toRepresentation();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java
index 37dd1ff..fc9ccdd 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationAPITest.java
@@ -191,7 +191,7 @@ public class AuthorizationAPITest extends AbstractAuthzTest {
assertEquals(resourceServerClientId, rpt.getAudience()[0]);
}
- private RealmResource getRealm() throws Exception {
+ private RealmResource getRealm() {
return adminClient.realm("authz-test");
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationTest.java
new file mode 100644
index 0000000..16eb0cb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/AuthorizationTest.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.authz;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.core.Response;
+
+import org.jetbrains.annotations.NotNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.ResourcesResource;
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.Configuration;
+import org.keycloak.jose.jws.JWSInputException;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.AccessToken.Authorization;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.AuthorizationRequest;
+import org.keycloak.representations.idm.authorization.AuthorizationResponse;
+import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
+import org.keycloak.representations.idm.authorization.Permission;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
+import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.RoleBuilder;
+import org.keycloak.testsuite.util.RolesBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationTest extends AbstractAuthzTest {
+
+ private AuthzClient authzClient;
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ testRealms.add(RealmBuilder.create().name("authz-test")
+ .roles(RolesBuilder.create().realmRole(RoleBuilder.create().name("uma_authorization").build()))
+ .user(UserBuilder.create().username("marta").password("password").addRoles("uma_authorization"))
+ .user(UserBuilder.create().username("kolo").password("password"))
+ .client(ClientBuilder.create().clientId("resource-server-test")
+ .secret("secret")
+ .authorizationServicesEnabled(true)
+ .redirectUris("http://localhost/resource-server-test")
+ .defaultRoles("uma_protection")
+ .directAccessGrants())
+ .client(ClientBuilder.create().clientId("test-client")
+ .secret("secret")
+ .authorizationServicesEnabled(true)
+ .redirectUris("http://localhost/test-client")
+ .directAccessGrants())
+ .build());
+ }
+
+ @Before
+ public void configureAuthorization() throws Exception {
+ ClientResource client = getClient();
+ AuthorizationResource authorization = client.authorization();
+
+ JSPolicyRepresentation policy = new JSPolicyRepresentation();
+
+ policy.setName("Grant Policy");
+ policy.setCode("$evaluation.grant();");
+
+ authorization.policies().js().create(policy).close();
+
+ policy = new JSPolicyRepresentation();
+
+ policy.setName("Deny Policy");
+ policy.setCode("$evaluation.deny();");
+ }
+
+ @After
+ public void onAfter() {
+ ResourcesResource resources = getClient().authorization().resources();
+ List<ResourceRepresentation> existingResources = resources.resources();
+
+ for (ResourceRepresentation resource : existingResources) {
+ resources.resource(resource.getId()).remove();
+ }
+ }
+
+ @Test
+ public void testResourceWithSameNameDifferentOwner() throws JWSInputException {
+ ResourceRepresentation koloResource = createResource("Resource A", "kolo", "Scope A", "Scope B");
+
+ createResourcePermission(koloResource, "Grant Policy");
+
+ ResourceRepresentation martaResource = createResource("Resource A", "marta", "Scope A", "Scope B");
+
+ createResourcePermission(martaResource, "Grant Policy");
+
+ assertNotEquals(koloResource.getId(), martaResource.getId());
+
+ AuthorizationRequest request = new AuthorizationRequest();
+
+ request.addPermission("Resource A");
+
+ List<Permission> permissions = authorize("kolo", "password", request);
+
+ assertEquals(1, permissions.size());
+
+ Permission permission = permissions.get(0);
+ assertTrue(permission.getScopes().containsAll(Arrays.asList("Scope A", "Scope B")));
+
+ assertEquals(koloResource.getId(), permission.getResourceId());
+
+ permissions = authorize("marta", "password", request);
+
+ assertEquals(1, permissions.size());
+
+ permission = permissions.get(0);
+
+ assertEquals(martaResource.getId(), permission.getResourceId());
+ assertTrue(permission.getScopes().containsAll(Arrays.asList("Scope A", "Scope B")));
+ }
+
+ @Test
+ public void testResourceServerWithSameNameDifferentOwner() {
+ ResourceRepresentation koloResource = createResource("Resource A", "kolo", "Scope A", "Scope B");
+
+ createResourcePermission(koloResource, "Grant Policy");
+
+ ResourceRepresentation serverResource = createResource("Resource A", null, "Scope A", "Scope B");
+
+ createResourcePermission(serverResource, "Grant Policy");
+
+ AuthorizationRequest request = new AuthorizationRequest();
+
+ request.addPermission("Resource A");
+
+ List<Permission> permissions = authorize("kolo", "password", request);
+
+ assertEquals(2, permissions.size());
+
+ for (Permission permission : permissions) {
+ assertTrue(permission.getResourceId().equals(koloResource.getId()) || permission.getResourceId().equals(serverResource.getId()));
+ assertEquals("Resource A", permission.getResourceName());
+ }
+ }
+
+ private List<Permission> authorize(String userName, String password, AuthorizationRequest request) {
+ AuthorizationResponse response = getAuthzClient().authorization(userName, password).authorize(request);
+ AccessToken token = toAccessToken(response.getToken());
+ Authorization authorization = token.getAuthorization();
+ return authorization.getPermissions();
+ }
+
+ private void createResourcePermission(ResourceRepresentation resource, String... policies) {
+ ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
+
+ permission.setName(resource.getName() + UUID.randomUUID().toString());
+ permission.addResource(resource.getId());
+ permission.addPolicy(policies);
+
+ Response response = getClient().authorization().permissions().resource().create(permission);
+
+ assertEquals(201, response.getStatus());
+ }
+
+ @NotNull
+ private ResourceRepresentation createResource(String name, String owner, String... scopes) {
+ ResourceRepresentation resource = new ResourceRepresentation();
+
+ resource.setName(name);
+ resource.setOwner(owner != null ? new ResourceOwnerRepresentation(owner) : null);
+ resource.addScope(scopes);
+
+ Response response = getClient().authorization().resources().create(resource);
+ ResourceRepresentation stored = response.readEntity(ResourceRepresentation.class);
+ response.close();
+
+ resource.setId(stored.getId());
+
+ return resource;
+ }
+
+ private RealmResource getRealm() {
+ return adminClient.realm("authz-test");
+ }
+
+ private ClientResource getClient() {
+ ClientsResource clients = getRealm().clients();
+ return clients.findByClientId("resource-server-test").stream().map(representation -> clients.get(representation.getId())).findFirst().orElseThrow(() -> new RuntimeException("Expected client [resource-server-test]"));
+ }
+
+ private AuthzClient getAuthzClient() {
+ if (authzClient == null) {
+ try {
+ authzClient = AuthzClient.create(JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/default-keycloak.json"), Configuration.class));
+ } catch (IOException cause) {
+ throw new RuntimeException("Failed to create authz client", cause);
+ }
+ }
+
+ return authzClient;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java
index 21bb9ee..f488d32 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PermissionManagementTest.java
@@ -52,7 +52,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
public void testCreatePermissionTicketWithResourceName() throws Exception {
ResourceRepresentation resource = addResource("Resource A", "kolo", true);
AuthzClient authzClient = getAuthzClient();
- PermissionResponse response = authzClient.protection("marta", "password").permission().create(new PermissionRequest(resource.getName()));
+ PermissionResponse response = authzClient.protection("marta", "password").permission().create(new PermissionRequest(resource.getId()));
AuthorizationRequest request = new AuthorizationRequest();
request.setTicket(response.getTicket());
request.setClaimToken(authzClient.obtainAccessToken("marta", "password").getToken());
@@ -125,7 +125,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
@Test
public void testDeleteScopeAndPermissionTicket() throws Exception {
ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB", "ScopeC");
- PermissionRequest permissionRequest = new PermissionRequest(resource.getName());
+ PermissionRequest permissionRequest = new PermissionRequest(resource.getId());
permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeB", "ScopeC")));
@@ -164,7 +164,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
@Test
public void testRemoveScopeFromResource() throws Exception {
ResourceRepresentation resource = addResource("Resource A", "kolo", true, "ScopeA", "ScopeB");
- PermissionRequest permissionRequest = new PermissionRequest(resource.getName(), "ScopeA", "ScopeB");
+ PermissionRequest permissionRequest = new PermissionRequest(resource.getId(), "ScopeA", "ScopeB");
AuthzClient authzClient = getAuthzClient();
PermissionResponse response = authzClient.protection("marta", "password").permission().create(permissionRequest);
@@ -255,7 +255,7 @@ public class PermissionManagementTest extends AbstractResourceServerTest {
getClient(getRealm()).authorization().resources().resource(resourceA.getId()).update(resourceA);
- PermissionRequest permissionRequest = new PermissionRequest("Resource A");
+ PermissionRequest permissionRequest = new PermissionRequest(resourceA.getId());
permissionRequest.setScopes(new HashSet<>(Arrays.asList("ScopeA", "ScopeC")));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationTest.java
new file mode 100644
index 0000000..9ffad7b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationTest.java
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.authz;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.Decision.Effect;
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.common.DefaultEvaluationContext;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DefaultEvaluation;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.GroupMembershipMapper;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
+import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.GroupBuilder;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.RoleBuilder;
+import org.keycloak.testsuite.util.RolesBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyEvaluationTest extends AbstractAuthzTest {
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ ProtocolMapperRepresentation groupProtocolMapper = new ProtocolMapperRepresentation();
+
+ groupProtocolMapper.setName("groups");
+ groupProtocolMapper.setProtocolMapper(GroupMembershipMapper.PROVIDER_ID);
+ groupProtocolMapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+ groupProtocolMapper.setConsentRequired(false);
+ Map<String, String> config = new HashMap<>();
+ config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "groups");
+ config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
+ config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
+ config.put("full.path", "true");
+ groupProtocolMapper.setConfig(config);
+
+ testRealms.add(RealmBuilder.create().name("authz-test")
+ .roles(RolesBuilder.create()
+ .realmRole(RoleBuilder.create().name("uma_authorization").build())
+ .realmRole(RoleBuilder.create().name("role-a").build())
+ .realmRole(RoleBuilder.create().name("role-b").build())
+ )
+ .group(GroupBuilder.create().name("Group A")
+ .subGroups(Arrays.asList("Group B", "Group D").stream().map(name -> {
+ if ("Group B".equals(name)) {
+ return GroupBuilder.create().name(name).subGroups(Arrays.asList("Group C", "Group E").stream().map(new Function<String, GroupRepresentation>() {
+ @Override
+ public GroupRepresentation apply(String name) {
+ return GroupBuilder.create().name(name).build();
+ }
+ }).collect(Collectors.toList())).build();
+ }
+ return GroupBuilder.create().name(name).realmRoles(Arrays.asList("role-a")).build();
+ }).collect(Collectors.toList())).build())
+ .group(GroupBuilder.create().name("Group E").build())
+ .user(UserBuilder.create().username("marta").password("password").addRoles("uma_authorization", "role-a").addGroups("Group A"))
+ .user(UserBuilder.create().username("alice").password("password").addRoles("uma_authorization").addGroups("/Group A/Group B/Group E"))
+ .user(UserBuilder.create().username("kolo").password("password").addRoles("uma_authorization").addGroups("/Group A/Group D"))
+ .user(UserBuilder.create().username("trinity").password("password").addRoles("uma_authorization").role("role-mapping-client", "client-role-a"))
+ .user(UserBuilder.create().username("jdoe").password("password").addGroups("/Group A/Group B", "/Group A/Group D"))
+ .client(ClientBuilder.create().clientId("resource-server-test")
+ .secret("secret")
+ .authorizationServicesEnabled(true)
+ .redirectUris("http://localhost/resource-server-test")
+ .defaultRoles("uma_protection")
+ .directAccessGrants()
+ .protocolMapper(groupProtocolMapper))
+ .client(ClientBuilder.create().clientId("role-mapping-client")
+ .defaultRoles("client-role-a", "client-role-b"))
+ .build());
+ }
+
+ @Deployment
+ public static WebArchive deploy() {
+ return RunOnServerDeployment.create(AbstractAuthzTest.class);
+ }
+
+ @Test
+ public void testCheckUserInGroup() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckUserInGroup);
+ }
+
+ public static void testCheckUserInGroup(KeycloakSession session) {
+ session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckUserInGroup");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('marta', 'Group C')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('marta', 'Group A')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('marta', '/Group A')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('marta', '/Group A/Group B')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('alice', '/Group A/Group B/Group E')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('alice', '/Group A')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (!realm.isUserInGroup('alice', '/Group A', false)) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('alice', '/Group E')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInGroup('alice', 'Group E')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+ }
+
+ @Test
+ public void testCheckUserInRole() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckUserInRole);
+ }
+
+ public static void testCheckUserInRole(KeycloakSession session) {
+ session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckUserInRole");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInRealmRole('marta', 'role-a')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInRealmRole('marta', 'role-b')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+ }
+
+ @Test
+ public void testCheckUserInClientRole() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckUserInClientRole);
+ }
+
+ public static void testCheckUserInClientRole(KeycloakSession session) {
+ session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckUserInClientRole");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInClientRole('trinity', 'role-mapping-client', 'client-role-a')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isUserInRealmRole('trinity', 'client-role-b')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+ }
+
+ @Test
+ public void testCheckGroupInRole() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckGroupInRole);
+ }
+
+ public static void testCheckGroupInRole(KeycloakSession session) {
+ session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckGroupInRole");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isGroupInRole('/Group A/Group D', 'role-a')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+
+ builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("if (realm.isGroupInRole('/Group A/Group D', 'role-b')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ policyRepresentation.setId(policy.getId());
+ policy = RepresentationToModel.toModel(policyRepresentation, authorization, policy);
+
+ evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertNull(evaluation.getEffect());
+ }
+
+ @Test
+ public void testCheckUserRealmRoles() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckUserRealmRoles);
+ }
+
+ public static void testCheckUserRealmRoles(KeycloakSession session) {
+ session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckUserRealmRoles");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("var roles = realm.getUserRealmRoles('marta');");
+ builder.append("if (roles.size() == 2 && roles.contains('uma_authorization') && roles.contains('role-a')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+ }
+
+ @Test
+ public void testCheckUserClientRoles() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckUserClientRoles);
+ }
+
+ public static void testCheckUserClientRoles(KeycloakSession session) {
+ session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckUserClientRoles");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("var roles = realm.getUserClientRoles('trinity', 'role-mapping-client');");
+ builder.append("if (roles.size() == 1 && roles.contains('client-role-a')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+ }
+
+ @Test
+ public void testCheckUserGroups() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckUserGroups);
+ }
+
+ public static void testCheckUserGroups(KeycloakSession session) {
+ session.getContext().setRealm(session.realms().getRealmByName("authz-test"));
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckUserGroups");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("var groups = realm.getUserGroups('jdoe');");
+ builder.append("if (groups.size() == 2 && groups.contains('/Group A/Group B') && groups.contains('/Group A/Group D')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+ }
+
+ @Test
+ public void testCheckUserAttributes() {
+ testingClient.server().run(PolicyEvaluationTest::testCheckUserAttributes);
+ }
+
+ public static void testCheckUserAttributes(KeycloakSession session) {
+ RealmModel realm = session.realms().getRealmByName("authz-test");
+ UserModel jdoe = session.users().getUserByUsername("jdoe", realm);
+
+ jdoe.setAttribute("a1", Arrays.asList("1", "2"));
+ jdoe.setSingleAttribute("a2", "3");
+
+ session.getContext().setRealm(realm);
+ AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
+ ClientModel clientModel = session.realms().getClientByClientId("resource-server-test", session.getContext().getRealm());
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
+ JSPolicyRepresentation policyRepresentation = new JSPolicyRepresentation();
+
+ policyRepresentation.setName("testCheckUserAttributes");
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("var realm = $evaluation.getRealm();");
+ builder.append("var attributes = realm.getUserAttributes('jdoe');");
+ builder.append("if (attributes.size() == 2 && attributes.containsKey('a1') && attributes.containsKey('a2') && attributes.get('a1').size() == 2 && attributes.get('a2').get(0).equals('3')) { $evaluation.grant(); }");
+
+ policyRepresentation.setCode(builder.toString());
+
+ Policy policy = storeFactory.getPolicyStore().create(policyRepresentation, resourceServer);
+ PolicyProvider provider = authorization.getProvider(policy.getType());
+
+ DefaultEvaluation evaluation = createEvaluation(session, authorization, resourceServer, policy);
+
+ provider.evaluate(evaluation);
+
+ Assert.assertEquals(Effect.PERMIT, evaluation.getEffect());
+ }
+
+ @NotNull
+ private static DefaultEvaluation createEvaluation(KeycloakSession session, AuthorizationProvider authorization, ResourceServer resourceServer, Policy policy) {
+ return new DefaultEvaluation(new ResourcePermission(null, null, resourceServer), new DefaultEvaluationContext(new Identity() {
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public Attributes getAttributes() {
+ return null;
+ }
+ }, session), policy, policy, new Decision() {
+ @Override
+ public void onDecision(Evaluation evaluation) {
+
+ }
+ }, authorization);
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java
index 41448cf..5d4c1a1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UmaGrantTypeTest.java
@@ -123,7 +123,7 @@ public class UmaGrantTypeTest extends AbstractResourceServerTest {
ResourceRepresentation resourceA = addResource("Resource Marta", "marta", true, "ScopeA", "ScopeB", "ScopeC");
permission.setName(resourceA.getName() + " Permission");
- permission.addResource(resourceA.getName());
+ permission.addResource(resourceA.getId());
permission.addPolicy("Default Policy");
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -131,7 +131,7 @@ public class UmaGrantTypeTest extends AbstractResourceServerTest {
ResourceRepresentation resourceB = addResource("Resource B", "marta", "ScopeA", "ScopeB", "ScopeC");
permission.setName(resourceB.getName() + " Permission");
- permission.addResource(resourceB.getName());
+ permission.addResource(resourceB.getId());
permission.addPolicy("Default Policy");
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java
index f8dd3de..5ef774e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedAccessTest.java
@@ -68,7 +68,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
permission.setName(resource.getName() + " Permission");
- permission.addResource(resource.getName());
+ permission.addResource(resource.getId());
permission.addPolicy("Only Owner Policy");
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -91,7 +91,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
assertTrue(permissions.isEmpty());
try {
- response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
+ response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
fail("User should have access to resource from another user");
} catch (AuthorizationDeniedException ade) {
@@ -104,7 +104,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
permission.setName(resource.getName() + " Permission");
- permission.addResource(resource.getName());
+ permission.addResource(resource.getId());
permission.addPolicy("Only Owner Policy");
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -127,7 +127,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
assertTrue(permissions.isEmpty());
try {
- response = authorize("kolo", "password", "Resource A", new String[] {});
+ response = authorize("kolo", "password", resource.getId(), new String[] {});
fail("User should have access to resource from another user");
} catch (AuthorizationDeniedException ade) {
@@ -156,7 +156,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
assertTrue(ticket.isGranted());
}
- response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
+ response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
rpt = response.getToken();
assertNotNull(rpt);
@@ -180,7 +180,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
resource = addResource("Resource A", "marta", true);
permission.setName(resource.getName() + " Permission");
- permission.addResource(resource.getName());
+ permission.addResource(resource.getId());
permission.addPolicy("Only Owner Policy");
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -203,7 +203,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
assertTrue(permissions.isEmpty());
try {
- response = authorize("kolo", "password", "Resource A", new String[] {});
+ response = authorize("kolo", "password", resource.getId(), new String[] {});
fail("User should have access to resource from another user");
} catch (AuthorizationDeniedException ade) {
@@ -232,7 +232,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
assertTrue(ticket.isGranted());
}
- response = authorize("kolo", "password", resource.getName(), new String[] {});
+ response = authorize("kolo", "password", resource.getId(), new String[] {});
rpt = response.getToken();
assertNotNull(rpt);
@@ -249,7 +249,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
assertPermissions(permissions, resource.getName());
assertTrue(permissions.isEmpty());
- response = authorize("kolo", "password", resource.getName(), new String[] {});
+ response = authorize("kolo", "password", resource.getId(), new String[] {});
rpt = response.getToken();
assertNotNull(rpt);
@@ -282,7 +282,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
resource = addResource("Resource A", "marta", true, "ScopeA", "ScopeB");
permission.setName(resource.getName() + " Permission");
- permission.addResource(resource.getName());
+ permission.addResource(resource.getId());
permission.addPolicy("Only Owner Policy");
getClient(getRealm()).authorization().permissions().resource().create(permission).close();
@@ -305,7 +305,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
assertTrue(permissions.isEmpty());
try {
- response = authorize("kolo", "password", "Resource A", new String[] {"ScopeA"});
+ response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA"});
fail("User should have access to resource from another user");
} catch (AuthorizationDeniedException ade) {
@@ -324,7 +324,7 @@ public class UserManagedAccessTest extends AbstractResourceServerTest {
permissionResource.update(ticket);
- response = authorize("kolo", "password", resource.getName(), new String[] {"ScopeA", "ScopeB"});
+ response = authorize("kolo", "password", resource.getId(), new String[] {"ScopeA", "ScopeB"});
rpt = response.getToken();
assertNotNull(rpt);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java
index 0ae1117..0dad533 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/AbstractCrossDCTest.java
@@ -377,10 +377,10 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
File dir = new File(cleanServerBaseDir);
if (dir.exists()) {
try {
- FileUtils.cleanDirectory(dir);
+ dir.renameTo(new File(dir.getParentFile(), dir.getName() + "--" + System.currentTimeMillis()));
File deploymentsDir = new File(dir, "deployments");
- deploymentsDir.mkdir();
+ FileUtils.forceMkdir(deploymentsDir);
} catch (IOException ioe) {
throw new RuntimeException("Failed to clean directory: " + cleanServerBaseDir, ioe);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java
index cfd7907..3775e38 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java
@@ -30,6 +30,7 @@ import org.keycloak.representations.AccessToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.util.ClientBuilder;
@@ -48,6 +49,7 @@ import static org.junit.Assert.assertEquals;
public class ServiceAccountTest extends AbstractKeycloakTest {
private static String userId;
+ private static String userName;
@Rule
public AssertEvents events = new AssertEvents(this);
@@ -89,10 +91,11 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
realm.user(defaultUser);
userId = KeycloakModelUtils.generateId();
+ userName = ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + enabledApp.getClientId();
UserBuilder serviceAccountUser = UserBuilder.create()
.id(userId)
- .username(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + enabledApp.getClientId())
+ .username(userName)
.serviceAccountId(enabledApp.getClientId());
realm.user(serviceAccountUser);
@@ -116,7 +119,7 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
.session(accessToken.getSessionState())
.detail(Details.TOKEN_ID, accessToken.getId())
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
- .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl")
+ .detail(Details.USERNAME, userName)
.assertEvent();
assertEquals(accessToken.getSessionState(), refreshToken.getSessionState());
@@ -153,7 +156,7 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
.session(accessToken.getSessionState())
.detail(Details.TOKEN_ID, accessToken.getId())
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
- .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl")
+ .detail(Details.USERNAME, userName)
.detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
.assertEvent();
@@ -246,4 +249,24 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
ClientManager.realm(adminClient.realm("test")).clientId("updated-client").renameTo("service-account-cl");
}
+
+ @Test
+ public void refreshTokenRefreshForDisabledServiceAccount() throws Exception {
+ try {
+ oauth.clientId("service-account-cl");
+ OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("secret1");
+ assertEquals(200, response.getStatusCode());
+
+ ClientManager.realm(adminClient.realm("test")).clientId("service-account-cl").setServiceAccountsEnabled(false);
+
+ response = oauth.doRefreshTokenRequest(response.getRefreshToken(), "secret1");
+ assertEquals(400, response.getStatusCode());
+ }
+ finally {
+ ClientManager.realm(adminClient.realm("test")).clientId("service-account-cl").setServiceAccountsEnabled(true);
+ UserRepresentation user = ClientManager.realm(adminClient.realm("test")).clientId("service-account-cl").getServiceAccountUser();
+ userId = user.getId();
+ userName = user.getUsername();
+ }
+ }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
index 3dfa580..154d659 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
@@ -65,6 +65,12 @@ public class OIDCHybridResponseTypeCodeIDTokenTest extends AbstractOIDCResponseT
Assert.assertNotNull(idToken.getCodeHash());
Assert.assertEquals(idToken.getCodeHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getCode()));
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ // Validate "s_hash"
+ Assert.assertNotNull(idToken.getStateHash());
+ Assert.assertEquals(idToken.getStateHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getState()));
+
// IDToken exchanged for the code
IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
index 132195d..4ceb049 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
@@ -66,6 +66,12 @@ public class OIDCHybridResponseTypeCodeIDTokenTokenTest extends AbstractOIDCResp
Assert.assertNotNull(idToken.getCodeHash());
Assert.assertEquals(idToken.getCodeHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getCode()));
+ // Financial API - Part 2: Read and Write API Security Profile
+ // http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
+ // Validate "s_hash"
+ Assert.assertNotNull(idToken.getStateHash());
+ Assert.assertEquals(idToken.getStateHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getState()));
+
// IDToken exchanged for the code
IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
index 78ec0e7..a3f7e66 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
@@ -71,6 +71,10 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI;
+import static org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper.REQUEST_OBJECT_REQUIRED_REQUEST_URI;
+
/**
* Test for supporting advanced parameters of OIDC specs (max_age, prompt, ...)
*
@@ -376,6 +380,281 @@ public class OIDCAdvancedRequestParamsTest extends AbstractTestRealmKeycloakTest
}
// REQUEST & REQUEST_URI
+
+ @Test
+ public void requestObjectNotRequiredNotProvided() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+
+ // Send request without request object
+ // Assert that the request is accepted
+ OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
+ Assert.assertNotNull(response.getCode());
+ Assert.assertEquals("mystate2", response.getState());
+ assertTrue(appPage.isCurrent());
+ }
+
+ @Test
+ public void requestObjectNotRequiredProvidedInRequestParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object in "request" param
+ oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+ // Assert that the request is accepted
+ OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+ Assert.assertNotNull(response1.getCode());
+ Assert.assertEquals("mystate2", response1.getState());
+ assertTrue(appPage.isCurrent());
+ }
+
+ @Test
+ public void requestObjectNotRequiredProvidedInRequestUriParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object reference in "request_uri" param
+ oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+ // Assert that the request is accepted
+ OAuthClient.AuthorizationEndpointResponse response2 = oauth.doLogin("test-user@localhost", "password");
+ Assert.assertNotNull(response2.getCode());
+ Assert.assertEquals("mystate2", response2.getState());
+ assertTrue(appPage.isCurrent());
+ }
+
+ @Test
+ public void requestObjectRequiredNotProvided() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI);
+ clientResource.update(clientRep);
+
+ // Send request without request object
+ // Assert that the request is not accepted
+ oauth.openLoginForm();
+ Assert.assertTrue(errorPage.isCurrent());
+ assertEquals("Invalid Request", errorPage.getError());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredProvidedInRequestParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object in "request" param
+ oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+ // Assert that the request is accepted
+ OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+ Assert.assertNotNull(response1.getCode());
+ Assert.assertEquals("mystate2", response1.getState());
+ assertTrue(appPage.isCurrent());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredProvidedInRequestUriParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_OR_REQUEST_URI);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object reference in "request_uri" param
+ oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+ // Assert that the request is accepted
+ OAuthClient.AuthorizationEndpointResponse response2 = oauth.doLogin("test-user@localhost", "password");
+ Assert.assertNotNull(response2.getCode());
+ Assert.assertEquals("mystate2", response2.getState());
+ assertTrue(appPage.isCurrent());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredAsRequestParamNotProvided() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST);
+ clientResource.update(clientRep);
+
+ // Send request without request object
+ // Assert that the request is not accepted
+ oauth.openLoginForm();
+ Assert.assertTrue(errorPage.isCurrent());
+ assertEquals("Invalid Request", errorPage.getError());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredAsRequestParamProvidedInRequestParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object in "request" param
+ oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+ // Assert that the request is accepted
+ OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+ Assert.assertNotNull(response1.getCode());
+ Assert.assertEquals("mystate2", response1.getState());
+ assertTrue(appPage.isCurrent());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredAsRequestParamProvidedInRequestUriParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object reference in "request_uri" param
+ oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+ // Assert that the request is accepted
+ oauth.openLoginForm();
+ Assert.assertTrue(errorPage.isCurrent());
+ assertEquals("Invalid Request", errorPage.getError());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredAsRequestUriParamNotProvided() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_URI);
+ clientResource.update(clientRep);
+
+ // Send request without request object
+ // Assert that the request is not accepted
+ oauth.openLoginForm();
+ Assert.assertTrue(errorPage.isCurrent());
+ assertEquals("Invalid Request", errorPage.getError());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredAsRequestUriParamProvidedInRequestParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_URI);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object in "request" param
+ oauth.request(oidcClientEndpointsResource.getOIDCRequest());
+ // Assert that the request is not accepted
+ oauth.openLoginForm();
+ Assert.assertTrue(errorPage.isCurrent());
+ assertEquals("Invalid Request", errorPage.getError());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
+
+ @Test
+ public void requestObjectRequiredAsRequestUriParamProvidedInRequestUriParam() throws Exception {
+ oauth.stateParamHardcoded("mystate2");
+ // Set request object not required for client
+ ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
+ ClientRepresentation clientRep = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(REQUEST_OBJECT_REQUIRED_REQUEST_URI);
+ clientResource.update(clientRep);
+
+ // Set up a request object
+ TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
+ oidcClientEndpointsResource.setOIDCRequest("test", "test-app", oauth.getRedirectUri(), "10", Algorithm.none.toString());
+
+ // Send request object reference in "request_uri" param
+ oauth.requestUri(TestApplicationResourceUrls.clientRequestUri());
+ // Assert that the request is accepted
+ OAuthClient.AuthorizationEndpointResponse response1 = oauth.doLogin("test-user@localhost", "password");
+ Assert.assertNotNull(response1.getCode());
+ Assert.assertEquals("mystate2", response1.getState());
+ assertTrue(appPage.isCurrent());
+
+ // Revert requiring request object for client
+ OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestObjectRequired(null);
+ clientResource.update(clientRep);
+ }
@Test
public void requestParamUnsigned() throws Exception {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
index 6bc7151..eb50949 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
@@ -5,6 +5,7 @@ import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -52,6 +53,12 @@ public class ClientManager {
clientResource.update(app);
}
+ public void setServiceAccountsEnabled(Boolean enabled) {
+ ClientRepresentation app = clientResource.toRepresentation();
+ app.setServiceAccountsEnabled(enabled);
+ clientResource.update(app);
+ }
+
public void updateAttribute(String attribute, String value) {
ClientRepresentation app = clientResource.toRepresentation();
if (app.getAttributes() == null) {
@@ -132,5 +139,9 @@ public class ClientManager {
}
clientResource.update(app);
}
+
+ public UserRepresentation getServiceAccountUser() {
+ return clientResource.getServiceAccountUser();
+ }
}
}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
index f0b2fe5..15d7bf7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
@@ -21,6 +21,7 @@ package org.keycloak.testsuite.x509;
import org.jboss.logging.Logger;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Rule;
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
import org.keycloak.authentication.AuthenticationFlow;
@@ -57,6 +58,7 @@ import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorC
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USER_ATTRIBUTE;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN_CN;
+import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTALTNAME_EMAIL;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_CN;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_EMAIL;
@@ -100,6 +102,27 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
return true;
}
+ @BeforeClass
+ public static void onBeforeTestClass() {
+ if (Boolean.parseBoolean(System.getProperty("auth.server.jboss"))) {
+ String authServerHome = System.getProperty("auth.server.home");
+
+ if (authServerHome != null && System.getProperty("auth.server.ssl.required") != null) {
+ authServerHome = authServerHome + "/standalone/configuration";
+ StringBuilder cliArgs = new StringBuilder();
+
+ cliArgs.append("--ignore-ssl-errors=true ");
+ cliArgs.append("--web-security=false ");
+ cliArgs.append("--ssl-certificates-path=" + authServerHome + "/ca.crt ");
+ cliArgs.append("--ssl-client-certificate-file=" + authServerHome + "/client.crt ");
+ cliArgs.append("--ssl-client-key-file=" + authServerHome + "/client.key ");
+ cliArgs.append("--ssl-client-key-passphrase=secret ");
+
+ System.setProperty("keycloak.phantomjs.cli.args", cliArgs.toString());
+ }
+ }
+ }
+
@Before
public void configureFlows() {
authMgmtResource = adminClient.realms().realm(REALM_NAME).flows();
@@ -301,6 +324,13 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
.setUserIdentityMapperType(USERNAME_EMAIL);
}
+ protected static X509AuthenticatorConfigModel createLoginSubjectAltNameEmail2UsernameOrEmailConfig() {
+ return new X509AuthenticatorConfigModel()
+ .setConfirmationPageAllowed(true)
+ .setMappingSourceType(SUBJECTALTNAME_EMAIL)
+ .setUserIdentityMapperType(USERNAME_EMAIL);
+ }
+
protected static X509AuthenticatorConfigModel createLoginSubjectEmailWithKeyUsage(String keyUsage) {
return createLoginSubjectEmail2UsernameOrEmailConfig()
.setKeyUsage(keyUsage);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginSubjectAltNameEmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginSubjectAltNameEmailTest.java
new file mode 100644
index 0000000..e8cfc37
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginSubjectAltNameEmailTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.x509;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel;
+import org.keycloak.events.Details;
+import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.x509.X509IdentityConfirmationPage;
+
+/**
+ * @author <a href="mailto:brat000012001@gmail.com">Peter Nalyvayko</a>
+ * @version $Revision: 1 $
+ * @date 8/12/2016
+ */
+
+public class X509BrowserLoginSubjectAltNameEmailTest extends AbstractX509AuthenticationTest {
+
+ @Page
+ protected AppPage appPage;
+
+ @Page
+ protected X509IdentityConfirmationPage loginConfirmationPage;
+
+ @Page
+ protected LoginPage loginPage;
+
+ @BeforeClass
+ public static void onBeforeTestClass() {
+ if (Boolean.parseBoolean(System.getProperty("auth.server.jboss"))) {
+ String authServerHome = System.getProperty("auth.server.home");
+
+ if (authServerHome != null && System.getProperty("auth.server.ssl.required") != null) {
+ authServerHome = authServerHome + "/standalone/configuration";
+ StringBuilder cliArgs = new StringBuilder();
+
+ cliArgs.append("--ignore-ssl-errors=true ");
+ cliArgs.append("--web-security=false ");
+ cliArgs.append("--ssl-certificates-path=" + authServerHome + "/ca.crt ");
+ cliArgs.append("--ssl-client-certificate-file=" + authServerHome + "/certs/clients/test-user-san-email@localhost.cert.pem ");
+ cliArgs.append("--ssl-client-key-file=" + authServerHome + "/certs/clients/test-user@localhost.key.pem ");
+ cliArgs.append("--ssl-client-key-passphrase=password");
+
+ System.setProperty("keycloak.phantomjs.cli.args", cliArgs.toString());
+ }
+ }
+ }
+
+ private void login(X509AuthenticatorConfigModel config, String userId, String username, String attemptedUsername) {
+
+ AuthenticatorConfigRepresentation cfg = newConfig("x509-browser-config", config.getConfig());
+ String cfgId = createConfig(browserExecution.getId(), cfg);
+ Assert.assertNotNull(cfgId);
+
+ loginConfirmationPage.open();
+
+ Assert.assertTrue(loginConfirmationPage.getSubjectDistinguishedNameText().equals("CN=test-user, OU=Keycloak, O=Red Hat, L=Boston, ST=MA, C=US"));
+ Assert.assertEquals(username, loginConfirmationPage.getUsernameText());
+
+ loginConfirmationPage.confirm();
+
+ Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+ Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
+
+ events.expectLogin()
+ .user(userId)
+ .detail(Details.USERNAME, attemptedUsername)
+ .removeDetail(Details.REDIRECT_URI)
+ .assertEvent();
+ }
+
+ @Test
+ public void loginAsUserFromCertSubjectEmail() {
+ login(createLoginSubjectAltNameEmail2UsernameOrEmailConfig(), userId, "test-user@localhost", "test-user@localhost");
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
index 2b5c24f..e45dc60 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
@@ -33,18 +33,20 @@
<property name="htmlUnit.version">${htmlUnitBrowserVersion}</property>
<property name="htmlUnitWebClientOptions">cssEnabled=false;historyPageCacheLimit=1</property>
- <!-- phantomjs -->
- <property name="phantomjs.cli.args">${phantomjs.cli.args}</property>
-
<!-- firefox -->
<property name="firefox_binary">${firefox_binary}</property>
<property name="firefoxLogLevel">OFF</property>
<property name="firefoxLegacy">${firefoxLegacyDriver}</property>
<!-- chrome -->
+ <property name="chromeBinary">${chromeBinary}</property>
<property name="chromeArguments">${chromeArguments}</property>
</extension>
+ <extension qualifier="drone">
+ <property name="instantiationTimeoutInSeconds">${droneInstantiationTimeoutInSeconds}</property>
+ </extension>
+
<extension qualifier="graphene">
<property name="waitGuiInterval">5</property>
<property name="waitAjaxInterval">5</property>
@@ -58,7 +60,6 @@
<property name="firefox_binary">${firefox_binary}</property>
<property name="chromeDriverBinary">${webdriver.chrome.driver}</property>
<property name="chromeArguments">${js.chromeArguments}</property>
- <property name="phantomjs.cli.args">${phantomjs.cli.args} --ssl-certificates-path=${client.certificate.ca.path} --ssl-client-certificate-file=${client.certificate.file} --ssl-client-key-file=${client.key.file} --ssl-client-key-passphrase=${client.key.passphrase}</property>
</extension>
<extension qualifier="graphene-secondbrowser">
@@ -383,6 +384,7 @@
-Djboss.node.name=auth-server-${node.name}-cross-dc-0_1
-Dauth.server.truststore=${auth.server.truststore}
-Dauth.server.truststore.password=${auth.server.truststore.password}
+ -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
@@ -408,6 +410,7 @@
-Djboss.node.name=auth-server-${node.name}-cross-dc-0_2-manual
-Dauth.server.truststore=${auth.server.truststore}
-Dauth.server.truststore.password=${auth.server.truststore.password}
+ -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
@@ -434,6 +437,7 @@
-Djboss.node.name=auth-server-${node.name}-cross-dc-1_1
-Dauth.server.truststore=${auth.server.truststore}
-Dauth.server.truststore.password=${auth.server.truststore.password}
+ -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
@@ -459,6 +463,7 @@
-Djboss.node.name=auth-server-${node.name}-cross-dc-1_2-manual
-Dauth.server.truststore=${auth.server.truststore}
-Dauth.server.truststore.password=${auth.server.truststore.password}
+ -Dkeycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled=${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
index 1d60090..5bc4976 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/authorization-test/import-authorization-unordered-settings.json
@@ -61,7 +61,7 @@
"mavenArtifactVersion": "${project.version}",
"mavenArtifactId": "photoz-authz-policy",
"sessionName": "MainOwnerSession",
- "mavenArtifactGroupId": "org.keycloak",
+ "mavenArtifactGroupId": "org.keycloak.testsuite",
"moduleName": "PhotozAuthzOwnerPolicy",
"scannerPeriod": "1",
"scannerPeriodUnit": "Hours"
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl
index 67a494a..e6a96da 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/common/xslt/arquillian.xsl
@@ -65,6 +65,7 @@
<property name="javaVmArguments">
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7901
${app.server.memory.settings}
+ ${app.server.cluster.tests.memory.settings}
-Djava.net.preferIPv4Stack=true
</property>
<property name="managementProtocol">${app.server.management.protocol}</property>
@@ -89,6 +90,7 @@
<property name="javaVmArguments">
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7902
${app.server.memory.settings}
+ ${app.server.cluster.tests.memory.settings}
-Djava.net.preferIPv4Stack=true
</property>
<property name="managementProtocol">${app.server.management.protocol}</property>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java
index 74ec300..eb41e03 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/cluster/EAPSAMLAdapterClusterTest.java
@@ -20,6 +20,7 @@ import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable;
import org.keycloak.testsuite.arquillian.annotation.*;
import java.io.*;
+import java.util.concurrent.TimeoutException;
import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest;
import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
@@ -30,6 +31,7 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.wildfly.extras.creaper.core.*;
import org.wildfly.extras.creaper.core.online.*;
import org.wildfly.extras.creaper.core.online.operations.*;
+import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
/**
@@ -52,13 +54,14 @@ public class EAPSAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
}
@Override
- protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, CliException, NumberFormatException {
+ protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, NumberFormatException, TimeoutException, InterruptedException {
log.infov("Preparing worker node ({0} @ {1})", nodeIndex, managementPort);
OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions
.standalone()
.hostAndPort("localhost", managementPort)
.build());
+ Administration administration = new Administration(clientWorkerNodeClient);
Operations op = new Operations(clientWorkerNodeClient);
Batch b = new Batch();
@@ -86,7 +89,8 @@ public class EAPSAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem"));
op.add(Address.subsystem("keycloak-saml"));
- clientWorkerNodeClient.execute("reload");
+ //clientWorkerNodeClient.execute("reload");
+ administration.reload();
log.infov("Worker node ({0}) Prepared", managementPort);
}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java
index b52a8de..37a7aa6 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/cluster/EAP6SAMLAdapterClusterTest.java
@@ -20,6 +20,7 @@ import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable;
import org.keycloak.testsuite.arquillian.annotation.*;
import java.io.*;
+import java.util.concurrent.TimeoutException;
import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest;
import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
@@ -31,6 +32,7 @@ import org.junit.Assert;
import org.wildfly.extras.creaper.core.*;
import org.wildfly.extras.creaper.core.online.*;
import org.wildfly.extras.creaper.core.online.operations.*;
+import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
import static org.keycloak.testsuite.adapter.AbstractServletsAdapterTest.samlServletDeployment;
@@ -54,7 +56,7 @@ public class EAP6SAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
}
@Override
- protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, CliException, NumberFormatException {
+ protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, NumberFormatException, TimeoutException, InterruptedException {
log.infov("Preparing worker node ({0} @ {1})", nodeIndex, managementPort);
OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions
@@ -62,6 +64,7 @@ public class EAP6SAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
.hostAndPort("localhost", managementPort)
.protocol(ManagementProtocol.REMOTE)
.build());
+ Administration administration = new Administration(clientWorkerNodeClient);
Operations op = new Operations(clientWorkerNodeClient);
Batch b = new Batch();
@@ -94,7 +97,8 @@ public class EAP6SAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTest {
Assert.assertTrue(op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem")).isSuccess());
Assert.assertTrue(op.add(Address.subsystem("keycloak-saml")).isSuccess());
- clientWorkerNodeClient.execute("reload");
+ //clientWorkerNodeClient.execute("reload");
+ administration.reload();
log.infov("Worker node ({0}) Prepared", managementPort);
}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java
index 5735a6a..78f86ae 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/cluster/WildflySAMLAdapterClusterTest.java
@@ -20,6 +20,7 @@ import org.keycloak.testsuite.adapter.page.EmployeeServletDistributable;
import org.keycloak.testsuite.arquillian.annotation.*;
import java.io.*;
+import java.util.concurrent.TimeoutException;
import org.keycloak.testsuite.adapter.servlet.cluster.AbstractSAMLAdapterClusterTest;
import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
@@ -30,6 +31,7 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.wildfly.extras.creaper.core.*;
import org.wildfly.extras.creaper.core.online.*;
import org.wildfly.extras.creaper.core.online.operations.*;
+import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
import static org.keycloak.testsuite.adapter.AbstractServletsAdapterTest.samlServletDeployment;
@@ -53,13 +55,14 @@ public class WildflySAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTes
}
@Override
- protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, CliException, NumberFormatException {
+ protected void prepareWorkerNode(int nodeIndex, Integer managementPort) throws IOException, NumberFormatException, TimeoutException, InterruptedException {
log.infov("Preparing worker node ({0} @ {1})", nodeIndex, managementPort);
OnlineManagementClient clientWorkerNodeClient = ManagementClient.online(OnlineOptions
.standalone()
.hostAndPort("localhost", managementPort)
.build());
+ Administration administration = new Administration(clientWorkerNodeClient);
Operations op = new Operations(clientWorkerNodeClient);
Batch b = new Batch();
@@ -87,7 +90,8 @@ public class WildflySAMLAdapterClusterTest extends AbstractSAMLAdapterClusterTes
op.add(Address.extension("org.keycloak.keycloak-saml-adapter-subsystem"), Values.of("module", "org.keycloak.keycloak-saml-adapter-subsystem"));
op.add(Address.subsystem("keycloak-saml"));
- clientWorkerNodeClient.execute("reload");
+ //clientWorkerNodeClient.execute("reload");
+ administration.reload();
log.infov("Worker node ({0}) Prepared", managementPort);
}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
index f35217c..42cde44 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
@@ -16,7 +16,6 @@
*/
package org.keycloak.testsuite.adapter.example.authorization;
-import org.keycloak.testsuite.adapter.example.authorization.AbstractPhotozExampleAdapterTest;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
/**
diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
index a90ff60..38b6e69 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
@@ -51,6 +51,8 @@
<app.server.management.port.jmx>10199</app.server.management.port.jmx>
<app.server.startup.timeout>60</app.server.startup.timeout>
<app.server.memory.settings>-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</app.server.memory.settings>
+ <!-- Cluster tests are failing with -Xmx512 for insufficient physical memory -->
+ <app.server.cluster.tests.memory.settings>-Xmx384m</app.server.cluster.tests.memory.settings>
<!--debug properties-->
<app.server.debug.port>5006</app.server.debug.port>
@@ -218,6 +220,7 @@
<app.server.startup.timeout>${app.server.startup.timeout}</app.server.startup.timeout>
<app.server.memory.settings>${app.server.memory.settings}</app.server.memory.settings>
+ <app.server.cluster.tests.memory.settings>${app.server.cluster.tests.memory.settings}</app.server.cluster.tests.memory.settings>
<app.server.jboss.jvm.debug.args>${app.server.jboss.jvm.debug.args}</app.server.jboss.jvm.debug.args>
<app.server.reverse-proxy.port.offset>${app.server.reverse-proxy.port.offset}</app.server.reverse-proxy.port.offset>
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
index a1fbb60..0e6501f 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/RulePolicyManagementTest.java
@@ -88,7 +88,7 @@ public class RulePolicyManagementTest extends AbstractAuthorizationSettingsTest
expected.setName(name);
expected.setDescription("description");
- expected.setArtifactGroupId("org.keycloak");
+ expected.setArtifactGroupId("org.keycloak.testsuite");
expected.setArtifactId("photoz-authz-policy");
expected.setArtifactVersion(Version.VERSION);
expected.setModuleName("PhotozAuthzOwnerPolicy");
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 04a9583..ea76512 100755
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -102,15 +102,16 @@
<browser>htmlUnit</browser>
<webdriverDownloadBinaries>true</webdriverDownloadBinaries>
+ <droneInstantiationTimeoutInSeconds>60</droneInstantiationTimeoutInSeconds>
<github.username/>
<github.secretToken/>
<ieDriverArch/>
<js.browser>phantomjs</js.browser>
<js.chromeArguments>--headless</js.chromeArguments>
<htmlUnitBrowserVersion>chrome</htmlUnitBrowserVersion>
- <phantomjs.cli.args>--ignore-ssl-errors=true --web-security=false --ssl-certificates-path=${client.certificate.ca.path} --ssl-client-certificate-file=${client.certificate.file} --ssl-client-key-file=${client.key.file} --ssl-client-key-passphrase=${client.key.passphrase}</phantomjs.cli.args>
<firefox_binary>/usr/bin/firefox</firefox_binary>
<firefoxLegacyDriver>true</firefoxLegacyDriver>
+ <chromeBinary/>
<chromeArguments/>
<frontend.console.output>true</frontend.console.output>
@@ -278,13 +279,14 @@
<js.chromeArguments>${js.chromeArguments}</js.chromeArguments>
<htmlUnitBrowserVersion>${htmlUnitBrowserVersion}</htmlUnitBrowserVersion>
<webdriverDownloadBinaries>${webdriverDownloadBinaries}</webdriverDownloadBinaries>
+ <droneInstantiationTimeoutInSeconds>${droneInstantiationTimeoutInSeconds}</droneInstantiationTimeoutInSeconds>
<github.username>${github.username}</github.username>
<github.secretToken>${github.secretToken}</github.secretToken>
<ieDriverArch>${ieDriverArch}</ieDriverArch>
<firefox_binary>${firefox_binary}</firefox_binary>
- <phantomjs.cli.args>${phantomjs.cli.args}</phantomjs.cli.args>
+ <chromeBinary>${chromeBinary}</chromeBinary>
<chromeArguments>${chromeArguments}</chromeArguments>
<firefoxLegacyDriver>${firefoxLegacyDriver}</firefoxLegacyDriver>
@@ -606,6 +608,8 @@
<auth.server.crossdc11.home>${auth.server.crossdc11.home}</auth.server.crossdc11.home>
<auth.server.crossdc12.home>${auth.server.crossdc12.home}</auth.server.crossdc12.home>
+ <keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>${keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled}</keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>
+
<!--8101-->
<auth.server.crossdc01.port.offset>21</auth.server.crossdc01.port.offset>
<!--8102-->
@@ -656,6 +660,7 @@
<cache.server.jboss>true</cache.server.jboss>
<cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir>
<keycloak.testsuite.logging.pattern>%d{HH:mm:ss,SSS} [%t] %-5p [%c{1.}] %m%n</keycloak.testsuite.logging.pattern>
+ <keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>false</keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>
</properties>
<dependencies>
<dependency>
@@ -728,6 +733,7 @@
<cache.server.jboss>true</cache.server.jboss>
<cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir>
<keycloak.testsuite.logging.pattern>%d{HH:mm:ss,SSS} [%t] %-5p [%c{1.}] %m%n</keycloak.testsuite.logging.pattern>
+ <keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>true</keycloak.connectionsInfinispan.default.remoteStoreSecurityEnabled>
</properties>
<dependencies>
<dependency>
diff --git a/testsuite/integration-deprecated/pom.xml b/testsuite/integration-deprecated/pom.xml
index e9cc992..b47e88a 100755
--- a/testsuite/integration-deprecated/pom.xml
+++ b/testsuite/integration-deprecated/pom.xml
@@ -280,6 +280,11 @@
<artifactId>mariadb-java-client</artifactId>
<version>${mariadb.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-test-apps-servlets</artifactId>
+ <version>4.0.0.CR1-SNAPSHOT</version>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
index 5ac5722..6e1831d 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
@@ -27,7 +27,7 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.util.DocumentUtil;
import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
-import org.keycloak.testsuite.samlfilter.SamlAdapterTest;
+import org.keycloak.testsuite.helper.adapter.SamlKeycloakRule;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
@@ -73,10 +73,10 @@ public class SamlEcpProfileTest {
protected String APP_SERVER_BASE_URL = "http://localhost:8081";
@ClassRule
- public static org.keycloak.testsuite.samlfilter.SamlKeycloakRule keycloakRule = new org.keycloak.testsuite.samlfilter.SamlKeycloakRule() {
+ public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
@Override
public void initWars() {
- ClassLoader classLoader = SamlAdapterTest.class.getClassLoader();
+ ClassLoader classLoader = SamlEcpProfileTest.class.getClassLoader();
initializeSamlSecuredWar("/keycloak-saml/ecp/ecp-sp", "/ecp-sp", "ecp-sp.war", classLoader);
}
diff --git a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index 064d46e..67cc922 100755
--- a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 77a1484..0a0f741 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty81/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index 064d46e..67cc922 100755
--- a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 1f59ff9..5dbfdc0 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty91/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index f1e72a4..9529c0f 100755
--- a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty92/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index f1e72a4..9529c0f 100644
--- a/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index f1e72a4..9529c0f 100644
--- a/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty94/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100644
--- a/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/jetty/jetty94/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/performance/keycloak/pom.xml b/testsuite/performance/keycloak/pom.xml
index f9404d9..2e1d1b5 100644
--- a/testsuite/performance/keycloak/pom.xml
+++ b/testsuite/performance/keycloak/pom.xml
@@ -37,7 +37,7 @@
<properties>
<server.groupId>org.keycloak</server.groupId>
<server.artifactId>keycloak-server-dist</server.artifactId>
- <server.version>${product.version}</server.version>
+ <!-- `server.version` is defined one level up -->
<server.unpacked.folder.name>keycloak-${server.version}</server.unpacked.folder.name>
<server.unpacked.home>${project.build.directory}/${server.unpacked.folder.name}</server.unpacked.home>
testsuite/performance/pom.xml 1(+1 -0)
diff --git a/testsuite/performance/pom.xml b/testsuite/performance/pom.xml
index 089fcd0..5865c06 100644
--- a/testsuite/performance/pom.xml
+++ b/testsuite/performance/pom.xml
@@ -32,6 +32,7 @@
<packaging>pom</packaging>
<properties>
+ <server.version>${product.version}</server.version>
<management.user/>
<management.user.password/>
</properties>
testsuite/performance/README.md 155(+90 -65)
diff --git a/testsuite/performance/README.md b/testsuite/performance/README.md
index 24b12ba..67f01bf 100644
--- a/testsuite/performance/README.md
+++ b/testsuite/performance/README.md
@@ -26,9 +26,8 @@ mvn clean install
# Make sure your Docker daemon is running THEN
mvn verify -Pprovision
-mvn verify -Pgenerate-data -Ddataset=100u -DnumOfWorkers=10 -DhashIterations=100
-mvn verify -Ptest -Ddataset=100u -DusersPerSec=4.5 -DrampUpPeriod=10 -DuserThinkTime=0 -DbadLoginAttempts=1 -DrefreshTokenCount=1 -DmeasurementPeriod=60 -DfilterResults=true
-
+mvn verify -Pgenerate-data -Ddataset=100u2c -DnumOfWorkers=10 -DhashIterations=100
+mvn verify -Ptest -Ddataset=100u2c -DusersPerSec=2 -DrampUpPeriod=10 -DuserThinkTime=0 -DbadLoginAttempts=1 -DrefreshTokenCount=1 -DmeasurementPeriod=60 -DfilterResults=true
```
Now open the generated report in a browser - the link to .html file is displayed at the end of the test.
@@ -40,7 +39,7 @@ mvn verify -Pteardown
You can perform all phases in a single run:
```
-mvn verify -Pprovision,generate-data,test,teardown -Ddataset=100u -DnumOfWorkers=10 -DhashIterations=100 -DusersPerSec=5 -DrampUpPeriod=10
+mvn verify -Pprovision,generate-data,test,teardown -Ddataset=100u2c -DnumOfWorkers=10 -DhashIterations=100 -DusersPerSec=4 -DrampUpPeriod=10
```
Note: The order in which maven profiles are listed does not determine the order in which profile related plugins are executed. `teardown` profile always executes last.
@@ -49,21 +48,44 @@ Keep reading for more information.
## Provisioning
-### Available provisioners:
+### Provision
-- `docker-compose` **Default.** See [`README.docker-compose.md`](README.docker-compose.md) for more details.
+#### Provisioners
-### Provision
+Depending on the target environment different provisioners may be used.
+Provisioner can be selected via property `-Dprovisioner=PROVISIONER`.
-Usage: `mvn verify -Pprovision [-Dprovisioner=<PROVISIONER>] [-D<PARAMETER>=<VALUE>] …`.
+Default value is `docker-compose` which is intended for testing on a local docker host.
+This is currently the only implemented option. See [`README.docker-compose.md`](README.docker-compose.md) for more details.
#### Deployment Types
-- Single node: `mvn verify -Pprovision`
-- Cluster: `mvn verify -Pprovision,cluster [-Dkeycloak.scale=N] [-Dkeycloak.cpusets="cpuset1 cpuset2 … cpusetM"]`. `N ∈ {1 .. M}`.
-- Cross-DC: `mvn verify -Pprovision,crossdc [-Dkeycloak.dc1.scale=K] [-Dkeycloak.dc2.scale=L] [-Dkeycloak.dc1.cpusets=…] [-Dkeycloak.dc2.cpusets=…]`
+Different types of deployment can be provisioned.
+The default deployment is `singlenode` with only a single instance of Keycloak server and a database.
+Additional options are `cluster` and `crossdc` which can be enabled with a profile (see below).
+
+#### Usage
+
+Usage: `mvn verify -P provision[,DEPLOYMENT_PROFILE] [-Dprovisioning.properties=NAMED_PROPERTY_SET]`.
+
+The properties are loaded from `tests/parameters/provisioning/${provisioning.properties}.properties` file.
+Individual parameters can be overriden from command line via `-D` params.
+
+Default property set is `docker-compose/4cpus/singlenode`.
+
+To load a custom properties file specify `-Dprovisioning.properties.file=ABSOLUTE_PATH_TO_FILE` instead of `-Dprovisioning.properties`.
+This file needs to contain all properties required by the specific combination of provisioner and deployment type.
+See examples in folder `tests/parameters/provisioning/docker-compose/4cpus`.
+
+Available parameters are described in [`README.provisioning-parameters.md`](README.provisioning-parameters.md).
+
+#### Examples:
+- Provision a single-node deployment with docker-compose: `mvn verify -P provision`
+- Provision a cluster deployment with docker-compose: `mvn verify -P provision,cluster`
+- Provision a cluster deployment with docker-compose, overriding some properties: `mvn verify -P provision,cluster -Dkeycloak.scale=2 -Dlb.worker.task-max-threads=32`
+- Provision a cross-DC deployment with docker-compose: `mvn verify -P provision,crossdc`
+- Provision a cross-DC deployment with docker-compose using a custom properties file: `mvn verify -P provision,crossdc -Dprovisioning.properties.file=/tmp/custom-crossdc.properties`
-All available parameters are described in [`README.provisioning-parameters.md`](README.provisioning-parameters.md).
#### Provisioned System
@@ -71,8 +93,9 @@ The `provision` operation will produce a `provisioned-system.properties` inside
with information about the provisioned system such as the type of deployment and URLs of Keycloak servers and load balancers.
This information is then used by operations `generate-data`, `import-dump`, `test`, `teardown`.
-Provisioning can be run multiple times with different parameters. The system will be updated/reprovisioned based on the new parameters.
-However when switching between different deployment types (e.g. from `singlenode` to `cluster`) it is always necessary
+Provisioning operation is idempotent for a specific combination of provisioner+deployment.
+When running multiple times the system will be simply updated based on the new parameters.
+However when switching between different provisioiners or deployment types it is **always necessary**
to tear down the currently running system.
**Note:** When switching deployment type from `singlenode` or `cluster` to `crossdc` (or the other way around)
@@ -80,6 +103,13 @@ it is necessary to update the generated Keycloak server configuration (inside `k
adding a `clean` goal to the provisioning command like so: `mvn clean verify -Pprovision …`. It is *not* necessary to update this configuration
when switching between `singlenode` and `cluster` deployments.
+### Collect Artifacts
+
+Usage: `mvn verify -Pcollect`
+
+Collects artifacts such as logs from the provisioned system and stores them in `tests/target/collected-artifacts/${deployment}-TIMESTAMP/`.
+When used in combination with teardown (see below) the artifacts are collected just before the system is torn down.
+
### Teardown
Usage: `mvn verify -Pteardown [-Dprovisioner=<PROVISIONER>]`
@@ -92,18 +122,19 @@ because it contains the `provisioned-system.properties` with information about t
### Generate Test Data
-Usage: `mvn verify -Pgenerate-data [-Ddataset=DATASET] [-D<dataset.property>=<value>]`.
+Usage: `mvn verify -P generate-data [-Ddataset=NAMED_PROPERTY_SET] [-DnumOfWorkers=N]`. The default dataset is `2u2c`. Workers default to `1`.
-Dataset properties are loaded from `datasets/${dataset}.properties` file. Individual properties can be overriden by specifying `-D` params.
+The parameters are loaded from `tests/parameters/datasets/${dataset}.properties` file.
+Individual properties can be overriden from command line via `-D` params.
-Dataset data is first generated as a .json file, and then imported into Keycloak via Admin Client REST API.
+To use a custom properties file specify `-Ddataset.properties.file=ABSOLUTE_PATH_TO_FILE` instead of `-Ddataset`.
-#### Dataset Properties
+#### Dataset Parameters
| Property | Description | Value in the Default Dataset |
| --- | --- | --- |
| `numOfRealms` | Number of realms to be created. | `1` |
-| `usersPerRealm` | Number of users per realm. | `100` |
+| `usersPerRealm` | Number of users per realm. | `2` |
| `clientsPerRealm` | Number of clients per realm. | `2` |
| `realmRoles` | Number of realm-roles per realm. | `2` |
| `realmRolesPerUser` | Number of realm-roles assigned to a created user. Has to be less than or equal to `realmRoles`. | `2` |
@@ -113,53 +144,73 @@ Dataset data is first generated as a .json file, and then imported into Keycloak
#### Examples:
-- `mvn verify -Pgenerate-data` - generate default dataset
-- `mvn verify -Pgenerate-data -DusersPerRealm=5` - generate default dataset, override the `usersPerRealm` property
-- `mvn verify -Pgenerate-data -Ddataset=100u` - generate `100u` dataset
-- `mvn verify -Pgenerate-data -Ddataset=100r/default` - generate dataset based on `datasets/100r/default.properties`
+- Generate the default dataset. `mvn verify -P generate-data`
+- Generate the `100u2c` dataset. `mvn verify -P generate-data -Ddataset=100u2c`
+- Generate the `100u2c` dataset but override some parameters. `mvn verify -P generate-data -Ddataset=100u2c -DclientRolesPerUser=5 -DclientRolesPerClient=5`
+
+#### Export Database
-#### Export / Import Database Dump
+To export the generated data to a data-dump file enable profile `-P export-dump`. This will create a `${DATASET}.sql.gz` file next to the dataset properties file.
-To speed up dataset initialization part, it is possible to pass `-Dexport-dump` option to have the generated dataset
-exported right after it has been generated. Then, if there is a data dump file available then `-Pimport-dump`
-can be used to import the data directly into the database, bypassing Keycloak server completely.
+Example: `mvn verify -P generate-data,export-dump -Ddataset=100u2c`
-**Usage:** `mvn verify -Pimport-dump [-Ddataset=DATASET]`
+#### Import Database
-**For example:**
-- `mvn verify -Pgenerate-data -Ddataset=100u -Dexport-dump` will generate data based on `datasets/100u.properties` and export a database dump to a file: `datasets/100u.sql.gz`.
-- `mvn verify -Pimport-dump -Ddataset=100u` will import the database dump from a file: `datasets/100u.sql.gz`, and reboot the server(s)
+To import data from an existing data-dump file use profile `-P import-dump`.
+
+Example: `mvn verify -P import-dump -Ddataset=100u2c`
+
+If the dump file doesn't exist locally the script will attempt to download it from `${db.dump.download.site}` which defaults to `https://downloads.jboss.org/keycloak-qe/${server.version}`
+with `server.version` defaulting to `${project.version}` from `pom.xml`.
+
+**Warning:** Don't override dataset parameters (with `-Dparam=value`) when running export/import because then the contents of dump file might not match the properties file.
### Run Tests
-Usage: `mvn verify -Ptest[,cluster] [-DtestParameter=value]`.
+Usage: `mvn verify -P test [-Dtest.properties=NAMED_PROPERTY_SET]`. Default property set is `basic-oidc`.
+
+The parameters are loaded from `tests/parameters/test/${test.properties}.properties` file.
+Individual properties can be overriden from command line via `-D` params.
+
+To use a custom properties file specify `-Dtest.properties.file=ABSOLUTE_PATH_TO_FILE` instead of `-Dtest.properties`.
-#### Common Parameters
+When running the tests it is also necessary to define a dataset to use. Usage is described in the section above.
+
+#### Common Test Run Parameters
| Parameter | Description | Default Value |
| --- | --- | --- |
| `gatling.simulationClass` | Classname of the simulation to be run. | `keycloak.BasicOIDCSimulation` |
| `dataset` | Name of the dataset to use. (Individual dataset properties can be overridden with `-Ddataset.property=value`.) | `default` |
-| `usersPerSec` | Arrival rate of new users per second. Can be a floating point number. | `1.0` |
-| `rampUpPeriod` | Period during which the users will be ramped up. (seconds) | `0` |
-| `warmUpPeriod` | Period with steady number of users intended for the system under test to warm up. (seconds) | `0` |
+| `usersPerSec` | Arrival rate of new users per second. Can be a floating point number. | `1.0` for BasicOIDCSimulation, `0.2` for AdminConsoleSimulation |
+| `rampUpPeriod` | Period during which the users will be ramped up. (seconds) | `15` |
+| `warmUpPeriod` | Period with steady number of users intended for the system under test to warm up. (seconds) | `15` |
| `measurementPeriod` | A measurement period after the system is warmed up. (seconds) | `30` |
| `filterResults` | Whether to filter out requests which are outside of the `measurementPeriod`. | `false` |
| `userThinkTime` | Pause between individual scenario steps. | `5` |
| `refreshTokenPeriod`| Period after which token should be refreshed. | `10` |
-#### Addtional Parameters of `keycloak.BasicOIDCSimulation`
+#### Test Run Parameters specific to `BasicOIDCSimulation`
| Parameter | Description | Default Value |
| --- | --- | --- |
| `badLoginAttempts` | | `0` |
| `refreshTokenCount` | | `0` |
+#### Examples:
+
+- Run test with default test and dataset parameters:
+
+`mvn verify -P test`
+
+- Run test specific test and dataset parameters:
-Example:
+`mvn verify -P test -Dtest.properties=basic-oidc -Ddataset=100u2c`
-`mvn verify -Ptest -Dgatling.simulationClass=keycloak.AdminConsoleSimulation -Ddataset=100u -DusersPerSec=1 -DmeasurementPeriod=60 -DuserThinkTime=0 -DrefreshTokenPeriod=15`
+- Run test with specific test and dataset parameters, overriding some from command line:
+
+`mvn verify -P test -Dtest.properties=admin-console -Ddataset=100u2c -DrampUpPeriod=30 -DwarmUpPeriod=60 -DusersPerSec=0.3`
## Monitoring
@@ -202,32 +253,6 @@ To compress the binary output with bzip add `-Dbzip=true` to the commandline.
Results will be stored in folder: `tests/target/sar`.
-## Examples
-
-### Single-node
-
-- Provision single node of KC + DB, generate data, run test, and tear down the provisioned system:
-
- `mvn verify -Pprovision,generate-data,test,teardown -Ddataset=100u -DusersPerSec=5`
-
-- Provision single node of KC + DB, generate data, no test, no teardown:
-
- `mvn verify -Pprovision,generate-data -Ddataset=100u`
-
-- Run test against provisioned system generating 5 new users per second, ramped up over 10 seconds, then tear it down:
-
- `mvn verify -Ptest,teardown -Ddataset=100u -DusersPerSec=5 -DrampUpPeriod=10`
-
-### Cluster
-
-- Provision a 1-node KC cluster + DB, generate data, run test against the provisioned system, then tear it down:
-
- `mvn verify -Pprovision,cluster,generate-data,test,teardown -Ddataset=100u -DusersPerSec=5`
-
-- Provision a 2-node KC cluster + DB, generate data, run test against the provisioned system, then tear it down:
-
- `mvn verify -Pprovision,cluster,generate-data,test,teardown -Dkeycloak.scale=2 -DusersPerRealm=200 -DusersPerSec=5`
-
## Developing tests in IntelliJ IDEA
diff --git a/testsuite/performance/tests/docker-compose.sh b/testsuite/performance/tests/docker-compose.sh
index 68529eb..5c79884 100755
--- a/testsuite/performance/tests/docker-compose.sh
+++ b/testsuite/performance/tests/docker-compose.sh
@@ -366,13 +366,16 @@ case "$OPERATION" in
crossdc) export DB_CONTAINER=${PROJECT_NAME}_mariadb_dc1_1 ;;
*) echo "Deployment '$DEPLOYMENT' doesn't support operation '$OPERATION'." ; exit 1 ;;
esac
- if [ -z "$DATASET" ]; then echo "Operation '$OPERATION' requires DATASET parameter."; exit 1; fi
+ if [ ! -f "$DATASET_PROPERTIES_FILE" ]; then echo "Operation '$OPERATION' requires a valid DATASET_PROPERTIES_FILE parameter."; exit 1; fi
+ DATASET_PROPERTIES_FILENAME=`basename $DATASET_PROPERTIES_FILE`
+ DATASET=${DATASET_PROPERTIES_FILENAME%.properties}
+ echo "DATASET_PROPERTIES_FILE: $DATASET_PROPERTIES_FILE"
echo "DATASET: $DATASET"
echo "Stopping Keycloak services."
runCommand "docker-compose -f $DOCKER_COMPOSE_FILE -p ${PROJECT_NAME} stop $KEYCLOAK_SERVICES"
- cd $PROJECT_BASEDIR/datasets
+ cd `dirname $DATASET_PROPERTIES_FILE`
case "$OPERATION" in
export-dump)
echo "Exporting $DATASET.sql."
@@ -384,7 +387,7 @@ case "$OPERATION" in
import-dump)
DUMP_DOWNLOAD_SITE=${DUMP_DOWNLOAD_SITE:-https://downloads.jboss.org/keycloak-qe}
if [ ! -f "$DATASET.sql.gz" ]; then
- echo "Downloading dump file."
+ echo "Downloading dump file: $DUMP_DOWNLOAD_SITE/$DATASET.sql.gz"
if ! curl -f -O $DUMP_DOWNLOAD_SITE/$DATASET.properties -O $DUMP_DOWNLOAD_SITE/$DATASET.sql.gz ; then
echo Download failed.
exit 1
@@ -409,6 +412,19 @@ case "$OPERATION" in
;;
+ collect)
+ TIMESTAMP=`date +%s`
+ ARTIFACTS_DIR="${PROJECT_BUILD_DIRECTORY}/collected-artifacts/${DEPLOYMENT}-${TIMESTAMP}"
+ SERVICES=`docker-compose -f $DOCKER_COMPOSE_FILE -p ${PROJECT_NAME} config --services`
+ echo "Collecting docker container logs."
+ rm -rf ${ARTIFACTS_DIR}; mkdir -p ${ARTIFACTS_DIR}
+ for SERVICE in ${SERVICES}; do
+ docker logs "${PROJECT_NAME}_${SERVICE}_1" > ${ARTIFACTS_DIR}/${SERVICE}.log 2>&1;
+ if [[ $? != 0 ]]; then echo "ERROR collecting from: ${SERVICE}"; rm ${ARTIFACTS_DIR}/${SERVICE}.log; fi
+ done
+ if [ -z "$(ls -A ${ARTIFACTS_DIR})" ]; then echo "No logs were collected."; rm -rf ${ARTIFACTS_DIR}; fi
+ ;;
+
*)
echo "Unsupported operation: '$OPERATION'"
exit 1
diff --git a/testsuite/performance/tests/parameters/datasets/volume-testing/big.properties b/testsuite/performance/tests/parameters/datasets/volume-testing/big.properties
new file mode 100644
index 0000000..4919199
--- /dev/null
+++ b/testsuite/performance/tests/parameters/datasets/volume-testing/big.properties
@@ -0,0 +1,8 @@
+numOfRealms=200
+usersPerRealm=1000000
+clientsPerRealm=2
+realmRoles=2
+realmRolesPerUser=2
+clientRolesPerUser=2
+clientRolesPerClient=2
+hashIterations=27500
diff --git a/testsuite/performance/tests/parameters/datasets/volume-testing/medium.properties b/testsuite/performance/tests/parameters/datasets/volume-testing/medium.properties
new file mode 100644
index 0000000..b80e841
--- /dev/null
+++ b/testsuite/performance/tests/parameters/datasets/volume-testing/medium.properties
@@ -0,0 +1,8 @@
+numOfRealms=20
+usersPerRealm=10000
+clientsPerRealm=2
+realmRoles=2
+realmRolesPerUser=2
+clientRolesPerUser=2
+clientRolesPerClient=2
+hashIterations=27500
diff --git a/testsuite/performance/tests/parameters/datasets/volume-testing/small.properties b/testsuite/performance/tests/parameters/datasets/volume-testing/small.properties
new file mode 100644
index 0000000..a281f90
--- /dev/null
+++ b/testsuite/performance/tests/parameters/datasets/volume-testing/small.properties
@@ -0,0 +1,8 @@
+numOfRealms=2
+usersPerRealm=1000
+clientsPerRealm=2
+realmRoles=2
+realmRolesPerUser=2
+clientRolesPerUser=2
+clientRolesPerClient=2
+hashIterations=27500
diff --git a/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/cluster.properties b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/cluster.properties
new file mode 100644
index 0000000..d9b1c9d
--- /dev/null
+++ b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/cluster.properties
@@ -0,0 +1,32 @@
+#provisioner=docker-compose
+#deployment=cluster
+
+# Keycloak Settings
+keycloak.scale=1
+keycloak.docker.cpusets=2 3
+keycloak.docker.memlimit=2500m
+keycloak.jvm.memory=-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+keycloak.http.max-connections=50000
+keycloak.ajp.max-connections=50000
+keycloak.worker.io-threads=2
+keycloak.worker.task-max-threads=16
+keycloak.ds.min-pool-size=10
+keycloak.ds.max-pool-size=100
+keycloak.ds.pool-prefill=true
+keycloak.ds.ps-cache-size=100
+
+# Database Settings
+db.docker.cpusets=1
+db.docker.memlimit=2g
+db.max.connections=100
+
+# Load Balancer Settings
+lb.docker.cpusets=1
+lb.docker.memlimit=1500m
+lb.jvm.memory=-Xms64m -Xmx1024m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+lb.http.max-connections=50000
+lb.worker.io-threads=2
+lb.worker.task-max-threads=16
+
+# Monitoring Settings
+monitoring.docker.cpusets=0
diff --git a/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/crossdc.properties b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/crossdc.properties
new file mode 100644
index 0000000..4a5083f
--- /dev/null
+++ b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/crossdc.properties
@@ -0,0 +1,42 @@
+#provisioner=docker-compose
+#deployment=crossdc
+
+# Keycloak Settings
+keycloak.dc1.scale=1
+keycloak.dc2.scale=1
+keycloak.dc1.docker.cpusets=2
+keycloak.dc2.docker.cpusets=3
+keycloak.docker.memlimit=2500m
+keycloak.jvm.memory=-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+keycloak.http.max-connections=50000
+keycloak.ajp.max-connections=50000
+keycloak.worker.io-threads=2
+keycloak.worker.task-max-threads=16
+keycloak.ds.min-pool-size=10
+keycloak.ds.max-pool-size=100
+keycloak.ds.pool-prefill=true
+keycloak.ds.ps-cache-size=100
+
+# Database Settings
+db.dc1.docker.cpusets=1
+db.dc2.docker.cpusets=1
+db.docker.memlimit=2g
+db.max.connections=100
+
+# Load Balancer Settings
+lb.dc1.docker.cpusets=1
+lb.dc2.docker.cpusets=1
+lb.docker.memlimit=1500m
+lb.jvm.memory=-Xms64m -Xmx1024m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+lb.http.max-connections=50000
+lb.worker.io-threads=2
+lb.worker.task-max-threads=16
+
+# Infinispan Settings
+infinispan.dc1.docker.cpusets=1
+infinispan.dc2.docker.cpusets=1
+infinispan.docker.memlimit=1500m
+infinispan.jvm.memory=-Xms64m -Xmx1g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -XX:+DisableExplicitGC
+
+# Monitoring Settings
+monitoring.docker.cpusets=0
diff --git a/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/singlenode.properties b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/singlenode.properties
new file mode 100644
index 0000000..e4a52c0
--- /dev/null
+++ b/testsuite/performance/tests/parameters/provisioning/docker-compose/4cpus/singlenode.properties
@@ -0,0 +1,23 @@
+#provisioner=docker-compose
+#deployment=singlenode
+
+# Keycloak Settings
+keycloak.scale=1
+keycloak.docker.cpusets=2-3
+keycloak.docker.memlimit=2500m
+keycloak.jvm.memory=-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
+keycloak.http.max-connections=50000
+keycloak.worker.io-threads=2
+keycloak.worker.task-max-threads=16
+keycloak.ds.min-pool-size=10
+keycloak.ds.max-pool-size=100
+keycloak.ds.pool-prefill=true
+keycloak.ds.ps-cache-size=100
+
+# Database Settings
+db.docker.cpusets=1
+db.docker.memlimit=2g
+db.max.connections=100
+
+# Monitoring Settings
+monitoring.docker.cpusets=0
diff --git a/testsuite/performance/tests/parameters/test/admin-console.properties b/testsuite/performance/tests/parameters/test/admin-console.properties
new file mode 100644
index 0000000..c3a2773
--- /dev/null
+++ b/testsuite/performance/tests/parameters/test/admin-console.properties
@@ -0,0 +1,8 @@
+gatling.simulationClass=keycloak.AdminConsoleSimulation
+usersPerSec=0.2
+rampUpPeriod=15
+warmUpPeriod=15
+measurementPeriod=30
+filterResults=false
+userThinkTime=0
+refreshTokenPeriod=0
diff --git a/testsuite/performance/tests/parameters/test/basic-oidc.properties b/testsuite/performance/tests/parameters/test/basic-oidc.properties
new file mode 100644
index 0000000..c9a4af0
--- /dev/null
+++ b/testsuite/performance/tests/parameters/test/basic-oidc.properties
@@ -0,0 +1,10 @@
+gatling.simulationClass=keycloak.BasicOIDCSimulation
+usersPerSec=1.0
+rampUpPeriod=15
+warmUpPeriod=15
+measurementPeriod=30
+filterResults=false
+userThinkTime=0
+refreshTokenPeriod=0
+refreshTokenCount=1
+badLoginAttempts=1
testsuite/performance/tests/pom.xml 240(+88 -152)
diff --git a/testsuite/performance/tests/pom.xml b/testsuite/performance/tests/pom.xml
index 37bb52b..e7c70c5 100644
--- a/testsuite/performance/tests/pom.xml
+++ b/testsuite/performance/tests/pom.xml
@@ -32,56 +32,20 @@
<properties>
<provisioner>docker-compose</provisioner>
<deployment>singlenode</deployment>
-
- <provisioned.system.properties.file>${project.build.directory}/provisioned-system.properties</provisioned.system.properties.file>
-
- <!-- Keycloak Server Settings -->
- <keycloak.scale/>
- <keycloak.dc1.scale/>
- <keycloak.dc2.scale/>
- <keycloak.docker.cpusets>2-3</keycloak.docker.cpusets>
- <keycloak.dc1.docker.cpusets>2</keycloak.dc1.docker.cpusets>
- <keycloak.dc2.docker.cpusets>3</keycloak.dc2.docker.cpusets>
- <keycloak.docker.memlimit>2500m</keycloak.docker.memlimit>
- <keycloak.jvm.memory>-Xms64m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</keycloak.jvm.memory>
- <keycloak.http.max-connections>50000</keycloak.http.max-connections>
- <keycloak.ajp.max-connections>50000</keycloak.ajp.max-connections>
- <keycloak.worker.io-threads>2</keycloak.worker.io-threads>
- <keycloak.worker.task-max-threads>16</keycloak.worker.task-max-threads>
- <keycloak.ds.min-pool-size>10</keycloak.ds.min-pool-size>
- <keycloak.ds.max-pool-size>100</keycloak.ds.max-pool-size>
- <keycloak.ds.pool-prefill>true</keycloak.ds.pool-prefill>
- <keycloak.ds.ps-cache-size>100</keycloak.ds.ps-cache-size>
-
- <!-- Database Settings -->
- <db.docker.cpusets>1</db.docker.cpusets>
- <db.dc1.docker.cpusets>1</db.dc1.docker.cpusets>
- <db.dc2.docker.cpusets>1</db.dc2.docker.cpusets>
- <db.docker.memlimit>2g</db.docker.memlimit>
- <db.max.connections>100</db.max.connections>
- <db.dump.download.site>https://downloads.jboss.org/keycloak-qe</db.dump.download.site>
- <!-- Load Balancer Settings -->
- <lb.docker.cpusets>1</lb.docker.cpusets>
- <lb.dc1.docker.cpusets>1</lb.dc1.docker.cpusets>
- <lb.dc2.docker.cpusets>1</lb.dc2.docker.cpusets>
- <lb.docker.memlimit>1500m</lb.docker.memlimit>
- <lb.jvm.memory>-Xms64m -Xmx1024m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</lb.jvm.memory>
- <lb.http.max-connections>50000</lb.http.max-connections>
- <lb.worker.io-threads>2</lb.worker.io-threads>
- <lb.worker.task-max-threads>16</lb.worker.task-max-threads>
-
- <!-- Infinispan Settings -->
- <infinispan.dc1.docker.cpusets>1</infinispan.dc1.docker.cpusets>
- <infinispan.dc2.docker.cpusets>1</infinispan.dc2.docker.cpusets>
- <infinispan.docker.memlimit>1500m</infinispan.docker.memlimit>
- <infinispan.jvm.memory>-Xms64m -Xmx1g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -XX:+DisableExplicitGC</infinispan.jvm.memory>
+ <provisioning.properties>${provisioner}/4cpus/${deployment}</provisioning.properties>
+ <dataset>2u2c</dataset>
+ <test.properties>basic-oidc</test.properties>
- <!-- Monitoring Settings -->
- <monitoring.docker.cpusets>0</monitoring.docker.cpusets>
+ <provisioning.properties.file>${project.basedir}/parameters/provisioning/${provisioning.properties}.properties</provisioning.properties.file>
+ <dataset.properties.file>${project.basedir}/parameters/datasets/${dataset}.properties</dataset.properties.file>
+ <test.properties.file>${project.basedir}/parameters/test/${test.properties}.properties</test.properties.file>
+
+ <provisioned.system.properties.file>${project.build.directory}/provisioned-system.properties</provisioned.system.properties.file>
- <!-- Other -->
- <dataset>default</dataset>
+ <!--other-->
+
+ <db.dump.download.site>https://downloads.jboss.org/keycloak-qe/${server.version}</db.dump.download.site>
<numOfWorkers>1</numOfWorkers>
<maven.compiler.target>1.8</maven.compiler.target>
@@ -207,6 +171,20 @@
<version>1.0.0</version>
<executions>
<execution>
+ <id>read-parameters</id>
+ <phase>initialize</phase>
+ <goals>
+ <goal>read-project-properties</goal>
+ </goals>
+ <configuration>
+ <files>
+ <file>${provisioning.properties.file}</file>
+ <file>${dataset.properties.file}</file>
+ <file>${test.properties.file}</file>
+ </files>
+ </configuration>
+ </execution>
+ <execution>
<id>read-existing-provisioned-system-properties</id>
<phase>initialize</phase>
<goals>
@@ -274,12 +252,11 @@
<skip>${gatling.skip.run}</skip>
<disableCompiler>true</disableCompiler>
<runMultipleSimulations>true</runMultipleSimulations>
- <!--includes>
- <include>keycloak.DemoSimulation2</include>
- </includes-->
<jvmArgs>
+ <!--common params-->
<param>-Dproject.build.directory=${project.build.directory}</param>
<param>-Dkeycloak.server.uris=${keycloak.frontend.servers}</param>
+ <!--dataset params-->
<param>-DnumOfRealms=${numOfRealms}</param>
<param>-DusersPerRealm=${usersPerRealm}</param>
<param>-DclientsPerRealm=${clientsPerRealm}</param>
@@ -288,6 +265,16 @@
<param>-DclientRolesPerUser=${clientRolesPerUser}</param>
<param>-DclientRolesPerClient=${clientRolesPerClient}</param>
<param>-DhashIterations=${hashIterations}</param>
+ <!--test params-->
+ <param>-DusersPerSec=${usersPerSec}</param>
+ <param>-DrampUpPeriod=${rampUpPeriod}</param>
+ <param>-DwarmUpPeriod=${warmUpPeriod}</param>
+ <param>-DmeasurementPeriod=${measurementPeriod}</param>
+ <param>-DfilterResults=${filterResults}</param>
+ <param>-DuserThinkTime=${userThinkTime}</param>
+ <param>-DrefreshTokenPeriod=${refreshTokenPeriod}</param>
+ <param>-DrefreshTokenCount=${refreshTokenCount}</param>
+ <param>-DbadLoginAttempts=${badLoginAttempts}</param>
</jvmArgs>
</configuration>
@@ -314,12 +301,24 @@
<profiles>
<profile>
- <id>docker-compose</id>
- <activation>
- <property>
- <name>!provisioner</name>
- </property>
- </activation>
+ <id>cluster</id>
+ <properties>
+ <deployment>cluster</deployment>
+ </properties>
+ </profile>
+ <profile>
+ <id>crossdc</id>
+ <properties>
+ <deployment>crossdc</deployment>
+ </properties>
+ </profile>
+
+ <profile>
+ <id>provision</id>
+ <properties>
+ <project.basedir>${project.basedir}</project.basedir>
+ <project.build.directory>${project.build.directory}</project.build.directory>
+ </properties>
<build>
<plugins>
<plugin>
@@ -327,58 +326,19 @@
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
- <id>copy-dockerfiles-etc</id>
+ <id>prepare-provisioning</id>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
- <copy todir="${project.build.directory}/docker-compose" overwrite="false" >
- <fileset dir="${project.basedir}/src/main/docker-compose"/>
- </copy>
- <copy todir="${project.build.directory}/docker-compose" overwrite="false" >
- <fileset dir="${project.basedir}/..">
- <include name="db/**"/>
- <include name="monitoring/**"/>
- </fileset>
- </copy>
- <copy todir="${project.build.directory}/docker-compose/infinispan" overwrite="false" >
- <fileset dir="${project.basedir}/../infinispan/target/docker"/>
- </copy>
- <copy todir="${project.build.directory}/docker-compose/load-balancer/wildfly-modcluster" overwrite="false" >
- <fileset dir="${project.basedir}/../load-balancer/wildfly-modcluster/target/docker"/>
- </copy>
- <copy todir="${project.build.directory}/docker-compose/keycloak" overwrite="false" >
- <fileset dir="${project.basedir}/../keycloak/target/docker"/>
- </copy>
+ <ant antfile="prepare-provisioning.xml" target="prepare-${provisioner}" />
</target>
</configuration>
</execution>
</executions>
</plugin>
- </plugins>
- </build>
- </profile>
-
- <profile>
- <id>cluster</id>
- <properties>
- <deployment>cluster</deployment>
- <keycloak.docker.cpusets>2 3</keycloak.docker.cpusets>
- </properties>
- </profile>
- <profile>
- <id>crossdc</id>
- <properties>
- <deployment>crossdc</deployment>
- </properties>
- </profile>
-
- <profile>
- <id>provision</id>
- <build>
- <plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
@@ -466,39 +426,6 @@
</profile>
<profile>
- <id>initialize-dataset-properties</id>
- <activation>
- <property>
- <name>dataset</name>
- </property>
- </activation>
- <build>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>properties-maven-plugin</artifactId>
- <version>1.0.0</version>
- <executions>
- <execution>
- <id>initialize-dataset-properties</id>
- <phase>pre-integration-test</phase>
- <goals>
- <goal>read-project-properties</goal>
- </goals>
- <configuration>
- <files>
- <file>${project.basedir}/datasets/${dataset}.properties</file>
- </files>
- <quiet>true</quiet>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </profile>
-
- <profile>
<id>generate-data</id>
<build>
<plugins>
@@ -560,26 +487,6 @@
<build>
<plugins>
<plugin>
- <artifactId>maven-enforcer-plugin</artifactId>
- <executions>
- <execution>
- <id>enforce-nondefault-dataset</id>
- <goals>
- <goal>enforce</goal>
- </goals>
- <configuration>
- <rules>
- <requireProperty>
- <property>dataset</property>
- <regex>(?!default).*</regex>
- <regexMessage>For the "export-dump" task property "dataset" cannot be set to "default".</regexMessage>
- </requireProperty>
- </rules>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
@@ -595,7 +502,7 @@
<PROVISIONER>${provisioner}</PROVISIONER>
<DEPLOYMENT>${deployment}</DEPLOYMENT>
<OPERATION>export-dump</OPERATION>
- <DATASET>${dataset}</DATASET>
+ <DATASET_PROPERTIES_FILE>${dataset.properties.file}</DATASET_PROPERTIES_FILE>
</environmentVariables>
</configuration>
</execution>
@@ -625,7 +532,7 @@
<PROVISIONER>${provisioner}</PROVISIONER>
<DEPLOYMENT>${deployment}</DEPLOYMENT>
<OPERATION>import-dump</OPERATION>
- <DATASET>${dataset}</DATASET>
+ <DATASET_PROPERTIES_FILE>${dataset.properties.file}</DATASET_PROPERTIES_FILE>
<DUMP_DOWNLOAD_SITE>${db.dump.download.site}</DUMP_DOWNLOAD_SITE>
</environmentVariables>
</configuration>
@@ -644,6 +551,35 @@
</profile>
<profile>
+ <id>collect</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>collect-artifacts</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>./${provisioner}.sh</executable>
+ <environmentVariables>
+ <PROVISIONER>${provisioner}</PROVISIONER>
+ <DEPLOYMENT>${deployment}</DEPLOYMENT>
+ <OPERATION>collect</OPERATION>
+ </environmentVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
<id>teardown</id>
<properties>
<delete.data>true</delete.data>
diff --git a/testsuite/performance/tests/prepare-provisioning.xml b/testsuite/performance/tests/prepare-provisioning.xml
new file mode 100644
index 0000000..3108bac
--- /dev/null
+++ b/testsuite/performance/tests/prepare-provisioning.xml
@@ -0,0 +1,24 @@
+<project name="prepare-provisioning" basedir="." >
+
+ <target name="prepare-docker-compose">
+ <copy todir="${project.build.directory}/docker-compose" overwrite="false" >
+ <fileset dir="${project.basedir}/src/main/docker-compose"/>
+ </copy>
+ <copy todir="${project.build.directory}/docker-compose" overwrite="false" failonerror="true">
+ <fileset dir="${project.basedir}/..">
+ <include name="db/**"/>
+ <include name="monitoring/**"/>
+ </fileset>
+ </copy>
+ <copy todir="${project.build.directory}/docker-compose/infinispan" overwrite="false" failonerror="true">
+ <fileset dir="${project.basedir}/../infinispan/target/docker"/>
+ </copy>
+ <copy todir="${project.build.directory}/docker-compose/load-balancer/wildfly-modcluster" overwrite="false" failonerror="true">
+ <fileset dir="${project.basedir}/../load-balancer/wildfly-modcluster/target/docker"/>
+ </copy>
+ <copy todir="${project.build.directory}/docker-compose/keycloak" overwrite="false" failonerror="true">
+ <fileset dir="${project.basedir}/../keycloak/target/docker"/>
+ </copy>
+ </target>
+
+</project>
diff --git a/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java b/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java
index 288b067..6d2f194 100644
--- a/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java
+++ b/testsuite/performance/tests/src/main/java/org/keycloak/performance/TestConfig.java
@@ -58,9 +58,7 @@ public class TestConfig {
public static final int rampUpPeriod = Integer.getInteger("rampUpPeriod", 0);
public static final int warmUpPeriod = Integer.getInteger("warmUpPeriod", 0);
public static final int measurementPeriod = Integer.getInteger("measurementPeriod", 30);
- public static final boolean rampDownASAP = Boolean.getBoolean("rampDownASAP"); // check for rampdown condition after each scenario step
public static final boolean filterResults = Boolean.getBoolean("filterResults"); // filter out results outside of measurementPeriod
- public static final int pace = Integer.getInteger("pace", 0); // additional dynamic "pause buffer" between scenario loops
public static final int userThinkTime = Integer.getInteger("userThinkTime", 0);
public static final int refreshTokenPeriod = Integer.getInteger("refreshTokenPeriod", 0);
diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index dc3bd09..3c1e745 100755
--- a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -25,7 +25,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 1f59ff9..5dbfdc0 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index b4a6d1c..5b1066c 100755
--- a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -26,7 +26,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/tomcat7/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index 1456496..1324c14 100755
--- a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -26,7 +26,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.helper.adapter.SamlAdapterTestStrategy;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.openqa.selenium.WebDriver;
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
index 124a5ca..8ef9d30 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
index 42a7f77..40dd007 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Error Servlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
index 0be7a74..86b6e6e 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.adapter.servlet.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
index f1cdbea..fcb90a9 100755
--- a/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsernameServlet</servlet-name>
- <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendUsernameServlet</servlet-name>
diff --git a/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml
index 36e0c9e..a4b7254 100755
--- a/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml
+++ b/testsuite/tomcat8/src/test/resources/tomcat-test/webapp/WEB-INF/web.xml
@@ -25,7 +25,7 @@
<servlet>
<servlet-name>SendUsername</servlet-name>
- <servlet-class>org.keycloak.testsuite.TomcatTest$SendUsernameServlet</servlet-class>
+ <servlet-class>org.keycloak.testsuite.helper.adapter.SendUsernameServlet</servlet-class>
</servlet>
<servlet-mapping>
diff --git a/testsuite/utils/src/main/resources/META-INF/keycloak-server.json b/testsuite/utils/src/main/resources/META-INF/keycloak-server.json
index 12ffb33..eb58977 100755
--- a/testsuite/utils/src/main/resources/META-INF/keycloak-server.json
+++ b/testsuite/utils/src/main/resources/META-INF/keycloak-server.json
@@ -94,7 +94,13 @@
"l1Lifespan": "${keycloak.connectionsInfinispan.l1Lifespan:600000}",
"remoteStoreEnabled": "${keycloak.connectionsInfinispan.remoteStoreEnabled:false}",
"remoteStoreHost": "${keycloak.connectionsInfinispan.remoteStoreServer:localhost}",
- "remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}"
+ "remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}",
+ "remoteStoreSecurityEnabled": "${keycloak.connectionsInfinispan.remoteStoreSecurityEnabled:false}",
+ "remoteStoreSecurityServerName": "${keycloak.connectionsInfinispan.remoteStoreSecurityServerName:keycloak-server}",
+ "remoteStoreSecurityRealm": "${keycloak.connectionsInfinispan.remoteStoreSecurityRealm:ApplicationRealm}",
+ "remoteStoreSecurityHotRodEndpoint": "${keycloak.connectionsInfinispan.remoteStoreSecurityHotRodEndpoint}",
+ "remoteStoreSecurityUsername": "${keycloak.connectionsInfinispan.remoteStoreSecurityUsername}",
+ "remoteStoreSecurityPassword": "${keycloak.connectionsInfinispan.remoteStoreSecurityPassword}"
}
},
diff --git a/themes/src/main/resources/theme/base/account/applications.ftl b/themes/src/main/resources/theme/base/account/applications.ftl
index 046df99..0b09256 100755
--- a/themes/src/main/resources/theme/base/account/applications.ftl
+++ b/themes/src/main/resources/theme/base/account/applications.ftl
@@ -28,7 +28,7 @@
<tr>
<td>
<#if application.effectiveUrl?has_content><a href="${application.effectiveUrl}"></#if>
- <#if application.client.name??>${advancedMsg(application.client.name)}<#else>${application.client.clientId}</#if>
+ <#if application.client.name?has_content>${advancedMsg(application.client.name)}<#else>${application.client.clientId}</#if>
<#if application.effectiveUrl?has_content></a></#if>
</td>
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index c384b13..12c5e05 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -309,6 +309,8 @@ user-info-signed-response-alg=User Info Signed Response Algorithm
user-info-signed-response-alg.tooltip=JWA algorithm used for signed User Info Endpoint response. If set to 'unsigned', then User Info Response won't be signed and will be returned in application/json format.
request-object-signature-alg=Request Object Signature Algorithm
request-object-signature-alg.tooltip=JWA algorithm, which client needs to use when sending OIDC request object specified by 'request' or 'request_uri' parameters. If set to 'any', then Request object can be signed by any algorithm (including 'none' ).
+request-object-required=Request Object Required
+request-object-required-alg.tooltip=Specifies if the client needs to provide a request object with their authorization requests, and what method they can use for this. If set to "not required", providing a request object is optional. In all other cases providing a request object is mandatory. If set to "request", the request object must be provided by value. If set to "request_uri", the request object must be provided by reference. If set to "request or request_uri", either method can be used.
fine-saml-endpoint-conf=Fine Grain SAML Endpoint Configuration
fine-saml-endpoint-conf.tooltip=Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service.
assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index 632ef2c..381a4c2 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -891,6 +891,13 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
"none",
"RS256"
];
+
+ $scope.requestObjectRequiredOptions = [
+ "not required",
+ "request or request_uri",
+ "request only",
+ "request_uri only"
+ ];
$scope.realm = realm;
$scope.samlAuthnStatement = false;
@@ -1045,6 +1052,9 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
var attrVal2 = $scope.client.attributes['request.object.signature.alg'];
$scope.requestObjectSignatureAlg = attrVal2==null ? 'any' : attrVal2;
+ var attrVal3 = $scope.client.attributes['request.object.required'];
+ $scope.requestObjectRequired = attrVal3==null ? 'not required' : attrVal3;
+
if ($scope.client.attributes["exclude.session.state.from.auth.response"]) {
if ($scope.client.attributes["exclude.session.state.from.auth.response"] == "true") {
$scope.excludeSessionStateFromAuthResponse = true;
@@ -1143,6 +1153,14 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
$scope.clientEdit.attributes['request.object.signature.alg'] = $scope.requestObjectSignatureAlg;
}
};
+
+ $scope.changeRequestObjectRequired = function() {
+ if ($scope.requestObjectRequired === 'not required') {
+ $scope.clientEdit.attributes['request.object.required'] = null;
+ } else {
+ $scope.clientEdit.attributes['request.object.required'] = $scope.requestObjectRequired;
+ }
+ };
$scope.$watch(function() {
return $location.path();
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index 96e00e9..9352ff1 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -409,6 +409,19 @@
</div>
<kc-tooltip>{{:: 'request-object-signature-alg.tooltip' | translate}}</kc-tooltip>
</div>
+ <div class="form-group clearfix block" data-ng-show="protocol == 'openid-connect'">
+ <label class="col-md-2 control-label" for="changeRequestObjectRequired">{{:: 'request-object-required' | translate}}</label>
+ <div class="col-sm-6">
+ <div>
+ <select class="form-control" id="requestObjectRequired"
+ ng-change="changeRequestObjectRequired()"
+ ng-model="requestObjectRequired"
+ ng-options="sig for sig in requestObjectRequiredOptions">
+ </select>
+ </div>
+ </div>
+ <kc-tooltip>{{:: 'request-object-required.tooltip' | translate}}</kc-tooltip>
+ </div>
</fieldset>
<fieldset data-ng-show="protocol == 'openid-connect'">
diff --git a/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties b/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties
index 61c740b..f18bf47 100644
--- a/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties
+++ b/themes/src/main/resources-community/theme/base/account/messages/messages_fr.properties
@@ -13,7 +13,7 @@ federatedIdentitiesHtmlTitle=Identit\u00e9s f\u00e9d\u00e9r\u00e9es
accountLogHtmlTitle=Acc\u00e8s au compte
changePasswordHtmlTitle=Changer de mot de passe
sessionsHtmlTitle=Sessions
-accountManagementTitle=Gestion de Compte Keycloak
+accountManagementTitle=Gestion du compte Keycloak
authenticatorTitle=Authentification
applicationsHtmlTitle=Applications
@@ -21,9 +21,9 @@ authenticatorCode=Mot de passe unique
email=Courriel
firstName=Pr\u00e9nom
givenName=Pr\u00e9nom
-fullName=Nom Complet
+fullName=Nom complet
lastName=Nom
-familyName=Nom de Famille
+familyName=Nom de famille
password=Mot de passe
passwordConfirm=Confirmation
passwordNew=Nouveau mot de passe
@@ -104,17 +104,17 @@ totpStep2=Ouvrez l''application et scannez le code-barres ou entrez la clef.
totpStep3=Entrez le code \u00e0 usage unique fourni par l''application et cliquez sur Sauvegarder pour terminer.
totpManualStep2=Ouvrez l''application et entrez la clef
-totpManualStep3=Utilisez les valeurs de configuration suivante si l''application les authorise
+totpManualStep3=Utilisez les valeurs de configuration suivante si l''application les autorise
totpUnableToScan=Impossible de scanner ?
-totpScanBarcode=Scanner le code bare?
+totpScanBarcode=Scanner le code-barres ?
totp.totp=Bas\u00e9 sur le temps
totp.hotp=Bas\u00e9 sur un compteur
totpType=Type
totpAlgorithm=Algorithme
-totpDigits=Digits
-totpInterval=Intervale
+totpDigits=Chiffres
+totpInterval=Intervalle
totpCounter=Compteur
missingUsernameMessage=Veuillez entrer votre nom d''utilisateur.