keycloak-aplcache
Changes
connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java 5(+5 -0)
connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java 5(+5 -0)
connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java 5(+5 -0)
distribution/feature-pack-builds/pom.xml 21(+21 -0)
distribution/feature-pack-builds/README.md 25(+25 -0)
distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/assembly.xml 36(+36 -0)
distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/server-provisioning.xml 23(+23 -0)
distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/server-provisioning.xml 23(+23 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/subsystems.xml 15(+15 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/template.xml 85(+85 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/subsystems.xml 17(+17 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/template.xml 81(+81 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/github/relaxng/main/module.xml 37(+37 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/istack/main/module.xml 40(+40 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/bind/main/module.xml 47(+47 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/txw2/main/module.xml 38(+38 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xsom/main/module.xml 39(+39 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/io/netty/main/module.xml 35(+35 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/javax/xml/bind/api/main/module.xml 38(+38 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml 13(+13 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/codec/main/module.xml 36(+36 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/logging/main/module.xml 25(+25 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/httpcomponents/main/module.xml 42(+42 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/james/mime4j/main/module.xml 38(+38 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/bouncycastle/main/module.xml 34(+34 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-core-asl/main/module.xml 36(+36 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-mapper-asl/main/module.xml 38(+38 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-xc/main/module.xml 40(+40 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/xnio/netty/netty-xnio-transport/main/module.xml 39(+39 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/joda/time/main/module.xml 34(+34 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml 20(+20 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml 47(+47 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml 21(+21 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml 17(+17 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml 25(+25 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml 27(+27 -0)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/slf4j/jcl-over-slf4j/main/module.xml 33(+33 -0)
distribution/feature-packs/pom.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml 138(+138 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml 88(+88 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml 35(+35 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml 87(+87 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json 72(+72 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml 13(+13 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml 14(+14 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml 13(+13 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml 13(+13 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml 14(+14 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml 18(+18 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml 24(+24 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml 23(+23 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml 18(+18 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml 21(+21 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml 24(+24 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml 16(+16 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml 18(+18 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml 24(+24 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml 24(+24 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml 25(+25 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml 25(+25 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml 26(+26 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml 18(+18 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml 12(+12 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml 18(+18 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml 26(+26 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml 18(+18 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml 16(+16 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml 18(+18 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml 19(+19 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml 30(+30 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server/main/module.xml 61(+61 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml 52(+52 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml 85(+85 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml 20(+20 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml 22(+22 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml 25(+25 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml 16(+16 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml 17(+17 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml 25(+25 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml 27(+27 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml 15(+15 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml 14(+14 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml 13(+13 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml 13(+13 -0)
distribution/modules/build.xml 7(+5 -2)
distribution/modules/pom.xml 10(+8 -2)
distribution/modules/src/main/resources/modules/org/keycloak/keycloak-adapter-subsystem/main/module.xml 51(+51 -0)
distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml 3(+2 -1)
distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml 2(+1 -1)
distribution/pom.xml 1(+1 -0)
distribution/server-dist/assembly.xml 63(+34 -29)
distribution/server-dist/pom.xml 54(+12 -42)
events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java 83(+61 -22)
examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml 2(+1 -1)
examples/demo-template/pom.xml 21(+21 -0)
examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml 2(+1 -1)
examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProvider.java 40(+39 -1)
examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java 12(+11 -1)
examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java 174(+174 -0)
examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProvider.java 53(+52 -1)
examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProviderFactory.java 17(+15 -2)
forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js 117(+110 -7)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-auth.html 8(+8 -0)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-representation.html 3(+3 -0)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html 5(+3 -2)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html 127(+127 -0)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html 144(+94 -50)
forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/beans/AdminEventBean.java 37(+37 -0)
integration/js/src/main/resources/keycloak.js 24(+12 -12)
integration/keycloak-subsystem/src/main/java/org/keycloak/subsystem/extension/Environment.java 58(+0 -58)
integration/keycloak-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessorEAP6.java 132(+0 -132)
integration/keycloak-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension 1(+0 -1)
integration/pom.xml 4(+1 -3)
integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProvider.java 16(+14 -2)
integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandler.java 27(+11 -16)
integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java 17(+11 -6)
integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponse.java 19(+18 -1)
integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProviderTest.java 18(+15 -3)
integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponseTest.java 1(+1 -0)
integration/wildfly/pom.xml 22(+22 -0)
integration/wildfly/wildfly-adapter/pom.xml 208(+104 -104)
integration/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/SecurityInfoHelper.java 232(+116 -116)
integration/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java 70(+35 -35)
integration/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java 50(+25 -25)
integration/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyRequestAuthenticator.java 274(+137 -137)
integration/wildfly/wildfly-adapter/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension 0(+0 -0)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/CredentialAddHandler.java 8(+2 -6)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/CredentialDefinition.java 3(+1 -2)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/CredentialReadWriteAttributeHandler.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/CredentialRemoveHandler.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java 4(+2 -2)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java 29(+2 -27)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessor.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessorWildFly.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakExtension.java 19(+7 -12)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakSubsystemAdd.java 38(+4 -34)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakSubsystemDefinition.java 6(+2 -4)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakSubsystemParser.java 40(+1 -39)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/RealmAddHandler.java 8(+2 -6)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/RealmDefinition.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/RealmRemoveHandler.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/RealmWriteAttributeHandler.java 8(+1 -7)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentAddHandler.java 8(+2 -6)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentDefinition.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentRemoveHandler.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentWriteAttributeHandler.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/logging/KeycloakLogger.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/java/org/keycloak/subsystem/adapter/logging/KeycloakMessages.java 2(+1 -1)
integration/wildfly/wildfly-adapter-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension 1(+1 -0)
integration/wildfly/wildfly-adapter-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties 27(+3 -24)
integration/wildfly/wildfly-adapter-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd 10(+5 -5)
integration/wildfly/wildfly-adapter-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml 7(+7 -0)
integration/wildfly/wildfly-adapter-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/RealmDefinitionTestCase.java 5(+1 -4)
integration/wildfly/wildfly-adapter-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java 130(+17 -113)
integration/wildfly/wildfly-adapter-subsystem/src/test/resources/org/keycloak/subsystem/adapter/extension/keycloak-1.1.xml 58(+24 -34)
integration/wildfly/wildfly-extensions/src/main/java/org/keycloak/provider/wildfly/ModuleProviderLoaderFactory.java 0(+0 -0)
integration/wildfly/wildfly-extensions/src/main/java/org/keycloak/provider/wildfly/ModuleThemeProviderFactory.java 0(+0 -0)
integration/wildfly/wildfly-extensions/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory 0(+0 -0)
integration/wildfly/wildfly-extensions/src/main/resources/META-INF/services/org.keycloak.provider.ProviderLoaderFactory 0(+0 -0)
integration/wildfly/wildfly-server-subsystem/pom.xml 106(+106 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AbstractAddOverlayHandler.java 78(+31 -47)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AddProviderHandler.java 17(+3 -14)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AuthServerAddHandler.java 9(+2 -7)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AuthServerDefinition.java 8(+3 -5)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AuthServerRemoveHandler.java 4(+2 -2)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AuthServerUtil.java 12(+6 -6)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AuthServerWriteAttributeHandler.java 14(+3 -11)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/KeycloakServerDeploymentProcessor.java 4(+2 -2)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/ListOverlaysHandler.java 4(+1 -3)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/OverlayKeycloakServerJsonHandler.java 2(+1 -1)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/RemoveOverlayHandler.java 14(+8 -6)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java 66(+66 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakDependencyProcessor.java 67(+67 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakDependencyProcessorWildFly.java 12(+7 -5)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java 79(+79 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java 55(+55 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java 45(+45 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java 127(+127 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakLogger.java 39(+39 -0)
integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakMessages.java 34(+34 -0)
integration/wildfly/wildfly-server-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension 1(+1 -0)
integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties 26(+26 -0)
integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd 38(+38 -0)
integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml 30(+30 -0)
integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml 11(+11 -0)
integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java 66(+66 -0)
integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml 6(+6 -0)
misc/UpdatingDatabaseSchema.md 4(+2 -2)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java 5(+5 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java 5(+5 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java 19(+19 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java 25(+25 -0)
pom.xml 208(+200 -8)
services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java 18(+15 -3)
services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java 28(+21 -7)
services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java 372(+190 -182)
services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java 18(+15 -3)
services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java 1005(+554 -451)
services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java 11(+8 -3)
services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java 41(+26 -15)
services/src/main/java/org/keycloak/services/resources/admin/UserClientRoleMappingsResource.java 15(+14 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java 226(+226 -0)
testsuite/wildfly/pom.xml 504(+504 -0)
Details
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java
index e660700..44fb65d 100755
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class IdentityProviderMapperSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
public String getName() {
return "identity-provider-mapper";
}
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java
index de9872a..b507e55 100644
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java
@@ -29,6 +29,11 @@ public class IdentityProviderSpi implements Spi {
public static final String IDENTITY_PROVIDER_SPI_NAME = "identity_provider";
@Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
public String getName() {
return IDENTITY_PROVIDER_SPI_NAME;
}
diff --git a/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java b/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java
index 4558be3..ec64192 100644
--- a/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java
+++ b/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class FileConnectionSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "connectionsFile";
}
diff --git a/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java b/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java
index d9f4228..510b164 100755
--- a/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java
+++ b/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class HttpClientSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "connectionsHttpClient";
}
diff --git a/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java b/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java
index 71f915d..f76c070 100644
--- a/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java
+++ b/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class InfinispanConnectionSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "connectionsInfinispan";
}
diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java
index 83859ab..d565357 100644
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class JpaConnectionSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "connectionsJpa";
}
diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java
index e95242a..c9bd8ee 100644
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class JpaUpdaterSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "connectionsJpaUpdater";
}
diff --git a/connections/jpa/src/main/resources/META-INF/persistence.xml b/connections/jpa/src/main/resources/META-INF/persistence.xml
index 55ff7f0..5bcb77e 100755
--- a/connections/jpa/src/main/resources/META-INF/persistence.xml
+++ b/connections/jpa/src/main/resources/META-INF/persistence.xml
@@ -35,9 +35,10 @@
<class>org.keycloak.models.sessions.jpa.entities.UserSessionEntity</class>
<class>org.keycloak.models.sessions.jpa.entities.UsernameLoginFailureEntity</class>
- <!-- JpaAuditProvider -->
+ <!-- JpaAuditProviders -->
<class>org.keycloak.events.jpa.EventEntity</class>
-
+ <class>org.keycloak.events.jpa.AdminEventEntity</class>
+
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Final.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Final.xml
new file mode 100755
index 0000000..7ee7763
--- /dev/null
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Final.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+ <changeSet author="keycloak" id="1.2.0.Final">
+ <!-- KEYCLOAK-1277 -->
+ <update tableName="CLIENT">
+ <column name="DIRECT_GRANTS_ONLY" valueBoolean="false"/>
+ <where>DIRECT_GRANTS_ONLY is null</where>
+ </update>
+ <update tableName="CLIENT">
+ <column name="BEARER_ONLY" valueBoolean="false"/>
+ <where>BEARER_ONLY is null</where>
+ </update>
+ <update tableName="CLIENT">
+ <column name="SURROGATE_AUTH_REQUIRED" valueBoolean="false"/>
+ <where>SURROGATE_AUTH_REQUIRED is null</where>
+ </update>
+ </changeSet>
+</databaseChangeLog>
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
index 50e8a48..27869eb 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
@@ -6,6 +6,29 @@
<delete tableName="CLIENT_SESSION"/>
<delete tableName="USER_SESSION_NOTE"/>
<delete tableName="USER_SESSION"/>
+ <createTable tableName="ADMIN_EVENT_ENTITY">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="ADMIN_EVENT_TIME" type="BIGINT"/>
+ <column name="REALM_ID" type="VARCHAR(255)"/>
+ <column name="OPERATION_TYPE" type="VARCHAR(255)"/>
+ <column name="AUTH_REALM_ID" type="VARCHAR(255)"/>
+ <column name="AUTH_CLIENT_ID" type="VARCHAR(255)"/>
+ <column name="AUTH_USER_ID" type="VARCHAR(255)"/>
+ <column name="IP_ADDRESS" type="VARCHAR(255)"/>
+ <column name="RESOURCE_PATH" type="VARCHAR(2550)"/>
+ <column name="REPRESENTATION" type="VARCHAR(25500)"/>
+ <column name="ERROR" type="VARCHAR(255)"/>
+ </createTable>
+ <addColumn tableName="REALM">
+ <column name="ADMIN_EVENTS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
+ <constraints nullable="false"/>
+ </column>
+ <column name="ADMIN_EVENTS_DETAILS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
+ <constraints nullable="false"/>
+ </column>
+ </addColumn>
<createTable tableName="CLIENT_SESSION_AUTH_STATUS">
<column name="AUTHENTICATOR" type="VARCHAR(32)">
<constraints nullable="false"/>
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml
index 8272af8..76c4507 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml
@@ -5,5 +5,6 @@
<include file="META-INF/jpa-changelog-1.1.0.Final.xml"/>
<include file="META-INF/jpa-changelog-1.2.0.Beta1.xml"/>
<include file="META-INF/jpa-changelog-1.2.0.CR1.xml"/>
+ <include file="META-INF/jpa-changelog-1.2.0.Final.xml"/>
<include file="META-INF/jpa-changelog-1.3.0.Beta1.xml"/>
</databaseChangeLog>
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java
index 031076d..f391dfd 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class MongoConnectionSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "connectionsMongo";
}
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java
index da89b4d..830aaa3 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class MongoUpdaterSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "connectionsMongoUpdater";
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java
index a88a75d..5b39f7e 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java
@@ -11,6 +11,9 @@ public class RealmEventsConfigRepresentation {
protected Long eventsExpiration;
protected List<String> eventsListeners;
protected List<String> enabledEventTypes;
+
+ protected Boolean adminEventsEnabled;
+ protected Boolean adminEventsDetailsEnabled;
public boolean isEventsEnabled() {
return eventsEnabled;
@@ -43,4 +46,21 @@ public class RealmEventsConfigRepresentation {
public void setEnabledEventTypes(List<String> enabledEventTypes) {
this.enabledEventTypes = enabledEventTypes;
}
+
+ public Boolean isAdminEventsEnabled() {
+ return adminEventsEnabled;
+ }
+
+ public void setAdminEventsEnabled(Boolean adminEventsEnabled) {
+ this.adminEventsEnabled = adminEventsEnabled;
+ }
+
+ public Boolean isAdminEventsDetailsEnabled() {
+ return adminEventsDetailsEnabled;
+ }
+
+ public void setAdminEventsDetailsEnabled(Boolean adminEventsDetailsEnabled) {
+ this.adminEventsDetailsEnabled = adminEventsDetailsEnabled;
+ }
+
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index d9926fe..0240a8d 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -57,10 +57,15 @@ public class RealmRepresentation {
protected String accountTheme;
protected String adminTheme;
protected String emailTheme;
+
protected Boolean eventsEnabled;
protected Long eventsExpiration;
protected List<String> eventsListeners;
protected List<String> enabledEventTypes;
+
+ protected Boolean adminEventsEnabled;
+ protected Boolean adminEventsDetailsEnabled;
+
private List<IdentityProviderRepresentation> identityProviders;
private List<IdentityProviderMapperRepresentation> identityProviderMappers;
private List<ProtocolMapperRepresentation> protocolMappers;
@@ -507,6 +512,22 @@ public class RealmRepresentation {
this.enabledEventTypes = enabledEventTypes;
}
+ public Boolean isAdminEventsEnabled() {
+ return adminEventsEnabled;
+ }
+
+ public void setAdminEventsEnabled(Boolean adminEventsEnabled) {
+ this.adminEventsEnabled = adminEventsEnabled;
+ }
+
+ public Boolean isAdminEventsDetailsEnabled() {
+ return adminEventsDetailsEnabled;
+ }
+
+ public void setAdminEventsDetailsEnabled(Boolean adminEventsDetailsEnabled) {
+ this.adminEventsDetailsEnabled = adminEventsDetailsEnabled;
+ }
+
public List<UserFederationProviderRepresentation> getUserFederationProviders() {
return userFederationProviders;
}
diff --git a/core/src/main/java/org/keycloak/util/SystemEnvProperties.java b/core/src/main/java/org/keycloak/util/SystemEnvProperties.java
new file mode 100644
index 0000000..1e54b52
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/SystemEnvProperties.java
@@ -0,0 +1,25 @@
+package org.keycloak.util;
+
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class SystemEnvProperties extends Properties {
+
+ @Override
+ public String getProperty(String key) {
+ if (key.startsWith("env.")) {
+ return System.getenv().get(key.substring(4));
+ } else {
+ return System.getProperty(key);
+ }
+ }
+
+ @Override
+ public String getProperty(String key, String defaultValue) {
+ String value = getProperty(key);
+ return value != null ? value : defaultValue;
+ }
+
+}
diff --git a/core/src/main/java/org/keycloak/util/SystemPropertiesJsonParserFactory.java b/core/src/main/java/org/keycloak/util/SystemPropertiesJsonParserFactory.java
index 52f893d..a09a91b 100644
--- a/core/src/main/java/org/keycloak/util/SystemPropertiesJsonParserFactory.java
+++ b/core/src/main/java/org/keycloak/util/SystemPropertiesJsonParserFactory.java
@@ -3,6 +3,8 @@ package org.keycloak.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
+import java.util.Map;
+import java.util.Properties;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.io.IOContext;
@@ -16,6 +18,8 @@ import org.codehaus.jackson.util.JsonParserDelegate;
*/
public class SystemPropertiesJsonParserFactory extends MappingJsonFactory {
+ private static final Properties properties = new SystemEnvProperties();
+
@Override
protected JsonParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException {
JsonParser delegate = super._createJsonParser(data, offset, len, ctxt);
@@ -34,8 +38,6 @@ public class SystemPropertiesJsonParserFactory extends MappingJsonFactory {
return new SystemPropertiesAwareJsonParser(delegate);
}
-
-
public static class SystemPropertiesAwareJsonParser extends JsonParserDelegate {
public SystemPropertiesAwareJsonParser(JsonParser d) {
@@ -45,7 +47,7 @@ public class SystemPropertiesJsonParserFactory extends MappingJsonFactory {
@Override
public String getText() throws IOException {
String orig = super.getText();
- return StringPropertyReplacer.replaceProperties(orig);
+ return StringPropertyReplacer.replaceProperties(orig, properties);
}
}
}
diff --git a/distribution/feature-pack-builds/adapter-only/adapter-only-build/assembly.xml b/distribution/feature-pack-builds/adapter-only/adapter-only-build/assembly.xml
new file mode 100644
index 0000000..704449a
--- /dev/null
+++ b/distribution/feature-pack-builds/adapter-only/adapter-only-build/assembly.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014 Red Hat, Inc., and individual 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>thin-server</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>${project.build.finalName}/**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-pack-builds/adapter-only/adapter-only-build/pom.xml b/distribution/feature-pack-builds/adapter-only/adapter-only-build/pom.xml
new file mode 100644
index 0000000..95f05ec
--- /dev/null
+++ b/distribution/feature-pack-builds/adapter-only/adapter-only-build/pom.xml
@@ -0,0 +1,88 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2015 Red Hat, Inc., and individual 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>adapter-only-builds</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-only-build</artifactId>
+
+ <name>Keycloak WildFly Build: Adapter Only</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>server-provisioning</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>server-provisioning.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <workDirectory>${project.build.directory}/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/distribution/feature-pack-builds/adapter-only/adapter-only-build/server-provisioning.xml b/distribution/feature-pack-builds/adapter-only/adapter-only-build/server-provisioning.xml
new file mode 100644
index 0000000..13de0ef
--- /dev/null
+++ b/distribution/feature-pack-builds/adapter-only/adapter-only-build/server-provisioning.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2015 Red Hat, Inc., and individual 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.
+ -->
+<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0">
+ <feature-packs>
+ <!-- uncomment wildfly-feature-pack to build against wildfly full instead of wildfly web -->
+ <!--<feature-pack groupId="org.wildfly" artifactId="wildfly-feature-pack" version="${wildfly.version}"/>-->
+
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
+ </feature-packs>
+</server-provisioning>
\ No newline at end of file
diff --git a/distribution/feature-pack-builds/adapter-only/adapter-only-dist/assembly.xml b/distribution/feature-pack-builds/adapter-only/adapter-only-dist/assembly.xml
new file mode 100644
index 0000000..704449a
--- /dev/null
+++ b/distribution/feature-pack-builds/adapter-only/adapter-only-dist/assembly.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014 Red Hat, Inc., and individual 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>thin-server</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>${project.build.finalName}/**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-pack-builds/adapter-only/adapter-only-dist/pom.xml b/distribution/feature-pack-builds/adapter-only/adapter-only-dist/pom.xml
new file mode 100644
index 0000000..4f1ca1a
--- /dev/null
+++ b/distribution/feature-pack-builds/adapter-only/adapter-only-dist/pom.xml
@@ -0,0 +1,92 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>adapter-only-builds</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-only-dist</artifactId>
+
+ <name>Keycloak WildFly Dist: Adapter Only</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>jboss-release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>server-provisioning</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>server-provisioning.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <workDirectory>${project.build.directory}/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/distribution/feature-pack-builds/adapter-only/adapter-only-dist/server-provisioning.xml b/distribution/feature-pack-builds/adapter-only/adapter-only-dist/server-provisioning.xml
new file mode 100644
index 0000000..b9f46bc
--- /dev/null
+++ b/distribution/feature-pack-builds/adapter-only/adapter-only-dist/server-provisioning.xml
@@ -0,0 +1,25 @@
+ <!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2015 Red Hat, Inc., and individual 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.
+ -->
+<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0" extract-schemas="true" copy-module-artifacts="true">
+ <feature-packs>
+ <!-- uncomment wildfly-feature-pack to build against wildfly full instead of wildfly web -->
+ <!--<feature-pack groupId="org.wildfly" artifactId="wildfly-feature-pack" version="${wildfly.version}"/>-->
+
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
+ </feature-packs>
+</server-provisioning>
\ No newline at end of file
diff --git a/distribution/feature-pack-builds/adapter-only/pom.xml b/distribution/feature-pack-builds/adapter-only/pom.xml
new file mode 100644
index 0000000..bd57e0b
--- /dev/null
+++ b/distribution/feature-pack-builds/adapter-only/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>feature-pack-builds</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <name>Adapter Only Builds</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>adapter-only-builds</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>adapter-feature-pack</module>
+ <module>adapter-only-build</module>
+ <module>adapter-only-dist</module>
+ </modules>
+</project>
distribution/feature-pack-builds/pom.xml 21(+21 -0)
diff --git a/distribution/feature-pack-builds/pom.xml b/distribution/feature-pack-builds/pom.xml
new file mode 100644
index 0000000..a35b3f7
--- /dev/null
+++ b/distribution/feature-pack-builds/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>distribution-pom</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <name>Feature Pack Builds</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>feature-pack-builds</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>adapter-only</module>
+ <module>server-only</module>
+ <module>server-and-adapter</module>
+ </modules>
+</project>
distribution/feature-pack-builds/README.md 25(+25 -0)
diff --git a/distribution/feature-pack-builds/README.md b/distribution/feature-pack-builds/README.md
new file mode 100644
index 0000000..fe4c55a
--- /dev/null
+++ b/distribution/feature-pack-builds/README.md
@@ -0,0 +1,25 @@
+Keycloak Feature Pack Builds
+============================
+
+The feature pack builds rely on WildFly Feature packs to create different combinations
+of Keycloak server/adapter and WildFly web/full.
+
+Types of Builds Created
+--------------------
+The three directories under feature-pack-builds are _adapter-only_, _server-only_, and _server-and-adapter_.
+
+* **adapter-only** - A WildFly server with the Keycloak adapter subsystem added. This build is based on the WildFly Web Feature Pack. **keycloak-adapter-feature-pack** contains all the modules needed to run the Keycloak WildFly Adapter. Therefore, the build is _org.wildfly:wildfly-web-feature-pack_ + _org.keycloak:keycloak-adapter-feature-pack_.
+* **server-only** - A WildFly server with the Keycloak adapter subsystem added. This build is based on the WildFly Full Feature Pack. **keycloak-server-feature-pack** contains all the modules needed to run the Keycloak Server without those already provided by the full WildFly Server. Therefore, the build is _org.wildfly:wildfly-feature-pack_ + _org.keycloak:keycloak-server-feature-pack_.
+* **server-and-adapter** is the same thing as **server-only** except it also includes **keycloak-adapter-feature-pack**. Therefore, the build is _org.wildfly:wildfly-feature-pack_ + _org.keycloak:keycloak-server-feature-pack_ + _org.keycloak:keycloak-adapter-feature-pack_.
+
+Building
+--------
+Each of the three types of builds in turn creates a build version and a dist version.
+
+The build version is a server that uses the new WildFly 9 feature whereby maven artifacts are not bundled with the server. Instead, they are looked up in a repository.
+
+For the dist version, these artifacts are copied into the server itself and no maven repo is required.
+
+By default, the dist version does not get built. To build it, specify the jboss-release profile:
+
+_mvn install -Pjboss-release_
diff --git a/distribution/feature-pack-builds/server-and-adapter/pom.xml b/distribution/feature-pack-builds/server-and-adapter/pom.xml
new file mode 100644
index 0000000..9616217
--- /dev/null
+++ b/distribution/feature-pack-builds/server-and-adapter/pom.xml
@@ -0,0 +1,20 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>feature-pack-builds</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <name>Builds with both server and adapter</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>server-and-adapter</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>server-and-adapter-build</module>
+ <module>server-and-adapter-dist</module>
+ </modules>
+</project>
diff --git a/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/assembly.xml b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/assembly.xml
new file mode 100644
index 0000000..704449a
--- /dev/null
+++ b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/assembly.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014 Red Hat, Inc., and individual 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>thin-server</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>${project.build.finalName}/**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/pom.xml b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/pom.xml
new file mode 100644
index 0000000..2bc3a0a
--- /dev/null
+++ b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/pom.xml
@@ -0,0 +1,93 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>server-and-adapter</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-and-adapter-build</artifactId>
+
+ <name>Keycloak WildFly Build: Server and Adapter</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>server-provisioning</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>server-provisioning.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <workDirectory>${project.build.directory}/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/server-provisioning.xml b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/server-provisioning.xml
new file mode 100644
index 0000000..f83f517
--- /dev/null
+++ b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-build/server-provisioning.xml
@@ -0,0 +1,23 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0">
+ <feature-packs>
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
+ </feature-packs>
+</server-provisioning>
\ No newline at end of file
diff --git a/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/assembly.xml b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/assembly.xml
new file mode 100644
index 0000000..704449a
--- /dev/null
+++ b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/assembly.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014 Red Hat, Inc., and individual 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>thin-server</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>${project.build.finalName}/**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/pom.xml b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/pom.xml
new file mode 100644
index 0000000..4a492fd
--- /dev/null
+++ b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/pom.xml
@@ -0,0 +1,98 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>server-and-adapter</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-and-adapter-dist</artifactId>
+
+ <name>Keycloak WildFly Dist: Server and Adapter</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>jboss-release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>server-provisioning</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>server-provisioning.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <workDirectory>${project.build.directory}/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/server-provisioning.xml b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/server-provisioning.xml
new file mode 100644
index 0000000..83253d7
--- /dev/null
+++ b/distribution/feature-pack-builds/server-and-adapter/server-and-adapter-dist/server-provisioning.xml
@@ -0,0 +1,23 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0" extract-schemas="true" copy-module-artifacts="true">
+ <feature-packs>
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
+ </feature-packs>
+</server-provisioning>
\ No newline at end of file
diff --git a/distribution/feature-pack-builds/server-only/pom.xml b/distribution/feature-pack-builds/server-only/pom.xml
new file mode 100644
index 0000000..af41711
--- /dev/null
+++ b/distribution/feature-pack-builds/server-only/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>feature-pack-builds</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <name>Server Only Builds</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>server-only-builds</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>server-feature-pack</module>
+ <module>server-only-build</module>
+ <module>server-only-dist</module>
+ </modules>
+</project>
diff --git a/distribution/feature-pack-builds/server-only/server-only-build/assembly.xml b/distribution/feature-pack-builds/server-only/server-only-build/assembly.xml
new file mode 100644
index 0000000..704449a
--- /dev/null
+++ b/distribution/feature-pack-builds/server-only/server-only-build/assembly.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014 Red Hat, Inc., and individual 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>thin-server</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>${project.build.finalName}/**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-pack-builds/server-only/server-only-build/pom.xml b/distribution/feature-pack-builds/server-only/server-only-build/pom.xml
new file mode 100644
index 0000000..5d88347
--- /dev/null
+++ b/distribution/feature-pack-builds/server-only/server-only-build/pom.xml
@@ -0,0 +1,87 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>server-only-builds</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-only-build</artifactId>
+
+ <name>Keycloak WildFly Build: Server Only</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>server-provisioning</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>server-provisioning.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <workDirectory>${project.build.directory}/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/distribution/feature-pack-builds/server-only/server-only-build/server-provisioning.xml b/distribution/feature-pack-builds/server-only/server-only-build/server-provisioning.xml
new file mode 100644
index 0000000..9e4b4f3
--- /dev/null
+++ b/distribution/feature-pack-builds/server-only/server-only-build/server-provisioning.xml
@@ -0,0 +1,22 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0">
+ <feature-packs>
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
+ </feature-packs>
+</server-provisioning>
\ No newline at end of file
diff --git a/distribution/feature-pack-builds/server-only/server-only-dist/assembly.xml b/distribution/feature-pack-builds/server-only/server-only-dist/assembly.xml
new file mode 100644
index 0000000..1d7cc51
--- /dev/null
+++ b/distribution/feature-pack-builds/server-only/server-only-dist/assembly.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014 Red Hat, Inc., and individual 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>full-server</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>${project.build.finalName}/**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-pack-builds/server-only/server-only-dist/pom.xml b/distribution/feature-pack-builds/server-only/server-only-dist/pom.xml
new file mode 100644
index 0000000..4f13fbc
--- /dev/null
+++ b/distribution/feature-pack-builds/server-only/server-only-dist/pom.xml
@@ -0,0 +1,92 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>server-only-builds</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-only-dist</artifactId>
+
+ <name>Keycloak WildFly Dist: Server Only</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-feature-pack</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>jboss-release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>server-provisioning</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>server-provisioning.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <workDirectory>${project.build.directory}/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/distribution/feature-pack-builds/server-only/server-only-dist/server-provisioning.xml b/distribution/feature-pack-builds/server-only/server-only-dist/server-provisioning.xml
new file mode 100644
index 0000000..d414b95
--- /dev/null
+++ b/distribution/feature-pack-builds/server-only/server-only-dist/server-provisioning.xml
@@ -0,0 +1,22 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0" extract-schemas="true" copy-module-artifacts="true">
+ <feature-packs>
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
+ </feature-packs>
+</server-provisioning>
\ No newline at end of file
diff --git a/distribution/feature-packs/adapter-feature-pack/assembly.xml b/distribution/feature-packs/adapter-feature-pack/assembly.xml
new file mode 100644
index 0000000..526c08d
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/assembly.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ /*
+ ~ * JBoss, Home of Professional Open Source.
+ ~ * Copyright 2014, Red Hat, Inc., and individual contributors
+ ~ * as indicated by the @author tags. See the copyright.txt file in the
+ ~ * distribution for a full listing of individual contributors.
+ ~ *
+ ~ * This is free software; you can redistribute it and/or modify it
+ ~ * under the terms of the GNU Lesser General Public License as
+ ~ * published by the Free Software Foundation; either version 2.1 of
+ ~ * the License, or (at your option) any later version.
+ ~ *
+ ~ * This software is distributed in the hope that it will be useful,
+ ~ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ * Lesser General Public License for more details.
+ ~ *
+ ~ * You should have received a copy of the GNU Lesser General Public
+ ~ * License along with this software; if not, write to the Free
+ ~ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ ~ */
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>feature-pack</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>target/${project.build.finalName}</directory>
+ <outputDirectory/>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-packs/adapter-feature-pack/feature-pack-build.xml b/distribution/feature-packs/adapter-feature-pack/feature-pack-build.xml
new file mode 100644
index 0000000..e55c8d9
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/feature-pack-build.xml
@@ -0,0 +1,36 @@
+<build xmlns="urn:wildfly:feature-pack-build:1.0">
+ <dependencies>
+ <artifact name="org.wildfly:wildfly-web-feature-pack" />
+ </dependencies>
+ <config>
+ <standalone template="configuration/standalone/template.xml" subsystems="configuration/standalone/subsystems.xml" output-file="standalone/configuration/standalone.xml" />
+ <domain template="configuration/domain/template.xml" subsystems="configuration/domain/subsystems.xml" output-file="domain/configuration/domain.xml" />
+ </config>
+
+ <copy-artifacts>
+ </copy-artifacts>
+ <mkdirs>
+ </mkdirs>
+
+ <file-permissions>
+ <permission value="755">
+ <filter pattern="*.sh" include="true"/>
+ </permission>
+ <permission value="700">
+ <filter pattern="*/tmp/auth" include="true"/>
+ </permission>
+ <permission value="600">
+ <filter pattern="*-users.properties" include="true" />
+ <filter pattern="*/.installation" include="true"/>
+ </permission>
+ </file-permissions>
+ <line-endings>
+ <windows>
+ <filter pattern="*.bat" include="true"/>
+ </windows>
+ <unix>
+ <filter pattern="*.sh" include="true"/>
+ <filter pattern="*.conf" include="true"/>
+ </unix>
+ </line-endings>
+</build>
\ No newline at end of file
diff --git a/distribution/feature-packs/adapter-feature-pack/pom.xml b/distribution/feature-packs/adapter-feature-pack/pom.xml
new file mode 100644
index 0000000..1fa74ff
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/pom.xml
@@ -0,0 +1,176 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>feature-packs-parent</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-feature-pack</artifactId>
+
+ <name>Keycloak Feature Pack: Adapter</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.github.relaxng</groupId>
+ <artifactId>relaxngDatatype</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.istack</groupId>
+ <artifactId>istack-commons-runtime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.istack</groupId>
+ <artifactId>istack-commons-tools</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xml.bind.external</groupId>
+ <artifactId>rngom</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xsom</groupId>
+ <artifactId>xsom</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-runtime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-xjc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>codemodel</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>txw2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.xml.bind</groupId>
+ <artifactId>jboss-jaxb-api_2.2_spec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.xnio.netty</groupId>
+ <artifactId>netty-xnio-transport</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.james</groupId>
+ <artifactId>apache-mime4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adapter-subsystem</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-undertow-adapter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-web-feature-pack</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions></executions>
+ </plugin>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-feature-pack-build-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>feature-pack-build</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>feature-pack-build.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>target/</outputDirectory>
+ <workDirectory>target/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/subsystems.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/subsystems.xml
new file mode 100644
index 0000000..3bff333
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/subsystems.xml
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
+<config>
+ <subsystems name="default">
+ <subsystem>logging.xml</subsystem>
+ <subsystem supplement="web-build">ee.xml</subsystem>
+ <subsystem>io.xml</subsystem>
+ <subsystem>jmx.xml</subsystem>
+ <subsystem supplement="web-build">naming.xml</subsystem>
+ <subsystem>request-controller.xml</subsystem>
+ <subsystem supplement="web-build">security.xml</subsystem>
+ <subsystem>undertow.xml</subsystem>
+ <subsystem>keycloak-adapter.xml</subsystem>
+ </subsystems>
+</config>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/template.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/template.xml
new file mode 100644
index 0000000..33a0ac7
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/domain/template.xml
@@ -0,0 +1,85 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ ~
+ -->
+
+<domain xmlns="urn:jboss:domain:2.1">
+
+ <extensions>
+ <?EXTENSIONS?>
+ </extensions>
+
+ <system-properties>
+ <!-- IPv4 is not required, but setting this helps avoid unintended use of IPv6 -->
+ <property name="java.net.preferIPv4Stack" value="true"/>
+ </system-properties>
+
+ <management>
+ <access-control provider="simple">
+ <role-mapping>
+ <role name="SuperUser">
+ <include>
+ <user name="$local"/>
+ </include>
+ </role>
+ </role-mapping>
+ </access-control>
+ </management>
+
+ <profiles>
+ <profile name="default">
+ <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+ </profile>
+ </profiles>
+
+ <!--
+ Named interfaces that can be referenced elsewhere in the configuration. The configuration
+ for how to associate these logical names with an actual network interface can either
+ be specified here or can be declared on a per-host basis in the equivalent element in host.xml.
+
+ These default configurations require the binding specification to be done in host.xml.
+ -->
+ <interfaces>
+ <interface name="management"/>
+ <interface name="public"/>
+ <interface name="unsecure"/>
+ </interfaces>
+
+ <socket-binding-groups>
+ <socket-binding-group name="standard-sockets" default-interface="public">
+ <!-- Needed for server groups using the 'default' profile -->
+ <?SOCKET-BINDINGS?>
+ </socket-binding-group>
+ </socket-binding-groups>
+
+ <server-groups>
+ <server-group name="main-server-group" profile="default">
+ <jvm name="default">
+ <heap size="64m" max-size="512m"/>
+ </jvm>
+ <socket-binding-group ref="standard-sockets"/>
+ </server-group>
+ </server-groups>
+
+</domain>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/subsystems.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
new file mode 100644
index 0000000..765f018
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
@@ -0,0 +1,17 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
+<config>
+ <subsystems>
+ <subsystem>logging.xml</subsystem>
+ <subsystem>deployment-scanner.xml</subsystem>
+ <subsystem supplement="web-build">ee.xml</subsystem>
+ <subsystem>io.xml</subsystem>
+ <subsystem>jmx.xml</subsystem>
+ <subsystem supplement="web-build">naming.xml</subsystem>
+ <subsystem>request-controller.xml</subsystem>
+ <subsystem supplement="web-build">security.xml</subsystem>
+ <subsystem>security-manager.xml</subsystem>
+ <subsystem>undertow.xml</subsystem>
+ <subsystem>keycloak-adapter.xml</subsystem>
+ </subsystems>
+</config>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/template.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/template.xml
new file mode 100644
index 0000000..d0a8130
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/configuration/standalone/template.xml
@@ -0,0 +1,81 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<server xmlns="urn:jboss:domain:2.0">
+
+ <extensions>
+ <?EXTENSIONS?>
+ </extensions>
+
+ <management>
+ <security-realms>
+ <security-realm name="ManagementRealm">
+ <authentication>
+ <local default-user="$local" />
+ <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
+ </authentication>
+ <authorization map-groups-to-roles="false">
+ <properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
+ </authorization>
+ </security-realm>
+ <security-realm name="ApplicationRealm">
+ <authentication>
+ <local default-user="$local" allowed-users="*" />
+ <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
+ </authentication>
+ <authorization>
+ <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
+ </authorization>
+ </security-realm>
+ </security-realms>
+ <audit-log>
+ <formatters>
+ <json-formatter name="json-formatter"/>
+ </formatters>
+ <handlers>
+ <file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
+ </handlers>
+ <logger log-boot="true" log-read-only="false" enabled="false">
+ <handlers>
+ <handler name="file"/>
+ </handlers>
+ </logger>
+ </audit-log>
+ <management-interfaces>
+ <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
+ <socket-binding http="management-http"/>
+ </http-interface>
+ </management-interfaces>
+ <access-control provider="simple">
+ <role-mapping>
+ <role name="SuperUser">
+ <include>
+ <user name="$local"/>
+ </include>
+ </role>
+ </role-mapping>
+ </access-control>
+ </management>
+
+ <profile>
+
+ <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+
+ </profile>
+
+ <interfaces>
+ <interface name="management">
+ <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+ </interface>
+ <interface name="public">
+ <inet-address value="${jboss.bind.address:127.0.0.1}"/>
+ </interface>
+ </interfaces>
+
+ <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
+ <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
+ <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
+
+ <?SOCKET-BINDINGS?>
+
+ </socket-binding-group>
+</server>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/content/README.md b/distribution/feature-packs/adapter-feature-pack/src/main/resources/content/README.md
new file mode 100644
index 0000000..e7b122b
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/content/README.md
@@ -0,0 +1,2 @@
+This directory intentionally left empty. The Feature Pack plugin barfs if there is no content
+directory. But Git won't save an empty directory. Thus, we need this readme file.
\ No newline at end of file
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/github/relaxng/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/github/relaxng/main/module.xml
new file mode 100644
index 0000000..c4985dd
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/github/relaxng/main/module.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2012, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+
+<module xmlns="urn:jboss:module:1.3" name="com.github.relaxng">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${com.github.relaxng:relaxngDatatype}"/>
+ </resources>
+
+ <dependencies>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/istack/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/istack/main/module.xml
new file mode 100644
index 0000000..e876e16
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/istack/main/module.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="com.sun.istack">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${com.sun.istack:istack-commons-runtime}"/>
+ <artifact name="${com.sun.istack:istack-commons-tools}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.activation.api" />
+ <module name="javax.api" />
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/bind/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/bind/main/module.xml
new file mode 100644
index 0000000..90c2a2a
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/bind/main/module.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="com.sun.xml.bind">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.glassfish.jaxb:jaxb-core}"/>
+ <artifact name="${org.glassfish.jaxb:jaxb-runtime}"/>
+ <artifact name="${org.glassfish.jaxb:jaxb-xjc}"/>
+ <artifact name="${org.glassfish.jaxb:codemodel}"/>
+ <artifact name="${com.sun.xml.bind.external:rngom}"/>
+ </resources>
+
+ <dependencies>
+ <module name="com.github.relaxng" export="true" />
+ <module name="com.sun.istack" export="true" />
+ <module name="com.sun.xml.txw2" export="true" />
+ <module name="com.sun.xsom" export="true" />
+ <module name="javax.api" />
+ <module name="javax.xml.bind.api" />
+ <module name="javax.xml.stream.api" />
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/txw2/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/txw2/main/module.xml
new file mode 100644
index 0000000..8b31f98
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xml/txw2/main/module.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="com.sun.xml.txw2">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.glassfish.jaxb:txw2}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xsom/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xsom/main/module.xml
new file mode 100644
index 0000000..bb0d1bb
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/com/sun/xsom/main/module.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="com.sun.xsom">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${com.sun.xsom:xsom}"/>
+ </resources>
+
+ <dependencies>
+ <module name="com.github.relaxng"/>
+ <module name="javax.api" />
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/io/netty/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/io/netty/main/module.xml
new file mode 100644
index 0000000..f841695
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/io/netty/main/module.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="io.netty">
+ <resources>
+ <artifact name="${io.netty:netty-all}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="sun.jdk"/>
+ <module name="org.javassist" optional="true"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/javax/xml/bind/api/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/javax/xml/bind/api/main/module.xml
new file mode 100644
index 0000000..fdb649f
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/javax/xml/bind/api/main/module.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="javax.xml.bind.api">
+
+
+ <dependencies>
+ <module name="javax.activation.api" export="true"/>
+ <module name="javax.xml.stream.api"/>
+ <module name="com.sun.xml.bind" services="import"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+ <resources>
+ <artifact name="${org.jboss.spec.javax.xml.bind:jboss-jaxb-api_2.2_spec}"/>
+ </resources>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml
new file mode 100644
index 0000000..ba70430
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="net.iharder.base64">
+ <resources>
+ <artifact name="${net.iharder:base64}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/codec/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/codec/main/module.xml
new file mode 100644
index 0000000..cf9cb86
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/codec/main/module.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.apache.commons.codec">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${commons-codec:commons-codec}"/>
+ </resources>
+
+ <dependencies>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/logging/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/logging/main/module.xml
new file mode 100644
index 0000000..f7362e3
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/commons/logging/main/module.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module-alias xmlns="urn:jboss:module:1.3" name="org.apache.commons.logging" target-name="org.slf4j.jcl-over-slf4j"/>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/httpcomponents/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/httpcomponents/main/module.xml
new file mode 100644
index 0000000..39aab46
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/httpcomponents/main/module.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.apache.httpcomponents">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.apache.httpcomponents:httpclient}"/>
+ <artifact name="${org.apache.httpcomponents:httpcore}"/>
+ <artifact name="${org.apache.httpcomponents:httpmime}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.apache.commons.codec"/>
+ <module name="org.apache.commons.logging"/>
+ <module name="org.apache.james.mime4j"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/james/mime4j/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/james/mime4j/main/module.xml
new file mode 100644
index 0000000..95de37e
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/apache/james/mime4j/main/module.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.apache.james.mime4j">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.apache.james:apache-mime4j}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.apache.commons.logging"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/bouncycastle/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/bouncycastle/main/module.xml
new file mode 100644
index 0000000..eaa0557
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/bouncycastle/main/module.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.bouncycastle">
+ <resources>
+ <artifact name="${org.bouncycastle:bcprov-jdk15on}"/>
+ <artifact name="${org.bouncycastle:bcpkix-jdk15on}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-core-asl/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-core-asl/main/module.xml
new file mode 100644
index 0000000..a4e2692
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-core-asl/main/module.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+<module xmlns="urn:jboss:module:1.3" name="org.codehaus.jackson.jackson-core-asl">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.codehaus.jackson:jackson-core-asl}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-mapper-asl/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-mapper-asl/main/module.xml
new file mode 100644
index 0000000..5e62a8a
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-mapper-asl/main/module.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+<module xmlns="urn:jboss:module:1.3" name="org.codehaus.jackson.jackson-mapper-asl">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.codehaus.jackson:jackson-mapper-asl}"/>
+ </resources>
+
+ <dependencies>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.joda.time"/>
+ <module name="javax.api"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-xc/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-xc/main/module.xml
new file mode 100644
index 0000000..25b7520
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/codehaus/jackson/jackson-xc/main/module.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+<module xmlns="urn:jboss:module:1.3" name="org.codehaus.jackson.jackson-xc">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.codehaus.jackson:jackson-xc}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="javax.activation.api"/>
+ <module name="javax.xml.bind.api"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/xnio/netty/netty-xnio-transport/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/xnio/netty/netty-xnio-transport/main/module.xml
new file mode 100644
index 0000000..1f3215d
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/xnio/netty/netty-xnio-transport/main/module.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.jboss.xnio.netty.netty-xnio-transport">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.jboss.xnio.netty:netty-xnio-transport}"/>
+ </resources>
+
+ <dependencies>
+ <module name="io.netty"/>
+ <module name="org.jboss.xnio"/>
+ <module name="org.jboss.xnio.nio"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/joda/time/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/joda/time/main/module.xml
new file mode 100644
index 0000000..c4b1b52
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/joda/time/main/module.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.joda.time">
+
+ <resources>
+ <artifact name="${joda-time:joda-time}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api" />
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml
new file mode 100644
index 0000000..07dcd06
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-adapter-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-adapter-core}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="org.jboss.logging"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="net.iharder.base64"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml
new file mode 100644
index 0000000..f7cd890
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-subsystem/main/module.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-adapter-subsystem">
+
+ <resources>
+ <artifact name="${org.keycloak:keycloak-wildfly-adapter-subsystem}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.jboss.staxmapper"/>
+ <module name="org.jboss.as.controller"/>
+ <module name="org.jboss.as.ee"/>
+ <module name="org.jboss.as.server"/>
+ <module name="org.jboss.modules"/>
+ <module name="org.jboss.msc"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.jboss.vfs"/>
+ <module name="org.jboss.as.web-common" optional="true"/>
+ <module name="org.jboss.as.web" optional="true"/>
+ <module name="org.jboss.as.version" optional="true"/>
+ <module name="org.keycloak.keycloak-wildfly-adapter" optional="true"/>
+ <module name="org.jboss.metadata"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml
new file mode 100644
index 0000000..b23c589
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-core}"/>
+ </resources>
+ <dependencies>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ <module name="javax.activation.api"/>
+ <module name="sun.jdk" optional="true" />
+ <module name="sun.jdk.jgss" optional="true" />
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml
new file mode 100644
index 0000000..6e5b217
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-jboss-adapter-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-jboss-adapter-core}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.picketbox"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml
new file mode 100644
index 0000000..9ba1cb2
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-undertow-adapter">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-undertow-adapter}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.bouncycastle" />
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="javax.servlet.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.jboss.xnio"/>
+ <module name="io.undertow.core"/>
+ <module name="io.undertow.servlet"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml
new file mode 100644
index 0000000..df7cc03
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wildfly-adapter">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-wildfly-adapter}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.bouncycastle" />
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="javax.servlet.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="io.undertow.core"/>
+ <module name="io.undertow.servlet"/>
+ <module name="org.picketbox"/>
+ <module name="org.keycloak.keycloak-undertow-adapter"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.jboss.xnio"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/slf4j/jcl-over-slf4j/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/slf4j/jcl-over-slf4j/main/module.xml
new file mode 100644
index 0000000..c29c8fc
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/layers/base/org/slf4j/jcl-over-slf4j/main/module.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.slf4j.jcl-over-slf4j">
+ <resources>
+ <artifact name="${org.slf4j:jcl-over-slf4j}"/>
+ </resources>
+
+ <dependencies>
+ <module name="org.slf4j"/>
+ </dependencies>
+</module>
distribution/feature-packs/pom.xml 20(+20 -0)
diff --git a/distribution/feature-packs/pom.xml b/distribution/feature-packs/pom.xml
new file mode 100644
index 0000000..dcc6c0c
--- /dev/null
+++ b/distribution/feature-packs/pom.xml
@@ -0,0 +1,20 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>distribution-pom</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <name>Feature Pack Builds</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>feature-packs-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>adapter-feature-pack</module>
+ <module>server-feature-pack</module>
+ </modules>
+</project>
diff --git a/distribution/feature-packs/server-feature-pack/assembly.xml b/distribution/feature-packs/server-feature-pack/assembly.xml
new file mode 100644
index 0000000..eaee2ca
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/assembly.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ /*
+ ~ * JBoss, Home of Professional Open Source.
+ ~ * Copyright 2014, Red Hat, Inc., and individual contributors
+ ~ * as indicated by the @author tags. See the copyright.txt file in the
+ ~ * distribution for a full listing of individual contributors.
+ ~ *
+ ~ * This is free software; you can redistribute it and/or modify it
+ ~ * under the terms of the GNU Lesser General Public License as
+ ~ * published by the Free Software Foundation; either version 2.1 of
+ ~ * the License, or (at your option) any later version.
+ ~ *
+ ~ * This software is distributed in the hope that it will be useful,
+ ~ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ * Lesser General Public License for more details.
+ ~ *
+ ~ * You should have received a copy of the GNU Lesser General Public
+ ~ * License along with this software; if not, write to the Free
+ ~ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ ~ */
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>feature-pack</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <!-- If war is filtered it will get corrupted. Only need to filter module.xml -->
+ <fileSets>
+ <fileSet>
+ <directory>target/${project.build.finalName}</directory>
+ <outputDirectory/>
+ <filtered>true</filtered>
+ <includes>
+ <include>**/module.xml</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>target/${project.build.finalName}</directory>
+ <outputDirectory/>
+ <filtered>false</filtered>
+ <excludes>
+ <exclude>**/module.xml</exclude>
+ </excludes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/distribution/feature-packs/server-feature-pack/feature-pack-build.xml b/distribution/feature-packs/server-feature-pack/feature-pack-build.xml
new file mode 100644
index 0000000..8737c28
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/feature-pack-build.xml
@@ -0,0 +1,39 @@
+<build xmlns="urn:wildfly:feature-pack-build:1.0">
+ <dependencies>
+ <artifact name="org.wildfly:wildfly-feature-pack" />
+ </dependencies>
+ <config>
+ <standalone template="configuration/standalone/template.xml" subsystems="configuration/standalone/subsystems.xml" output-file="standalone/configuration/standalone.xml" />
+ <domain template="configuration/domain/template.xml" subsystems="configuration/domain/subsystems.xml" output-file="domain/configuration/domain.xml" />
+ </config>
+
+ <mkdirs>
+ </mkdirs>
+<!-- <copy-artifacts>
+ <copy-artifact artifact="org.keycloak.subsystem:keycloak-server" to-location="standalone/configuration" extract="true">
+
+ <filter pattern="**/keycloak-server.json" include="true"/>
+ </copy-artifact>
+ </copy-artifacts> -->
+ <file-permissions>
+ <permission value="755">
+ <filter pattern="*.sh" include="true"/>
+ </permission>
+ <permission value="700">
+ <filter pattern="*/tmp/auth" include="true"/>
+ </permission>
+ <permission value="600">
+ <filter pattern="*-users.properties" include="true" />
+ <filter pattern="*/.installation" include="true"/>
+ </permission>
+ </file-permissions>
+ <line-endings>
+ <windows>
+ <filter pattern="*.bat" include="true"/>
+ </windows>
+ <unix>
+ <filter pattern="*.sh" include="true"/>
+ <filter pattern="*.conf" include="true"/>
+ </unix>
+ </line-endings>
+</build>
\ No newline at end of file
diff --git a/distribution/feature-packs/server-feature-pack/pom.xml b/distribution/feature-packs/server-feature-pack/pom.xml
new file mode 100644
index 0000000..c5bfc3e
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/pom.xml
@@ -0,0 +1,149 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>feature-packs-parent</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-server-feature-pack</artifactId>
+
+ <name>Keycloak Feature Pack: Server</name>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-dependencies-server-all</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak.subsystem</groupId>
+ <artifactId>keycloak-server</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-server-subsystem</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-extensions</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-feature-pack</artifactId>
+ <type>zip</type>
+ </dependency>
+
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-undertow-adapter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak.subsystem</groupId>
+ <artifactId>keycloak-server</artifactId>
+ <type>war</type>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions></executions>
+ </plugin>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-feature-pack-build-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>feature-pack-build</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <config-file>feature-pack-build.xml</config-file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>target/</outputDirectory>
+ <workDirectory>target/assembly/work</workDirectory>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.keycloak.subsystem</groupId>
+ <artifactId>keycloak-server</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ <overWrite>true</overWrite>
+ <outputDirectory>${project.build.directory}/${project.build.finalName}/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/auth-server</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
new file mode 100644
index 0000000..2dde48f
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
@@ -0,0 +1,138 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
+<config>
+ <subsystems name="default">
+ <!-- Each subsystem to be included relative to the src/main/resources directory -->
+ <subsystem>logging.xml</subsystem>
+ <subsystem>batch.xml</subsystem>
+ <subsystem>bean-validation.xml</subsystem>
+ <subsystem>keycloak-datasources.xml</subsystem>
+ <subsystem>ee.xml</subsystem>
+ <subsystem>ejb3.xml</subsystem>
+ <subsystem>io.xml</subsystem>
+ <subsystem>infinispan.xml</subsystem>
+ <subsystem>jaxrs.xml</subsystem>
+ <subsystem>jca.xml</subsystem>
+ <subsystem>jdr.xml</subsystem>
+ <subsystem supplement="domain">jmx.xml</subsystem>
+ <subsystem>jpa.xml</subsystem>
+ <subsystem>jsf.xml</subsystem>
+ <subsystem>mail.xml</subsystem>
+ <subsystem>naming.xml</subsystem>
+ <subsystem>pojo.xml</subsystem>
+ <subsystem>remoting.xml</subsystem>
+ <subsystem>resource-adapters.xml</subsystem>
+ <subsystem>request-controller.xml</subsystem>
+ <subsystem>sar.xml</subsystem>
+ <subsystem>security.xml</subsystem>
+ <subsystem>security-manager.xml</subsystem>
+ <subsystem>transactions.xml</subsystem>
+ <subsystem>undertow.xml</subsystem>
+ <subsystem>webservices.xml</subsystem>
+ <subsystem>weld.xml</subsystem>
+ <subsystem>keycloak-server.xml</subsystem>
+ </subsystems>
+ <subsystems name="ha">
+ <!-- Each subsystem to be included relative to the src/main/resources directory -->
+ <subsystem>logging.xml</subsystem>
+ <subsystem>batch.xml</subsystem>
+ <subsystem>bean-validation.xml</subsystem>
+ <subsystem>keycloak-datasources.xml</subsystem>
+ <subsystem>ee.xml</subsystem>
+ <subsystem supplement="ha">ejb3.xml</subsystem>
+ <subsystem>io.xml</subsystem>
+ <subsystem supplement="ha">infinispan.xml</subsystem>
+ <subsystem>jaxrs.xml</subsystem>
+ <subsystem>jca.xml</subsystem>
+ <subsystem>jdr.xml</subsystem>
+ <subsystem>jgroups.xml</subsystem>
+ <subsystem supplement="domain">jmx.xml</subsystem>
+ <subsystem>jpa.xml</subsystem>
+ <subsystem>jsf.xml</subsystem>
+ <subsystem>mail.xml</subsystem>
+ <subsystem>mod_cluster.xml</subsystem>
+ <subsystem>naming.xml</subsystem>
+ <subsystem>pojo.xml</subsystem>
+ <subsystem>remoting.xml</subsystem>
+ <subsystem>resource-adapters.xml</subsystem>
+ <subsystem>request-controller.xml</subsystem>
+ <subsystem>sar.xml</subsystem>
+ <subsystem>security.xml</subsystem>
+ <subsystem>security-manager.xml</subsystem>
+ <subsystem>transactions.xml</subsystem>
+ <subsystem supplement="ha">undertow.xml</subsystem>
+ <subsystem>webservices.xml</subsystem>
+ <subsystem>weld.xml</subsystem>
+ <subsystem>keycloak-server.xml</subsystem>
+ </subsystems>
+ <subsystems name="full">
+ <!-- Each subsystem to be included relative to the src/main/resources directory -->
+ <subsystem>logging.xml</subsystem>
+ <subsystem>batch.xml</subsystem>
+ <subsystem>bean-validation.xml</subsystem>
+ <subsystem>keycloak-datasources.xml</subsystem>
+ <subsystem supplement="full">ee.xml</subsystem>
+ <subsystem supplement="full">ejb3.xml</subsystem>
+ <subsystem>io.xml</subsystem>
+ <subsystem>infinispan.xml</subsystem>
+ <subsystem>iiop-openjdk.xml</subsystem>
+ <subsystem>jaxrs.xml</subsystem>
+ <subsystem>jca.xml</subsystem>
+ <subsystem>jdr.xml</subsystem>
+ <subsystem supplement="domain">jmx.xml</subsystem>
+ <subsystem>jpa.xml</subsystem>
+ <subsystem>jsf.xml</subsystem>
+ <subsystem>jsr77.xml</subsystem>
+ <subsystem>mail.xml</subsystem>
+ <subsystem>messaging.xml</subsystem>
+ <subsystem>naming.xml</subsystem>
+ <subsystem>pojo.xml</subsystem>
+ <subsystem>remoting.xml</subsystem>
+ <subsystem>resource-adapters.xml</subsystem>
+ <subsystem>request-controller.xml</subsystem>
+ <subsystem>sar.xml</subsystem>
+ <subsystem>security.xml</subsystem>
+ <subsystem>security-manager.xml</subsystem>
+ <subsystem>transactions.xml</subsystem>
+ <subsystem>undertow.xml</subsystem>
+ <subsystem>webservices.xml</subsystem>
+ <subsystem>weld.xml</subsystem>
+ <subsystem>keycloak-server.xml</subsystem>
+ </subsystems>
+ <subsystems name="full-ha">
+ <!-- Each subsystem to be included relative to the src/main/resources directory -->
+ <subsystem>logging.xml</subsystem>
+ <subsystem>batch.xml</subsystem>
+ <subsystem>bean-validation.xml</subsystem>
+ <subsystem>keycloak-datasources.xml</subsystem>
+ <subsystem supplement="full">ee.xml</subsystem>
+ <subsystem supplement="full-ha">ejb3.xml</subsystem>
+ <subsystem>io.xml</subsystem>
+ <subsystem supplement="ha">infinispan.xml</subsystem>
+ <subsystem>iiop-openjdk.xml</subsystem>
+ <subsystem>jaxrs.xml</subsystem>
+ <subsystem>jca.xml</subsystem>
+ <subsystem>jdr.xml</subsystem>
+ <subsystem>jgroups.xml</subsystem>
+ <subsystem supplement="domain">jmx.xml</subsystem>
+ <subsystem>jpa.xml</subsystem>
+ <subsystem>jsf.xml</subsystem>
+ <subsystem>jsr77.xml</subsystem>
+ <subsystem>mail.xml</subsystem>
+ <subsystem supplement="ha">messaging.xml</subsystem>
+ <subsystem>mod_cluster.xml</subsystem>
+ <subsystem>naming.xml</subsystem>
+ <subsystem>pojo.xml</subsystem>
+ <subsystem>remoting.xml</subsystem>
+ <subsystem>resource-adapters.xml</subsystem>
+ <subsystem>request-controller.xml</subsystem>
+ <subsystem>sar.xml</subsystem>
+ <subsystem>security.xml</subsystem>
+ <subsystem>security-manager.xml</subsystem>
+ <subsystem>transactions.xml</subsystem>
+ <subsystem supplement="ha">undertow.xml</subsystem>
+ <subsystem>webservices.xml</subsystem>
+ <subsystem>weld.xml</subsystem>
+ <subsystem>keycloak-server.xml</subsystem>
+ </subsystems>
+</config>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml
new file mode 100644
index 0000000..cf3cccc
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml
@@ -0,0 +1,88 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<domain xmlns="urn:jboss:domain:3.0">
+
+ <extensions>
+ <?EXTENSIONS?>
+ </extensions>
+
+ <system-properties>
+ <!-- IPv4 is not required, but setting this helps avoid unintended use of IPv6 -->
+ <property name="java.net.preferIPv4Stack" value="true"/>
+ </system-properties>
+
+ <management>
+ <access-control provider="simple">
+ <role-mapping>
+ <role name="SuperUser">
+ <include>
+ <user name="$local"/>
+ </include>
+ </role>
+ </role-mapping>
+ </access-control>
+ </management>
+
+ <profiles>
+ <profile name="default">
+ <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+ </profile>
+ <profile name="ha">
+ <?SUBSYSTEMS socket-binding-group="ha-sockets"?>
+ </profile>
+ <profile name="full">
+ <?SUBSYSTEMS socket-binding-group="full-sockets"?>
+ </profile>
+ <profile name="full-ha">
+ <?SUBSYSTEMS socket-binding-group="full-ha-sockets"?>
+ </profile>
+ </profiles>
+
+ <!--
+ Named interfaces that can be referenced elsewhere in the configuration. The configuration
+ for how to associate these logical names with an actual network interface can either
+ be specified here or can be declared on a per-host basis in the equivalent element in host.xml.
+
+ These default configurations require the binding specification to be done in host.xml.
+ -->
+ <interfaces>
+ <interface name="management"/>
+ <interface name="public"/>
+ <interface name="unsecure"/>
+ </interfaces>
+
+ <socket-binding-groups>
+ <socket-binding-group name="standard-sockets" default-interface="public">
+ <!-- Needed for server groups using the 'default' profile -->
+ <?SOCKET-BINDINGS?>
+ </socket-binding-group>
+ <socket-binding-group name="ha-sockets" default-interface="public">
+ <!-- Needed for server groups using the 'ha' profile -->
+ <?SOCKET-BINDINGS?>
+ </socket-binding-group>
+ <socket-binding-group name="full-sockets" default-interface="public">
+ <!-- Needed for server groups using the 'full' profile -->
+ <?SOCKET-BINDINGS?>
+ </socket-binding-group>
+ <socket-binding-group name="full-ha-sockets" default-interface="public">
+ <!-- Needed for server groups using the 'full-ha' profile -->
+ <?SOCKET-BINDINGS?>
+ </socket-binding-group>
+ </socket-binding-groups>
+
+ <server-groups>
+ <server-group name="main-server-group" profile="full">
+ <jvm name="default">
+ <heap size="64m" max-size="512m"/>
+ </jvm>
+ <socket-binding-group ref="full-sockets"/>
+ </server-group>
+ <server-group name="other-server-group" profile="full-ha">
+ <jvm name="default">
+ <heap size="64m" max-size="512m"/>
+ </jvm>
+ <socket-binding-group ref="full-ha-sockets"/>
+ </server-group>
+ </server-groups>
+
+</domain>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
new file mode 100644
index 0000000..fad3c38
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
@@ -0,0 +1,35 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
+<config>
+ <subsystems>
+ <subsystem>logging.xml</subsystem>
+ <subsystem>batch.xml</subsystem>
+ <subsystem>bean-validation.xml</subsystem>
+ <subsystem>keycloak-datasources.xml</subsystem>
+ <subsystem>deployment-scanner.xml</subsystem>
+ <subsystem>ee.xml</subsystem>
+ <subsystem>ejb3.xml</subsystem>
+ <subsystem>io.xml</subsystem>
+ <subsystem>infinispan.xml</subsystem>
+ <subsystem>jaxrs.xml</subsystem>
+ <subsystem>jca.xml</subsystem>
+ <subsystem>jdr.xml</subsystem>
+ <subsystem>jmx.xml</subsystem>
+ <subsystem>jpa.xml</subsystem>
+ <subsystem>jsf.xml</subsystem>
+ <subsystem>mail.xml</subsystem>
+ <subsystem>naming.xml</subsystem>
+ <subsystem>pojo.xml</subsystem>
+ <subsystem>remoting.xml</subsystem>
+ <subsystem>resource-adapters.xml</subsystem>
+ <subsystem>request-controller.xml</subsystem>
+ <subsystem>sar.xml</subsystem>
+ <subsystem>security-manager.xml</subsystem>
+ <subsystem>security.xml</subsystem>
+ <subsystem>transactions.xml</subsystem>
+ <subsystem>undertow.xml</subsystem>
+ <subsystem>webservices.xml</subsystem>
+ <subsystem>weld.xml</subsystem>
+ <subsystem>keycloak-server.xml</subsystem>
+ </subsystems>
+</config>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml
new file mode 100644
index 0000000..2260468
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml
@@ -0,0 +1,87 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<server xmlns="urn:jboss:domain:3.0">
+
+ <extensions>
+ <?EXTENSIONS?>
+ </extensions>
+
+ <management>
+ <security-realms>
+ <security-realm name="ManagementRealm">
+ <authentication>
+ <local default-user="$local" skip-group-loading="true" />
+ <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
+ </authentication>
+ <authorization map-groups-to-roles="false">
+ <properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
+ </authorization>
+ </security-realm>
+ <security-realm name="ApplicationRealm">
+ <authentication>
+ <local default-user="$local" allowed-users="*" skip-group-loading="true" />
+ <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
+ </authentication>
+ <authorization>
+ <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
+ </authorization>
+ </security-realm>
+ </security-realms>
+ <audit-log>
+ <formatters>
+ <json-formatter name="json-formatter"/>
+ </formatters>
+ <handlers>
+ <file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
+ </handlers>
+ <logger log-boot="true" log-read-only="false" enabled="false">
+ <handlers>
+ <handler name="file"/>
+ </handlers>
+ </logger>
+ </audit-log>
+ <management-interfaces>
+ <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
+ <socket-binding http="management-http"/>
+ </http-interface>
+ </management-interfaces>
+ <access-control provider="simple">
+ <role-mapping>
+ <role name="SuperUser">
+ <include>
+ <user name="$local"/>
+ </include>
+ </role>
+ </role-mapping>
+ </access-control>
+ </management>
+
+ <profile>
+
+ <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+
+ </profile>
+
+ <interfaces>
+ <interface name="management">
+ <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+ </interface>
+ <interface name="public">
+ <inet-address value="${jboss.bind.address:127.0.0.1}"/>
+ </interface>
+ <!-- TODO - only show this if the jacorb subsystem is added -->
+ <interface name="unsecure">
+ <!-- Used for IIOP sockets in the standard configuration.
+ To secure JacORB you need to setup SSL -->
+ <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/>
+ </interface>
+ </interfaces>
+
+ <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
+ <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
+ <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
+
+ <?SOCKET-BINDINGS?>
+
+ </socket-binding-group>
+</server>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json b/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json
new file mode 100644
index 0000000..9f0d03e
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json
@@ -0,0 +1,72 @@
+{
+ "admin": {
+ "realm": "master"
+ },
+
+ "eventsStore": {
+ "provider": "jpa",
+ "jpa": {
+ "exclude-events": [ "REFRESH_TOKEN" ]
+ }
+ },
+
+ "realm": {
+ "provider": "jpa"
+ },
+
+ "user": {
+ "provider": "jpa"
+ },
+
+ "userSessions": {
+ "provider" : "mem"
+ },
+
+ "realmCache": {
+ "provider": "mem"
+ },
+
+ "userCache": {
+ "provider": "mem",
+ "mem": {
+ "maxSize": 20000
+ }
+ },
+
+ "timer": {
+ "provider": "basic"
+ },
+
+ "theme": {
+ "default": "keycloak",
+ "staticMaxAge": 2592000,
+ "cacheTemplates": true,
+ "cacheThemes": true,
+ "folder": {
+ "dir": "${jboss.server.config.dir}/themes"
+ }
+ },
+
+ "login": {
+ "provider": "freemarker"
+ },
+
+ "account": {
+ "provider": "freemarker"
+ },
+
+ "email": {
+ "provider": "freemarker"
+ },
+
+ "scheduled": {
+ "interval": 900
+ },
+
+ "connectionsJpa": {
+ "default": {
+ "dataSource": "java:jboss/datasources/KeycloakDS",
+ "databaseSchema": "update"
+ }
+ }
+}
\ No newline at end of file
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml
new file mode 100644
index 0000000..cc18aaa
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/core/main/module.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="com.google.zxing.core">
+ <resources>
+ <artifact name="${com.google.zxing:core}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml
new file mode 100644
index 0000000..b73ba9b
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/com/google/zxing/javase/main/module.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="com.google.zxing.javase">
+ <resources>
+ <artifact name="${com.google.zxing:javase}"/>
+ </resources>
+ <dependencies>
+ <module name="com.google.zxing.core"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml
new file mode 100644
index 0000000..10f1103
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="de.idyl.winzipaes">
+ <resources>
+ <!-- Insert resources here -->
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml
new file mode 100644
index 0000000..ba70430
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/net/iharder/base64/main/module.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="net.iharder.base64">
+ <resources>
+ <artifact name="${net.iharder:base64}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml
new file mode 100644
index 0000000..2043bef
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/freemarker/main/module.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.freemarker">
+ <resources>
+ <artifact name="${org.freemarker:freemarker}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.apache.log4j"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml
new file mode 100644
index 0000000..d36887e
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-api/main/module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-account-api">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-account-api}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml
new file mode 100644
index 0000000..1512a9e
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-account-freemarker/main/module.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-account-freemarker">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-account-freemarker}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-forms-common-freemarker"/>
+ <module name="org.keycloak.keycloak-account-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.freemarker"/>
+ <module name="javax.api"/>
+ <module name="javax.ws.rs.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml
new file mode 100644
index 0000000..07dcd06
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-adapter-core/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-adapter-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-adapter-core}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="org.jboss.logging"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="net.iharder.base64"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml
new file mode 100644
index 0000000..f983726
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-core/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-broker-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-broker-core}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml
new file mode 100644
index 0000000..1a75cd1
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-oidc/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-broker-oidc">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-broker-oidc}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.ws.rs.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml
new file mode 100644
index 0000000..839d9f9
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-broker-saml/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-broker-saml">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-broker-saml}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api" />
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-saml-core"/>
+ <module name="org.keycloak.keycloak-saml-protocol"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.ws.rs.api"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml
new file mode 100644
index 0000000..ef1f1b2
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-file/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-file">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-connections-file}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-export-import-api"/>
+ <module name="org.keycloak.keycloak-export-import-single-file"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml
new file mode 100755
index 0000000..f52288e
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-http-client/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-http-client">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-connections-http-client}"/>
+ </resources>
+ <exports>
+ <include path="META-INF/**"/>
+ </exports>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="org.apache.httpcomponents"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml
new file mode 100644
index 0000000..94a9f1a
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-infinispan/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-infinispan">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-connections-infinispan}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.infinispan"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml
new file mode 100644
index 0000000..ef36ac3
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa/main/module.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-jpa">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-connections-jpa}"/>
+ </resources>
+ <exports>
+ <include path="META-INF/**"/>
+ </exports>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="javax.persistence.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.bouncycastle" />
+ <module name="javax.api"/>
+ <module name="org.hibernate" services="import"/>
+ <module name="org.javassist"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml
new file mode 100644
index 0000000..8ade3fd
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-jpa-liquibase/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-jpa-liquibase">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-connections-jpa-liquibase}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-jpa"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.liquibase"/>
+ <module name="javax.persistence.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml
new file mode 100644
index 0000000..504023f
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-mongo">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-connections-mongo}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.mongodb.mongo-java-driver"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml
new file mode 100644
index 0000000..621f06d
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-connections-mongo-update/main/module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-mongo-update">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-connections-mongo-update}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-mongo"/>
+ <module name="org.mongodb.mongo-java-driver"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
\ No newline at end of file
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml
new file mode 100644
index 0000000..b23c589
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core/main/module.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-core}"/>
+ </resources>
+ <dependencies>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ <module name="javax.activation.api"/>
+ <module name="sun.jdk" optional="true" />
+ <module name="sun.jdk.jgss" optional="true" />
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml
new file mode 100644
index 0000000..c773354
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-core-jaxrs/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-core-jaxrs">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-core-jaxrs}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml
new file mode 100644
index 0000000..ed433b5
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-api/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-email-api">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-email-api}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml
new file mode 100644
index 0000000..a0c371f
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-email-freemarker/main/module.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-email-freemarker">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-email-freemarker}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-forms-common-freemarker"/>
+ <module name="org.keycloak.keycloak-email-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="javax.mail.api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.freemarker"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml
new file mode 100644
index 0000000..2f8c152
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-api/main/module.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-events-api">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-events-api}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml
new file mode 100644
index 0000000..255f830
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-email/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-events-email">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-events-email}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-email-api"/>
+ <module name="javax.mail.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml
new file mode 100644
index 0000000..5a6fe2b
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jboss-logging/main/module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-events-jboss-logging">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-events-jboss-logging}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="javax.ws.rs.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml
new file mode 100644
index 0000000..12c859e
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-jpa/main/module.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-events-jpa">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-events-jpa}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-connections-jpa"/>
+ <module name="javax.persistence.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.javassist"/>
+ <module name="org.hibernate" services="import"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml
new file mode 100644
index 0000000..4e48e7f
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-events-mongo/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-events-mongo">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-events-mongo}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-connections-mongo"/>
+ <module name="org.mongodb.mongo-java-driver"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml
new file mode 100644
index 0000000..2e50335
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-api/main/module.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-export-import-api">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-export-import-api}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-model"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml
new file mode 100644
index 0000000..1cda32b
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-dir/main/module.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-export-import-dir">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-export-import-dir}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-model"/>
+ <module name="org.keycloak.keycloak-export-import-api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml
new file mode 100644
index 0000000..a390929
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-single-file/main/module.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-export-import-single-file">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-export-import-single-file}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-model"/>
+ <module name="org.keycloak.keycloak-export-import-api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml
new file mode 100644
index 0000000..a33365d
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-export-import-zip/main/module.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-export-import-zip">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-export-import-zip}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-model"/>
+ <module name="org.keycloak.keycloak-export-import-api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="de.idyl.winzipaes"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml
new file mode 100644
index 0000000..c6c6325
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-freemarker/main/module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-forms-common-freemarker">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-forms-common-freemarker}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.freemarker"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml
new file mode 100644
index 0000000..0e12a97
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-forms-common-themes/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-forms-common-themes">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-forms-common-themes}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-forms-common-freemarker"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.freemarker"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml
new file mode 100644
index 0000000..572ab38
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-infinispan/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-invalidation-cache-infinispan">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-invalidation-cache-infinispan}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-model"/>
+ <module name="org.keycloak.keycloak-connections-infinispan"/>
+ <module name="org.infinispan"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml
new file mode 100644
index 0000000..1844bc8
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-invalidation-cache-model/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-invalidation-cache-model">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-invalidation-cache-model}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml
new file mode 100644
index 0000000..6e5b217
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-jboss-adapter-core/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-jboss-adapter-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-jboss-adapter-core}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.picketbox"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml
new file mode 100644
index 0000000..d99ac75
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-js-adapter/main/module.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-js-adapter">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-js-adapter}"/>
+ </resources>
+ <dependencies>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml
new file mode 100644
index 0000000..4f9da8b
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-kerberos-federation/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-kerberos-federation">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-kerberos-federation}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="net.iharder.base64"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
\ No newline at end of file
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml
new file mode 100644
index 0000000..e8c9e4d
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-ldap-federation/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-ldap-federation">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-ldap-federation}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-kerberos-federation"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml
new file mode 100644
index 0000000..ff6f6ac
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-api/main/module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-login-api">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-login-api}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml
new file mode 100644
index 0000000..1cb5c41
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-login-freemarker/main/module.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-login-freemarker">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-login-freemarker}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-forms-common-freemarker"/>
+ <module name="org.keycloak.keycloak-login-api"/>
+ <module name="org.keycloak.keycloak-email-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.freemarker"/>
+ <module name="javax.api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml
new file mode 100644
index 0000000..14a0a86
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-api/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-api">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-api}"/>
+ </resources>
+ <dependencies>
+ <module name="org.jboss.logging"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml
new file mode 100644
index 0000000..e3ae276
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-file/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-file">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-file}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-file"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml
new file mode 100644
index 0000000..4f50b7a
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-jpa/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-jpa">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-jpa}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-jpa" services="import"/>
+ <module name="javax.persistence.api"/>
+ <module name="net.iharder.base64"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.javassist"/>
+ <module name="org.hibernate" services="import"/>
+ <module name="org.bouncycastle" />
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml
new file mode 100644
index 0000000..702406c
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-mongo/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-mongo">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-mongo}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-mongo"/>
+ <module name="org.mongodb.mongo-java-driver"/>
+ <module name="net.iharder.base64"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml
new file mode 100644
index 0000000..23f94b1
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-infinispan/main/module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-sessions-infinispan">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-sessions-infinispan}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-infinispan"/>
+ <module name="org.infinispan"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml
new file mode 100644
index 0000000..2033069
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-jpa/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-sessions-jpa">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-sessions-jpa}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-jpa"/>
+ <module name="javax.persistence.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="org.javassist"/>
+ <module name="org.hibernate" services="import"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml
new file mode 100644
index 0000000..6a1d101
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mem/main/module.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-sessions-mem">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-sessions-mem}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml
new file mode 100644
index 0000000..6993680
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-model-sessions-mongo/main/module.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-model-sessions-mongo">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-model-sessions-mongo}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-connections-mongo"/>
+ <module name="org.mongodb.mongo-java-driver"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml
new file mode 100644
index 0000000..c09490e
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-core/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-saml-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-saml-core}"/>
+ </resources>
+ <dependencies>
+ <module name="org.jboss.logging"/>
+ <module name="org.apache.santuario.xmlsec">
+ <imports>
+ <exclude path="javax/*"/>
+ </imports>
+ </module>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml
new file mode 100644
index 0000000..fc0cd15
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-saml-protocol/main/module.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-saml-protocol">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-saml-protocol}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-saml-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-events-api"/>
+ <module name="org.keycloak.keycloak-account-api"/>
+ <module name="org.keycloak.keycloak-email-api"/>
+ <module name="org.keycloak.keycloak-login-api"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.keycloak.keycloak-forms-common-freemarker"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="org.jboss.logging"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.resteasy.resteasy-crypto"/>
+ <module name="org.jboss.resteasy.resteasy-multipart-provider"/>
+ <module name="org.keycloak.keycloak-connections-http-client" services="import"/>
+
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server/main/module.xml
new file mode 100644
index 0000000..6c87781
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server/main/module.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-server">
+ <resources>
+ <artifact name="${org.keycloak.subsystem:keycloak-server}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-account-api" services="import"/>
+ <module name="org.keycloak.keycloak-account-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-connections-infinispan" services="import"/>
+ <module name="org.keycloak.keycloak-connections-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
+ <module name="org.keycloak.keycloak-connections-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-connections-mongo-update" services="import"/>
+ <module name="org.keycloak.keycloak-connections-file" services="import"/>
+ <module name="org.keycloak.keycloak-core" services="import"/>
+ <module name="org.keycloak.keycloak-core-jaxrs" services="import"/>
+ <module name="org.keycloak.keycloak-email-api" services="import"/>
+ <module name="org.keycloak.keycloak-email-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-events-api" services="import"/>
+ <module name="org.keycloak.keycloak-events-email" services="import"/>
+ <module name="org.keycloak.keycloak-events-jboss-logging" services="import"/>
+ <module name="org.keycloak.keycloak-events-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-events-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-api" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-dir" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-single-file" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-zip" services="import"/>
+ <module name="org.keycloak.keycloak-forms-common-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-forms-common-themes" services="import"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
+ <module name="org.keycloak.keycloak-js-adapter" services="import"/>
+ <module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
+ <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
+ <module name="org.keycloak.keycloak-login-api" services="import"/>
+ <module name="org.keycloak.keycloak-login-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-model-api" services="import"/>
+ <module name="org.keycloak.keycloak-model-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-model-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-infinispan" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-mem" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-saml-protocol" services="import"/>
+ <module name="org.keycloak.keycloak-services" export="true" services="import"/>
+ <module name="org.keycloak.keycloak-social-core" services="import"/>
+ <module name="org.keycloak.keycloak-social-facebook" services="import"/>
+ <module name="org.keycloak.keycloak-social-github" services="import"/>
+ <module name="org.keycloak.keycloak-social-google" services="import"/>
+ <module name="org.keycloak.keycloak-social-twitter" services="import"/>
+ <module name="org.keycloak.keycloak-social-linkedin" services="import"/>
+ <module name="org.keycloak.keycloak-social-stackoverflow" services="import"/>
+ <module name="org.keycloak.keycloak-server-subsystem" services="import"/>
+ <module name="org.keycloak.keycloak-timer-api" services="import"/>
+ <module name="org.keycloak.keycloak-timer-basic" services="import"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
new file mode 100644
index 0000000..5233767
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-server-subsystem">
+ <properties>
+ <property name="keycloak-version" value="${project.version}"/>
+ <property name="auth-server-exploded" value="false"/>
+ </properties>
+
+ <resources>
+ <resource-root path="."/>
+ <artifact name="${org.keycloak:keycloak-wildfly-server-subsystem}"/>
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.jboss.staxmapper"/>
+ <module name="org.jboss.as.controller"/>
+ <module name="org.jboss.as.ee"/>
+ <module name="org.jboss.as.server"/>
+ <module name="org.jboss.modules"/>
+ <module name="org.jboss.msc"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.jboss.vfs"/>
+ <module name="org.jboss.as.web-common" optional="true"/>
+ <module name="org.jboss.as.web" optional="true"/>
+ <module name="org.jboss.as.version" optional="true"/>
+ <module name="org.keycloak.keycloak-wildfly-adapter" optional="true"/>
+ <module name="org.jboss.metadata"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml
new file mode 100644
index 0000000..598d5dd
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-services/main/module.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-services">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-services}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-account-api" services="import"/>
+ <module name="org.keycloak.keycloak-account-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-broker-core" services="import"/>
+ <module name="org.keycloak.keycloak-broker-oidc" services="import"/>
+ <module name="org.keycloak.keycloak-broker-saml" services="import"/>
+ <module name="org.keycloak.keycloak-connections-http-client" services="import"/>
+ <module name="org.keycloak.keycloak-connections-infinispan" services="import"/>
+ <module name="org.keycloak.keycloak-connections-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
+ <module name="org.keycloak.keycloak-connections-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-connections-mongo-update" services="import"/>
+ <module name="org.keycloak.keycloak-connections-file" services="import"/>
+ <module name="org.keycloak.keycloak-core" services="import"/>
+ <module name="org.keycloak.keycloak-core-jaxrs" services="import"/>
+ <module name="org.keycloak.keycloak-email-api" services="import"/>
+ <module name="org.keycloak.keycloak-email-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-events-api" services="import"/>
+ <module name="org.keycloak.keycloak-events-email" services="import"/>
+ <module name="org.keycloak.keycloak-events-jboss-logging" services="import"/>
+ <module name="org.keycloak.keycloak-events-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-events-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-api" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-dir" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-single-file" services="import"/>
+ <module name="org.keycloak.keycloak-export-import-zip" services="import"/>
+ <module name="org.keycloak.keycloak-forms-common-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-forms-common-themes" services="import"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/>
+ <module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
+ <module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
+ <module name="org.keycloak.keycloak-js-adapter" services="import"/>
+ <module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
+ <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
+ <module name="org.keycloak.keycloak-login-api" services="import"/>
+ <module name="org.keycloak.keycloak-login-freemarker" services="import"/>
+ <module name="org.keycloak.keycloak-model-api" services="import"/>
+ <module name="org.keycloak.keycloak-model-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-model-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-model-file" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-infinispan" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-jpa" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-mem" services="import"/>
+ <module name="org.keycloak.keycloak-model-sessions-mongo" services="import"/>
+ <module name="org.keycloak.keycloak-wildfly-extensions" services="import"/>
+
+ <module name="org.keycloak.keycloak-saml-protocol" services="import"/>
+ <module name="org.keycloak.keycloak-services" export="true" services="import"/>
+ <module name="org.keycloak.keycloak-social-core" services="import"/>
+ <module name="org.keycloak.keycloak-social-facebook" services="import"/>
+ <module name="org.keycloak.keycloak-social-github" services="import"/>
+ <module name="org.keycloak.keycloak-social-google" services="import"/>
+ <module name="org.keycloak.keycloak-social-twitter" services="import"/>
+ <module name="org.keycloak.keycloak-social-linkedin" services="import"/>
+ <module name="org.keycloak.keycloak-social-stackoverflow" services="import"/>
+ <module name="org.keycloak.keycloak-timer-api" services="import"/>
+ <module name="org.keycloak.keycloak-timer-basic" services="import"/>
+
+ <module name="javax.ws.rs.api"/>
+ <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+ <module name="org.jboss.resteasy.resteasy-crypto"/>
+ <module name="org.jboss.resteasy.resteasy-multipart-provider"/>
+ <module name="javax.servlet.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="com.google.zxing.core"/>
+ <module name="com.google.zxing.javase"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.bouncycastle" />
+ <module name="net.iharder.base64"/>
+ <module name="javax.api"/>
+ <module name="javax.activation.api"/>
+ <module name="org.apache.httpcomponents"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml
new file mode 100644
index 0000000..836d5d6
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-core/main/module.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-core">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-social-core}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml
new file mode 100644
index 0000000..4c22779
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-facebook/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-facebook">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-social-facebook}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-broker-oidc"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml
new file mode 100644
index 0000000..9197bb0
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-github/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-github">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-social-github}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-broker-oidc"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml
new file mode 100644
index 0000000..bb56189
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-google/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-google">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-social-google}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-broker-oidc"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml
new file mode 100644
index 0000000..db38543
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-linkedin/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-linkedin">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-social-linkedin}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-broker-oidc"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml
new file mode 100644
index 0000000..5af13ce
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-stackoverflow/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-stackoverflow">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-social-stackoverflow}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-broker-oidc"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml
new file mode 100644
index 0000000..cf56209
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-social-twitter/main/module.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-twitter">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-social-twitter}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-social-core"/>
+ <module name="org.keycloak.keycloak-broker-core"/>
+ <module name="org.keycloak.keycloak-broker-oidc"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.twitter4j"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml
new file mode 100644
index 0000000..7704916
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-api/main/module.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-timer-api">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-timer-api}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml
new file mode 100644
index 0000000..e2279f9
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-timer-basic/main/module.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-timer-basic">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-timer-basic}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-timer-api"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.jboss.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml
new file mode 100644
index 0000000..9ba1cb2
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-undertow-adapter/main/module.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-undertow-adapter">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-undertow-adapter}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.bouncycastle" />
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="javax.servlet.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.jboss.xnio"/>
+ <module name="io.undertow.core"/>
+ <module name="io.undertow.servlet"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml
new file mode 100644
index 0000000..df7cc03
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adapter/main/module.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wildfly-adapter">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-wildfly-adapter}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.bouncycastle" />
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="javax.servlet.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="io.undertow.core"/>
+ <module name="io.undertow.servlet"/>
+ <module name="org.picketbox"/>
+ <module name="org.keycloak.keycloak-undertow-adapter"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.jboss.xnio"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml
new file mode 100644
index 0000000..05a48e5
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-extensions/main/module.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wildfly-extensions">
+ <resources>
+ <artifact name="${org.keycloak:keycloak-wildfly-extensions}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.keycloak.keycloak-services"/>
+ <module name="org.keycloak.keycloak-forms-common-freemarker"/>
+ <module name="org.keycloak.keycloak-forms-common-themes"/>
+ <module name="org.jboss.modules"/>
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml
new file mode 100644
index 0000000..d75eef0
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/liquibase/main/module.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.liquibase">
+ <resources>
+ <artifact name="${org.liquibase:liquibase-core}"/>
+ </resources>
+ <dependencies>
+ <module name="org.apache.commons.logging"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml
new file mode 100644
index 0000000..bb4acdd
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/mongodb/mongo-java-driver/main/module.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.mongodb.mongo-java-driver">
+ <resources>
+ <artifact name="${org.mongodb:mongo-java-driver}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml
new file mode 100644
index 0000000..70b84dc
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/twitter4j/main/module.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.twitter4j">
+ <resources>
+ <artifact name="${org.twitter4j:twitter4j-core}"/>
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ </dependencies>
+
+</module>
distribution/modules/build.xml 7(+5 -2)
diff --git a/distribution/modules/build.xml b/distribution/modules/build.xml
index 0fdcfa4..e7ede69 100755
--- a/distribution/modules/build.xml
+++ b/distribution/modules/build.xml
@@ -336,8 +336,11 @@
<maven-resource group="org.keycloak" artifact="keycloak-wildfly-adapter"/>
</module-def>
- <module-def name="org.keycloak.keycloak-subsystem">
- <maven-resource group="org.keycloak" artifact="keycloak-subsystem"/>
+ <module-def name="org.keycloak.keycloak-server-subsystem">
+ <maven-resource group="org.keycloak" artifact="keycloak-wildfly-server-subsystem"/>
+ </module-def>
+ <module-def name="org.keycloak.keycloak-adapter-subsystem">
+ <maven-resource group="org.keycloak" artifact="keycloak-wildfly-adapter-subsystem"/>
</module-def>
<module-def name="org.keycloak.keycloak-as7-subsystem">
<maven-resource group="org.keycloak" artifact="keycloak-as7-subsystem"/>
distribution/modules/pom.xml 10(+8 -2)
diff --git a/distribution/modules/pom.xml b/distribution/modules/pom.xml
index da8260d..501e422 100755
--- a/distribution/modules/pom.xml
+++ b/distribution/modules/pom.xml
@@ -56,7 +56,13 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-subsystem</artifactId>
+ <artifactId>keycloak-wildfly-server-subsystem</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adapter-subsystem</artifactId>
+ <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak.subsystem</groupId>
@@ -174,7 +180,7 @@
<artifactId>keycloak-server</artifactId>
<type>war</type>
<overWrite>true</overWrite>
- <outputDirectory>${project.build.directory}/modules/org/keycloak/keycloak-subsystem/main/auth-server</outputDirectory>
+ <outputDirectory>${project.build.directory}/modules/org/keycloak/keycloak-server-subsystem/main/auth-server</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-adapter-subsystem/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-adapter-subsystem/main/module.xml
new file mode 100755
index 0000000..3408a92
--- /dev/null
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-adapter-subsystem/main/module.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2014, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-adapter-subsystem">
+ <properties>
+ <property name="keycloak-version" value="${project.version}"/>
+ </properties>
+
+ <resources>
+ <resource-root path="."/>
+ <!-- Insert resources here -->
+ </resources>
+
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.jboss.staxmapper"/>
+ <module name="org.jboss.as.controller"/>
+ <module name="org.jboss.as.ee"/>
+ <module name="org.jboss.as.server"/>
+ <module name="org.jboss.modules"/>
+ <module name="org.jboss.msc"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.jboss.vfs"/>
+ <module name="org.jboss.as.web-common" optional="true"/>
+ <module name="org.jboss.as.web" optional="true"/>
+ <module name="org.jboss.as.version" optional="true"/>
+ <module name="org.keycloak.keycloak-as7-adapter" optional="true"/>
+ <module name="org.jboss.metadata"/>
+ </dependencies>
+</module>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
index ddf2475..9a7229f 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
@@ -10,6 +10,7 @@
<module name="org.keycloak.keycloak-account-api" services="import"/>
<module name="org.keycloak.keycloak-account-freemarker" services="import"/>
<module name="org.keycloak.keycloak-adapter-core" services="import"/>
+ <module name="org.keycloak.keycloak-adapter-subsystem" services="import"/>
<module name="org.keycloak.keycloak-as7-adapter" services="import"/>
<module name="org.keycloak.keycloak-as7-subsystem" services="import"/>
<module name="org.keycloak.keycloak-connections-infinispan" services="import"/>
@@ -57,7 +58,7 @@
<module name="org.keycloak.keycloak-social-twitter" services="import"/>
<module name="org.keycloak.keycloak-social-linkedin" services="import"/>
<module name="org.keycloak.keycloak-social-stackoverflow" services="import"/>
- <module name="org.keycloak.keycloak-subsystem" services="import"/>
+ <module name="org.keycloak.keycloak-server-subsystem" services="import"/>
<module name="org.keycloak.keycloak-timer-api" services="import"/>
<module name="org.keycloak.keycloak-timer-basic" services="import"/>
<module name="org.keycloak.keycloak-undertow-adapter" services="import"/>
distribution/pom.xml 1(+1 -0)
diff --git a/distribution/pom.xml b/distribution/pom.xml
index d09fbb8..8eeaafc 100755
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -37,5 +37,6 @@
<module>server-overlay</module>
<module>src-dist</module>
<module>subsystem-war</module>
+ <module>feature-packs</module>
</modules>
</project>
distribution/server-dist/assembly.xml 63(+34 -29)
diff --git a/distribution/server-dist/assembly.xml b/distribution/server-dist/assembly.xml
index b677d2c..6f0c028 100755
--- a/distribution/server-dist/assembly.xml
+++ b/distribution/server-dist/assembly.xml
@@ -8,55 +8,60 @@
<includeBaseDirectory>true</includeBaseDirectory>
+ <!-- If war is filtered it will get corrupted. Only need to filter module.xml -->
<fileSets>
<fileSet>
- <directory>${project.build.directory}/unpacked/wildfly-${wildfly.version}</directory>
- <outputDirectory></outputDirectory>
+ <directory>target/${project.build.finalName}</directory>
+ <outputDirectory/>
+ <filtered>true</filtered>
+ <includes>
+ <include>**/module.xml</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>target/${project.build.finalName}</directory>
+ <outputDirectory/>
+ <filtered>false</filtered>
<excludes>
- <exclude>**/*.sh</exclude>
+ <exclude>**/module.xml</exclude>
<exclude>welcome-content/**</exclude>
- <exclude>docs/**</exclude>
+ <exclude>appclient</exclude>
+ <exclude>appclient/*</exclude>
<exclude>standalone/deployments</exclude>
<exclude>standalone/deployments/*</exclude>
- <exclude>standalone/configuration/standalone*.xml</exclude>
</excludes>
</fileSet>
<fileSet>
- <directory>${project.build.directory}/unpacked</directory>
- <outputDirectory>standalone/configuration</outputDirectory>
+ <directory>src/main/welcome-content</directory>
+ <outputDirectory>welcome-content</outputDirectory>
<includes>
- <include>standalone*.xml</include>
+ <include>*.*</include>
</includes>
</fileSet>
<fileSet>
- <directory>${project.build.directory}/unpacked/wildfly-${wildfly.version}</directory>
- <outputDirectory></outputDirectory>
+ <directory>../../forms/common-themes/src/main/resources/theme</directory>
+ <outputDirectory>standalone/configuration/themes</outputDirectory>
<includes>
- <include>**/*.sh</include>
+ <include>**/**</include>
</includes>
- <fileMode>0755</fileMode>
</fileSet>
<fileSet>
- <directory>src/main/welcome-content</directory>
- <outputDirectory>welcome-content</outputDirectory>
+ <directory>../../</directory>
<includes>
- <include>*.*</include>
+ <include>License.html</include>
</includes>
+ <outputDirectory></outputDirectory>
</fileSet>
</fileSets>
- <dependencySets>
- <dependencySet>
- <includes>
- <include>org.keycloak:keycloak-server-overlay:zip</include>
- </includes>
- <outputDirectory></outputDirectory>
- <unpack>true</unpack>
- <unpackOptions>
- <excludes>
- <exclude>standalone/configuration/standalone-keycloak.xml</exclude>
- </excludes>
- </unpackOptions>
- </dependencySet>
- </dependencySets>
+ <files>
+ <file>
+ <source>../server-overlay/src/main/themes/README.txt</source>
+ <outputDirectory>standalone/configuration/themes</outputDirectory>
+ </file>
+ <file>
+ <source>../server-overlay/src/main/providers/README.txt</source>
+ <outputDirectory>standalone/configuration/providers</outputDirectory>
+ </file>
+ </files>
</assembly>
distribution/server-dist/pom.xml 54(+12 -42)
diff --git a/distribution/server-dist/pom.xml b/distribution/server-dist/pom.xml
index 07c00ea..cc76727 100755
--- a/distribution/server-dist/pom.xml
+++ b/distribution/server-dist/pom.xml
@@ -28,58 +28,26 @@
<build>
<finalName>keycloak-${project.version}</finalName>
+
<plugins>
<plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <executions>
- <execution>
- <id>unpack-wildfly</id>
- <phase>prepare-package</phase>
- <goals>
- <goal>unpack</goal>
- </goals>
- <configuration>
- <artifactItems>
- <artifactItem>
- <groupId>org.wildfly</groupId>
- <artifactId>wildfly-dist</artifactId>
- <version>${wildfly.version}</version>
- <type>zip</type>
- <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
- </artifactItem>
- </artifactItems>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>xml-maven-plugin</artifactId>
- <version>1.0</version>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
<executions>
<execution>
- <id>generate-resources</id>
- <phase>package</phase>
+ <id>server-provisioning</id>
<goals>
- <goal>transform</goal>
+ <goal>build</goal>
</goals>
+ <phase>compile</phase>
<configuration>
- <transformationSets>
- <transformationSet>
- <dir>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration</dir>
- <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
- <includes>
- <include>standalone*.xml</include>
- </includes>
- <outputDir>${project.build.directory}/unpacked</outputDir>
- </transformationSet>
- </transformationSets>
+ <config-file>server-provisioning.xml</config-file>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
@@ -92,9 +60,11 @@
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
- <outputDirectory>target</outputDirectory>
- <workDirectory>target/assembly/work</workDirectory>
+ <recompressZippedFiles>true</recompressZippedFiles>
+ <finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</execution>
diff --git a/distribution/server-dist/server-provisioning.xml b/distribution/server-dist/server-provisioning.xml
new file mode 100644
index 0000000..d414b95
--- /dev/null
+++ b/distribution/server-dist/server-provisioning.xml
@@ -0,0 +1,22 @@
+<!--
+~ JBoss, Home of Professional Open Source.
+~ Copyright 2015 Red Hat, Inc., and individual 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.
+-->
+<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0" extract-schemas="true" copy-module-artifacts="true">
+ <feature-packs>
+ <feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
+ </feature-packs>
+</server-provisioning>
\ No newline at end of file
diff --git a/distribution/server-overlay/src/main/xslt/standalone.xsl b/distribution/server-overlay/src/main/xslt/standalone.xsl
index 0180557..9e7d309 100755
--- a/distribution/server-overlay/src/main/xslt/standalone.xsl
+++ b/distribution/server-overlay/src/main/xslt/standalone.xsl
@@ -16,7 +16,8 @@
<xsl:template match="//j:extensions">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
- <extension module="org.keycloak.keycloak-subsystem"/>
+ <extension module="org.keycloak.keycloak-server-subsystem"/>
+ <extension module="org.keycloak.keycloak-adapter-subsystem"/>
</xsl:copy>
</xsl:template>
@@ -38,7 +39,7 @@
<xsl:template match="//j:profile">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
- <subsystem xmlns="urn:jboss:domain:keycloak:1.0">
+ <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<auth-server name="main-auth-server">
<enabled>true</enabled>
<web-context>auth</web-context>
diff --git a/docbook/reference/en/en-US/modules/javascript-adapter.xml b/docbook/reference/en/en-US/modules/javascript-adapter.xml
index 80f04ed..30f8dd0 100755
--- a/docbook/reference/en/en-US/modules/javascript-adapter.xml
+++ b/docbook/reference/en/en-US/modules/javascript-adapter.xml
@@ -305,6 +305,23 @@ keycloak.updateToken(5).success(function(refreshed) {
]]></programlisting>
</simplesect>
+
+ <simplesect>
+ <title>clearToken()</title>
+
+ <para>
+ Clear authentication state, including tokens. This can be useful if application has detected the session
+ has expired, for example if updating token fails. Invoking this results in onAuthLogout callback listener
+ being invoked.
+ </para>
+
+ <programlisting><![CDATA[
+keycloak.updateToken(5).error(function() {
+ keycloak.clearToken();
+});
+]]></programlisting>
+
+ </simplesect>
</section>
<section>
diff --git a/docbook/reference/en/en-US/modules/server-installation.xml b/docbook/reference/en/en-US/modules/server-installation.xml
index e6cd134..9c321a2 100755
--- a/docbook/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/reference/en/en-US/modules/server-installation.xml
@@ -195,7 +195,7 @@
<term>databaseSchema</term>
<listitem>
<para>
- Value of database schema (Hibernate property "hibernate.hbm2ddl.auto" ).
+ Specify if schema should be updated or validated. Valid values are "update" and "validate" ("update is default).
</para>
</listitem>
</varlistentry>
diff --git a/events/api/src/main/java/org/keycloak/events/admin/AdminEvent.java b/events/api/src/main/java/org/keycloak/events/admin/AdminEvent.java
new file mode 100644
index 0000000..4225501
--- /dev/null
+++ b/events/api/src/main/java/org/keycloak/events/admin/AdminEvent.java
@@ -0,0 +1,119 @@
+package org.keycloak.events.admin;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AdminEvent {
+
+ private long time;
+
+ private String realmId;
+
+ private AuthDetails authDetails;
+
+ private OperationType operationType;
+
+ private String resourcePath;
+
+ private String representation;
+
+ private String error;
+
+ /**
+ * Returns the time of the event
+ *
+ * @return time in millis
+ */
+ public long getTime() {
+ return time;
+ }
+
+ public void setTime(long time) {
+ this.time = time;
+ }
+
+ /**
+ * Returns the id of the realm
+ *
+ * @return
+ */
+ public String getRealmId() {
+ return realmId;
+ }
+
+ public void setRealmId(String realmId) {
+ this.realmId = realmId;
+ }
+
+ /**
+ * Returns authentication details
+ *
+ * @return
+ */
+ public AuthDetails getAuthDetails() {
+ return authDetails;
+ }
+
+ public void setAuthDetails(AuthDetails authDetails) {
+ this.authDetails = authDetails;
+ }
+
+ /**
+ * Returns the type of the operation
+ *
+ * @return
+ */
+ public OperationType getOperationType() {
+ return operationType;
+ }
+
+ public void setOperationType(OperationType operationType) {
+ this.operationType = operationType;
+ }
+
+ /**
+ * Returns the path of the resource. For example:
+ * <ul>
+ * <li><b>realms</b> - realm list</li>
+ * <li><b>realms/master</b> - master realm</li>
+ * <li><b>realms/clients/00d4b16f-f1f9-4e73-8366-d76b18f3e0e1</b> - client within the master realm</li>
+ * </ul>
+ *
+ * @return
+ */
+ public String getResourcePath() {
+ return resourcePath;
+ }
+
+ public void setResourcePath(String resourcePath) {
+ this.resourcePath = resourcePath;
+ }
+
+ /**
+ * Returns the updated JSON representation if <code>operationType</code> is <code>CREATE</code> or <code>UPDATE</code>.
+ * Otherwise returns <code>null</code>.
+ *
+ * @return
+ */
+ public String getRepresentation() {
+ return representation;
+ }
+
+ public void setRepresentation(String representation) {
+ this.representation = representation;
+ }
+
+ /**
+ * If the event was unsuccessful returns the error message. Otherwise returns <code>null</code>.
+ *
+ * @return
+ */
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+
+}
diff --git a/events/api/src/main/java/org/keycloak/events/admin/AdminEventQuery.java b/events/api/src/main/java/org/keycloak/events/admin/AdminEventQuery.java
new file mode 100644
index 0000000..d7b5fe4
--- /dev/null
+++ b/events/api/src/main/java/org/keycloak/events/admin/AdminEventQuery.java
@@ -0,0 +1,110 @@
+package org.keycloak.events.admin;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface AdminEventQuery {
+
+ /**
+ * Search by resource realm
+ *
+ * @param realmId realm id
+ * @return Associated <code>AdminEventQuery</code> for method chaining
+ */
+ AdminEventQuery realm(String realmId);
+
+ /**
+ * Search by authentication realm
+ *
+ * @param realmId realm name
+ * @return Associated <code>AdminEventQuery</code> for method chaining
+ */
+ AdminEventQuery authRealm(String realmId);
+
+ /**
+ * Search by authenticated client
+ *
+ * @param clientId client uuid
+ * @return Associated <code>AdminEventQuery</code> for method chaining
+ */
+ AdminEventQuery authClient(String clientId);
+
+ /**
+ * Search by authenticated user
+ *
+ * @param userId user uuid
+ * @return Associated <code>AdminEventQuery</code> for method chaining
+ */
+ AdminEventQuery authUser(String userId);
+
+ /**
+ * Search by request ip address
+ *
+ * @param ipAddress
+ * @return Associated <code>AdminEventQuery</code> for method chaining
+ */
+ AdminEventQuery authIpAddress(String ipAddress);
+
+ /**
+ * Search by operation type
+ *
+ * @param operations
+ * @return <code>this</code> for method chaining
+ */
+ AdminEventQuery operation(OperationType... operations);
+
+ /**
+ * Search by resource path. Supports wildcards <code>*</code> and <code>**</code>. For example:
+ * <ul>
+ * <li><b>*/master</b> - matches 'realms/master'</li>
+ * <li><b>**/00d4b16f</b> - matches 'realms/master/clients/00d4b16f'</li>
+ * <li><b>realms/master/**</b> - matches anything under 'realms/master'</li>
+ * </ul>
+ *
+ * @param resourcePath
+ * @return <code>this</code> for method chaining
+ */
+ AdminEventQuery resourcePath(String resourcePath);
+
+ /**
+ * Search by events after the specified time
+ *
+ * @param fromTime time in millis
+ * @return <code>this</code> for method chaining
+ */
+ AdminEventQuery fromTime(String fromTime);
+
+ /**
+ * Search by events before the specified time
+ *
+ * @param toTime time in millis
+ * @return <code>this</code> for method chaining
+ */
+ AdminEventQuery toTime(String toTime);
+
+ /**
+ * Used for pagination
+ *
+ * @param first first result to return
+ * @return <code>this</code> for method chaining
+ */
+ AdminEventQuery firstResult(int first);
+
+ /**
+ * Use for pagination
+ *
+ * @param max the maximum results to return
+ * @return <code>this</code> for method chaining
+ */
+ AdminEventQuery maxResults(int max);
+
+ /**
+ * Executes the query and returns the results
+ *
+ * @return
+ */
+ List<AdminEvent> getResultList();
+
+}
diff --git a/events/api/src/main/java/org/keycloak/events/admin/AuthDetails.java b/events/api/src/main/java/org/keycloak/events/admin/AuthDetails.java
new file mode 100644
index 0000000..d32eff1
--- /dev/null
+++ b/events/api/src/main/java/org/keycloak/events/admin/AuthDetails.java
@@ -0,0 +1,48 @@
+package org.keycloak.events.admin;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AuthDetails {
+
+ private String realmId;
+
+ private String clientId;
+
+ private String userId;
+
+ private String ipAddress;
+
+ public String getRealmId() {
+ return realmId;
+ }
+
+ public void setRealmId(String realmId) {
+ this.realmId = realmId;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+}
diff --git a/events/api/src/main/java/org/keycloak/events/admin/AuthQuery.java b/events/api/src/main/java/org/keycloak/events/admin/AuthQuery.java
new file mode 100644
index 0000000..3be431f
--- /dev/null
+++ b/events/api/src/main/java/org/keycloak/events/admin/AuthQuery.java
@@ -0,0 +1,48 @@
+package org.keycloak.events.admin;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AuthQuery {
+
+ private String realmId;
+
+ private String clientId;
+
+ private String userId;
+
+ private String ipAddress;
+
+ public String getRealmId() {
+ return realmId;
+ }
+
+ public void setRealmId(String realmId) {
+ this.realmId = realmId;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+}
diff --git a/events/api/src/main/java/org/keycloak/events/admin/OperationType.java b/events/api/src/main/java/org/keycloak/events/admin/OperationType.java
new file mode 100755
index 0000000..ca3ae20
--- /dev/null
+++ b/events/api/src/main/java/org/keycloak/events/admin/OperationType.java
@@ -0,0 +1,13 @@
+package org.keycloak.events.admin;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public enum OperationType {
+
+ CREATE,
+ UPDATE,
+ DELETE,
+ ACTION;
+
+}
diff --git a/events/api/src/main/java/org/keycloak/events/EventBuilder.java b/events/api/src/main/java/org/keycloak/events/EventBuilder.java
index 4945989..ee7a70a 100644
--- a/events/api/src/main/java/org/keycloak/events/EventBuilder.java
+++ b/events/api/src/main/java/org/keycloak/events/EventBuilder.java
@@ -7,6 +7,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.util.Time;
import java.util.HashMap;
import java.util.LinkedList;
@@ -149,7 +150,7 @@ public class EventBuilder {
}
private void send() {
- event.setTime(System.currentTimeMillis());
+ event.setTime(Time.toMillis(Time.currentTime()));
if (store != null) {
if (realm.getEnabledEventTypes() != null && !realm.getEnabledEventTypes().isEmpty() ? realm.getEnabledEventTypes().contains(event.getType().name()) : event.getType().isSaveByDefault()) {
diff --git a/events/api/src/main/java/org/keycloak/events/EventListenerProvider.java b/events/api/src/main/java/org/keycloak/events/EventListenerProvider.java
index 01ab302..957d639 100644
--- a/events/api/src/main/java/org/keycloak/events/EventListenerProvider.java
+++ b/events/api/src/main/java/org/keycloak/events/EventListenerProvider.java
@@ -1,5 +1,6 @@
package org.keycloak.events;
+import org.keycloak.events.admin.AdminEvent;
import org.keycloak.provider.Provider;
/**
@@ -9,4 +10,6 @@ public interface EventListenerProvider extends Provider {
public void onEvent(Event event);
+ public void onEvent(AdminEvent event, boolean includeRepresentation);
+
}
diff --git a/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java b/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java
index 70cdea4..a16ad46 100644
--- a/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java
+++ b/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class EventListenerSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
public String getName() {
return "eventsListener";
}
diff --git a/events/api/src/main/java/org/keycloak/events/EventStoreProvider.java b/events/api/src/main/java/org/keycloak/events/EventStoreProvider.java
index c742556..afdaf92 100644
--- a/events/api/src/main/java/org/keycloak/events/EventStoreProvider.java
+++ b/events/api/src/main/java/org/keycloak/events/EventStoreProvider.java
@@ -1,5 +1,7 @@
package org.keycloak.events;
+import org.keycloak.events.admin.AdminEventQuery;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@@ -7,10 +9,18 @@ public interface EventStoreProvider extends EventListenerProvider {
public EventQuery createQuery();
+ public AdminEventQuery createAdminQuery();
+
public void clear();
public void clear(String realmId);
public void clear(String realmId, long olderThan);
+ public void clearAdmin();
+
+ public void clearAdmin(String realmId);
+
+ public void clearAdmin(String realmId, long olderThan);
+
}
diff --git a/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java b/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java
index 573fc86..af5f59f 100644
--- a/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java
+++ b/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class EventStoreSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "eventsStore";
}
diff --git a/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java b/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java
index 71a432a..400ef04 100755
--- a/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java
+++ b/events/email/src/main/java/org/keycloak/events/email/EmailEventListenerProvider.java
@@ -3,6 +3,7 @@ package org.keycloak.events.email;
import org.jboss.logging.Logger;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
+import org.keycloak.events.admin.AdminEvent;
import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventType;
@@ -50,6 +51,11 @@ public class EmailEventListenerProvider implements EventListenerProvider {
}
@Override
+ public void onEvent(AdminEvent event, boolean includeRepresentation) {
+
+ }
+
+ @Override
public void close() {
}
diff --git a/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java b/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java
index dba4304..38283f7 100755
--- a/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java
+++ b/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java
@@ -1,6 +1,7 @@
package org.keycloak.events.log;
import org.jboss.logging.Logger;
+import org.keycloak.events.admin.AdminEvent;
import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.models.KeycloakContext;
@@ -9,8 +10,8 @@ import org.keycloak.models.KeycloakSession;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriInfo;
+
import java.util.Map;
-import java.util.logging.Level;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -66,29 +67,42 @@ public class JBossLoggingEventListenerProvider implements EventListenerProvider
}
}
}
+
+ if(logger.isTraceEnabled()) {
+ setKeycloakContext(sb);
+ }
- if (logger.isTraceEnabled()) {
- KeycloakContext context = session.getContext();
- UriInfo uriInfo = context.getUri();
- HttpHeaders headers = context.getRequestHeaders();
- if (uriInfo != null) {
- sb.append(", requestUri=");
- sb.append(uriInfo.getRequestUri().toString());
- }
+ logger.log(logger.isTraceEnabled() ? Logger.Level.TRACE : level, sb.toString());
+ }
+ }
- if (headers != null) {
- sb.append(", cookies=[");
- boolean f = true;
- for (Map.Entry<String, Cookie> e : headers.getCookies().entrySet()) {
- if (f) {
- f = false;
- } else {
- sb.append(", ");
- }
- sb.append(e.getValue().toString());
- }
- sb.append("]");
- }
+ @Override
+ public void onEvent(AdminEvent adminEvent, boolean includeRepresentation) {
+ Logger.Level level = adminEvent.getError() != null ? errorLevel : successLevel;
+
+ if (logger.isEnabled(level)) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("operationType=");
+ sb.append(adminEvent.getOperationType());
+ sb.append(", realmId=");
+ sb.append(adminEvent.getAuthDetails().getRealmId());
+ sb.append(", clientId=");
+ sb.append(adminEvent.getAuthDetails().getClientId());
+ sb.append(", userId=");
+ sb.append(adminEvent.getAuthDetails().getUserId());
+ sb.append(", ipAddress=");
+ sb.append(adminEvent.getAuthDetails().getIpAddress());
+ sb.append(", resourcePath=");
+ sb.append(adminEvent.getResourcePath());
+
+ if (adminEvent.getError() != null) {
+ sb.append(", error=");
+ sb.append(adminEvent.getError());
+ }
+
+ if(logger.isTraceEnabled()) {
+ setKeycloakContext(sb);
}
logger.log(logger.isTraceEnabled() ? Logger.Level.TRACE : level, sb.toString());
@@ -98,5 +112,30 @@ public class JBossLoggingEventListenerProvider implements EventListenerProvider
@Override
public void close() {
}
+
+ private void setKeycloakContext(StringBuilder sb) {
+ KeycloakContext context = session.getContext();
+ UriInfo uriInfo = context.getUri();
+ HttpHeaders headers = context.getRequestHeaders();
+ if (uriInfo != null) {
+ sb.append(", requestUri=");
+ sb.append(uriInfo.getRequestUri().toString());
+ }
+
+ if (headers != null) {
+ sb.append(", cookies=[");
+ boolean f = true;
+ for (Map.Entry<String, Cookie> e : headers.getCookies().entrySet()) {
+ if (f) {
+ f = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(e.getValue().toString());
+ }
+ sb.append("]");
+ }
+
+ }
}
diff --git a/events/jpa/src/main/java/org/keycloak/events/jpa/AdminEventEntity.java b/events/jpa/src/main/java/org/keycloak/events/jpa/AdminEventEntity.java
new file mode 100644
index 0000000..b814c5a
--- /dev/null
+++ b/events/jpa/src/main/java/org/keycloak/events/jpa/AdminEventEntity.java
@@ -0,0 +1,137 @@
+package org.keycloak.events.jpa;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
+ */
+@Entity
+@Table(name="ADMIN_EVENT_ENTITY")
+public class AdminEventEntity {
+
+ @Id
+ @Column(name="ID", length = 36)
+ private String id;
+
+ @Column(name="ADMIN_EVENT_TIME")
+ private long time;
+
+ @Column(name="REALM_ID")
+ private String realmId;
+
+ @Column(name="OPERATION_TYPE")
+ private String operationType;
+
+ @Column(name="AUTH_REALM_ID")
+ private String authRealmId;
+
+ @Column(name="AUTH_CLIENT_ID")
+ private String authClientId;
+
+ @Column(name="AUTH_USER_ID")
+ private String authUserId;
+
+ @Column(name="IP_ADDRESS")
+ private String authIpAddress;
+
+ @Column(name="RESOURCE_PATH")
+ private String resourcePath;
+
+ @Column(name="REPRESENTATION", length = 25500)
+ private String representation;
+
+ @Column(name="ERROR")
+ private String error;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ public void setTime(long time) {
+ this.time = time;
+ }
+
+ public String getRealmId() {
+ return realmId;
+ }
+
+ public void setRealmId(String realmId) {
+ this.realmId = realmId;
+ }
+
+ public String getOperationType() {
+ return operationType;
+ }
+
+ public void setOperationType(String operationType) {
+ this.operationType = operationType;
+ }
+
+ public String getAuthRealmId() {
+ return authRealmId;
+ }
+
+ public void setAuthRealmId(String authRealmId) {
+ this.authRealmId = authRealmId;
+ }
+
+ public String getAuthClientId() {
+ return authClientId;
+ }
+
+ public void setAuthClientId(String authClientId) {
+ this.authClientId = authClientId;
+ }
+
+ public String getAuthUserId() {
+ return authUserId;
+ }
+
+ public void setAuthUserId(String authUserId) {
+ this.authUserId = authUserId;
+ }
+
+ public String getAuthIpAddress() {
+ return authIpAddress;
+ }
+
+ public void setAuthIpAddress(String authIpAddress) {
+ this.authIpAddress = authIpAddress;
+ }
+
+ public String getResourcePath() {
+ return resourcePath;
+ }
+
+ public void setResourcePath(String resourcePath) {
+ this.resourcePath = resourcePath;
+ }
+
+ public String getRepresentation() {
+ return representation;
+ }
+
+ public void setRepresentation(String representation) {
+ this.representation = representation;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+
+}
diff --git a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaAdminEventQuery.java b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaAdminEventQuery.java
new file mode 100644
index 0000000..f9ea14d
--- /dev/null
+++ b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaAdminEventQuery.java
@@ -0,0 +1,154 @@
+package org.keycloak.events.jpa;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.OperationType;
+
+/**
+ * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
+ */
+public class JpaAdminEventQuery implements AdminEventQuery {
+
+ private final EntityManager em;
+ private final CriteriaBuilder cb;
+ private final CriteriaQuery<AdminEventEntity> cq;
+ private final Root<AdminEventEntity> root;
+ private final ArrayList<Predicate> predicates;
+ private Integer firstResult;
+ private Integer maxResults;
+
+ public JpaAdminEventQuery(EntityManager em) {
+ this.em = em;
+
+ cb = em.getCriteriaBuilder();
+ cq = cb.createQuery(AdminEventEntity.class);
+ root = cq.from(AdminEventEntity.class);
+ predicates = new ArrayList<Predicate>();
+ }
+
+ @Override
+ public AdminEventQuery realm(String realmId) {
+ predicates.add(cb.equal(root.get("realmId"), realmId));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery operation(OperationType... operations) {
+ List<String> operationStrings = new LinkedList<String>();
+ for (OperationType e : operations) {
+ operationStrings.add(e.toString());
+ }
+ predicates.add(root.get("operationType").in(operationStrings));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authRealm(String authRealmId) {
+ predicates.add(cb.equal(root.get("authRealmId"), authRealmId));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authClient(String authClientId) {
+ predicates.add(cb.equal(root.get("authClientId"), authClientId));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authUser(String authUserId) {
+ predicates.add(cb.equal(root.get("authUserId"), authUserId));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authIpAddress(String ipAddress) {
+ predicates.add(cb.equal(root.get("authIpAddress"), ipAddress));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery resourcePath(String resourcePath) {
+ Expression<String> rPath = root.get("resourcePath");
+ predicates.add(cb.like(rPath, "%"+resourcePath+"%"));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery fromTime(String fromTime) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ Long from = null;
+ try {
+ from = df.parse(fromTime).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ predicates.add(cb.greaterThanOrEqualTo(root.<Long>get("time"), from));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery toTime(String toTime) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ Long to = null;
+ try {
+ to = df.parse(toTime).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ predicates.add(cb.lessThanOrEqualTo(root.<Long>get("time"), to));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery firstResult(int firstResult) {
+ this.firstResult = firstResult;
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery maxResults(int maxResults) {
+ this.maxResults = maxResults;
+ return this;
+ }
+
+ @Override
+ public List<AdminEvent> getResultList() {
+ if (!predicates.isEmpty()) {
+ cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
+ }
+
+ cq.orderBy(cb.desc(root.get("time")));
+
+ TypedQuery<AdminEventEntity> query = em.createQuery(cq);
+
+ if (firstResult != null) {
+ query.setFirstResult(firstResult);
+ }
+
+ if (maxResults != null) {
+ query.setMaxResults(maxResults);
+ }
+
+ List<AdminEvent> events = new LinkedList<AdminEvent>();
+ for (AdminEventEntity e : query.getResultList()) {
+ events.add(JpaEventStoreProvider.convertAdminEvent(e));
+ }
+
+ return events;
+ }
+
+}
diff --git a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java
index 5e39d17..ffbf619 100644
--- a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java
+++ b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java
@@ -131,7 +131,7 @@ public class JpaEventQuery implements EventQuery {
List<Event> events = new LinkedList<Event>();
for (EventEntity e : query.getResultList()) {
- events.add(JpaEventStoreProvider.convert(e));
+ events.add(JpaEventStoreProvider.convertEvent(e));
}
return events;
diff --git a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java
index 8fca6ec..d3ff4f8 100755
--- a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java
+++ b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java
@@ -3,12 +3,17 @@ package org.keycloak.events.jpa;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.jboss.logging.Logger;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.AuthDetails;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.events.Event;
import org.keycloak.events.EventQuery;
import org.keycloak.events.EventStoreProvider;
import org.keycloak.events.EventType;
import javax.persistence.EntityManager;
+
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
@@ -51,49 +56,121 @@ public class JpaEventStoreProvider implements EventStoreProvider {
@Override
public void onEvent(Event event) {
- em.persist(convert(event));
+ em.persist(convertEvent(event));
+ }
+
+ @Override
+ public AdminEventQuery createAdminQuery() {
+ return new JpaAdminEventQuery(em);
+ }
+
+ @Override
+ public void clearAdmin() {
+ em.createQuery("delete from AdminEventEntity").executeUpdate();
+ }
+
+ @Override
+ public void clearAdmin(String realmId) {
+ em.createQuery("delete from AdminEventEntity where realmId = :realmId").setParameter("realmId", realmId).executeUpdate();
+ }
+
+ @Override
+ public void clearAdmin(String realmId, long olderThan) {
+ em.createQuery("delete from AdminEventEntity where realmId = :realmId and time < :time").setParameter("realmId", realmId).setParameter("time", olderThan).executeUpdate();
+ }
+
+ @Override
+ public void onEvent(AdminEvent event, boolean includeRepresentation) {
+ em.persist(convertAdminEvent(event, includeRepresentation));
}
@Override
public void close() {
}
- static EventEntity convert(Event o) {
- EventEntity e = new EventEntity();
- e.setId(UUID.randomUUID().toString());
- e.setTime(o.getTime());
- e.setType(o.getType().toString());
- e.setRealmId(o.getRealmId());
- e.setClientId(o.getClientId());
- e.setUserId(o.getUserId());
- e.setSessionId(o.getSessionId());
- e.setIpAddress(o.getIpAddress());
- e.setError(o.getError());
+ static EventEntity convertEvent(Event event) {
+ EventEntity eventEntity = new EventEntity();
+ eventEntity.setId(UUID.randomUUID().toString());
+ eventEntity.setTime(event.getTime());
+ eventEntity.setType(event.getType().toString());
+ eventEntity.setRealmId(event.getRealmId());
+ eventEntity.setClientId(event.getClientId());
+ eventEntity.setUserId(event.getUserId());
+ eventEntity.setSessionId(event.getSessionId());
+ eventEntity.setIpAddress(event.getIpAddress());
+ eventEntity.setError(event.getError());
try {
- e.setDetailsJson(mapper.writeValueAsString(o.getDetails()));
+ eventEntity.setDetailsJson(mapper.writeValueAsString(event.getDetails()));
} catch (IOException ex) {
logger.error("Failed to write log details", ex);
}
- return e;
- }
-
- static Event convert(EventEntity o) {
- Event e = new Event();
- e.setTime(o.getTime());
- e.setType(EventType.valueOf(o.getType()));
- e.setRealmId(o.getRealmId());
- e.setClientId(o.getClientId());
- e.setUserId(o.getUserId());
- e.setSessionId(o.getSessionId());
- e.setIpAddress(o.getIpAddress());
- e.setError(o.getError());
+ return eventEntity;
+ }
+
+ static Event convertEvent(EventEntity eventEntity) {
+ Event event = new Event();
+ event.setTime(eventEntity.getTime());
+ event.setType(EventType.valueOf(eventEntity.getType()));
+ event.setRealmId(eventEntity.getRealmId());
+ event.setClientId(eventEntity.getClientId());
+ event.setUserId(eventEntity.getUserId());
+ event.setSessionId(eventEntity.getSessionId());
+ event.setIpAddress(eventEntity.getIpAddress());
+ event.setError(eventEntity.getError());
try {
- Map<String, String> details = mapper.readValue(o.getDetailsJson(), mapType);
- e.setDetails(details);
+ Map<String, String> details = mapper.readValue(eventEntity.getDetailsJson(), mapType);
+ event.setDetails(details);
} catch (IOException ex) {
logger.error("Failed to read log details", ex);
}
- return e;
+ return event;
+ }
+
+ static AdminEventEntity convertAdminEvent(AdminEvent adminEvent, boolean includeRepresentation) {
+ AdminEventEntity adminEventEntity = new AdminEventEntity();
+ adminEventEntity.setId(UUID.randomUUID().toString());
+ adminEventEntity.setTime(adminEvent.getTime());
+ adminEventEntity.setRealmId(adminEvent.getRealmId());
+ setAuthDetails(adminEventEntity, adminEvent.getAuthDetails());
+ adminEventEntity.setOperationType(adminEvent.getOperationType().toString());
+ adminEventEntity.setResourcePath(adminEvent.getResourcePath());
+ adminEventEntity.setError(adminEvent.getError());
+
+ if(includeRepresentation) {
+ adminEventEntity.setRepresentation(adminEvent.getRepresentation());
+ }
+ return adminEventEntity;
+ }
+
+ static AdminEvent convertAdminEvent(AdminEventEntity adminEventEntity) {
+ AdminEvent adminEvent = new AdminEvent();
+ adminEvent.setTime(adminEventEntity.getTime());
+ adminEvent.setRealmId(adminEventEntity.getRealmId());
+ setAuthDetails(adminEvent, adminEventEntity);
+ adminEvent.setOperationType(OperationType.valueOf(adminEventEntity.getOperationType()));
+ adminEvent.setResourcePath(adminEventEntity.getResourcePath());
+ adminEvent.setError(adminEventEntity.getError());
+
+ if(adminEventEntity.getRepresentation() != null) {
+ adminEvent.setRepresentation(adminEventEntity.getRepresentation());
+ }
+ return adminEvent;
+ }
+
+ private static void setAuthDetails(AdminEventEntity adminEventEntity, AuthDetails authDetails) {
+ adminEventEntity.setAuthRealmId(authDetails.getRealmId());
+ adminEventEntity.setAuthClientId(authDetails.getClientId());
+ adminEventEntity.setAuthUserId(authDetails.getUserId());
+ adminEventEntity.setAuthIpAddress(authDetails.getIpAddress());
+ }
+
+ private static void setAuthDetails(AdminEvent adminEvent, AdminEventEntity adminEventEntity) {
+ AuthDetails authDetails = new AuthDetails();
+ authDetails.setRealmId(adminEventEntity.getAuthRealmId());
+ authDetails.setClientId(adminEventEntity.getAuthClientId());
+ authDetails.setUserId(adminEventEntity.getAuthUserId());
+ authDetails.setIpAddress(adminEventEntity.getAuthIpAddress());
+ adminEvent.setAuthDetails(authDetails);
}
}
diff --git a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
new file mode 100644
index 0000000..c614d76
--- /dev/null
+++ b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
@@ -0,0 +1,132 @@
+package org.keycloak.events.mongo;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.OperationType;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.BasicDBObjectBuilder;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+
+public class MongoAdminEventQuery implements AdminEventQuery{
+
+ private Integer firstResult;
+ private Integer maxResults;
+ private DBCollection audit;
+ private final BasicDBObject query;
+
+ public MongoAdminEventQuery(DBCollection audit) {
+ this.audit = audit;
+ query = new BasicDBObject();
+ }
+
+ @Override
+ public AdminEventQuery realm(String realmId) {
+ query.put("realmId", realmId);
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery operation(OperationType... operations) {
+ List<String> operationStrings = new LinkedList<String>();
+ for (OperationType e : operations) {
+ operationStrings.add(e.toString());
+ }
+ query.put("operationType", new BasicDBObject("$in", operationStrings));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authRealm(String authRealmId) {
+ query.put("authRealmId", authRealmId);
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authClient(String authClientId) {
+ query.put("authClientId", authClientId);
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authUser(String authUserId) {
+ query.put("authUserId", authUserId);
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authIpAddress(String ipAddress) {
+ query.put("authIpAddress", ipAddress);
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery resourcePath(String resourcePath) {
+ query.put("resourcePath", Pattern.compile(resourcePath));
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery fromTime(String fromTime) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ Long from = null;
+ try {
+ from = df.parse(fromTime).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ query.put("time", BasicDBObjectBuilder.start("$gte", from).get());
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery toTime(String toTime) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ Long to = null;
+ try {
+ to = df.parse(toTime).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ query.put("time", BasicDBObjectBuilder.start("$lte", to).get());
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery firstResult(int firstResult) {
+ this.firstResult = firstResult;
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery maxResults(int maxResults) {
+ this.maxResults = maxResults;
+ return this;
+ }
+
+ @Override
+ public List<AdminEvent> getResultList() {
+ DBCursor cur = audit.find(query).sort(new BasicDBObject("time", -1));
+ if (firstResult != null) {
+ cur.skip(firstResult);
+ }
+ if (maxResults != null) {
+ cur.limit(maxResults);
+ }
+
+ List<AdminEvent> events = new LinkedList<AdminEvent>();
+ while (cur.hasNext()) {
+ events.add(MongoEventStoreProvider.convertAdminEvent((BasicDBObject) cur.next()));
+ }
+
+ return events;
+ }
+
+}
diff --git a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java
index c2569cc..75165c7 100755
--- a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java
+++ b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java
@@ -118,7 +118,7 @@ public class MongoEventQuery implements EventQuery {
List<Event> events = new LinkedList<Event>();
while (cur.hasNext()) {
- events.add(MongoEventStoreProvider.convert((BasicDBObject) cur.next()));
+ events.add(MongoEventStoreProvider.convertEvent((BasicDBObject) cur.next()));
}
return events;
diff --git a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java
index 65b6573..27e1ea5 100755
--- a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java
+++ b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java
@@ -3,6 +3,11 @@ package org.keycloak.events.mongo;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
+
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.AuthDetails;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.events.Event;
import org.keycloak.events.EventQuery;
import org.keycloak.events.EventStoreProvider;
@@ -15,11 +20,13 @@ import java.util.Map;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class MongoEventStoreProvider implements EventStoreProvider {
-
+
private DBCollection events;
+ private DBCollection adminEvents;
- public MongoEventStoreProvider(DBCollection events) {
+ public MongoEventStoreProvider(DBCollection events, DBCollection adminEvents) {
this.events = events;
+ this.adminEvents = adminEvents;
}
@Override
@@ -47,27 +54,55 @@ public class MongoEventStoreProvider implements EventStoreProvider {
@Override
public void onEvent(Event event) {
- events.insert(convert(event));
+ events.insert(convertEvent(event));
+ }
+
+ @Override
+ public AdminEventQuery createAdminQuery() {
+ return new MongoAdminEventQuery(adminEvents);
+ }
+
+ @Override
+ public void clearAdmin() {
+ adminEvents.remove(new BasicDBObject());
+ }
+
+ @Override
+ public void clearAdmin(String realmId) {
+ adminEvents.remove(new BasicDBObject("realmId", realmId));
+ }
+
+ @Override
+ public void clearAdmin(String realmId, long olderThan) {
+ BasicDBObject q = new BasicDBObject();
+ q.put("realmId", realmId);
+ q.put("time", new BasicDBObject("$lt", olderThan));
+ adminEvents.remove(q);
+ }
+
+ @Override
+ public void onEvent(AdminEvent adminEvent, boolean includeRepresentation) {
+ adminEvents.insert(convertAdminEvent(adminEvent, includeRepresentation));
}
@Override
public void close() {
}
- static DBObject convert(Event o) {
+ static DBObject convertEvent(Event event) {
BasicDBObject e = new BasicDBObject();
- e.put("time", o.getTime());
- e.put("type", o.getType().toString());
- e.put("realmId", o.getRealmId());
- e.put("clientId", o.getClientId());
- e.put("userId", o.getUserId());
- e.put("sessionId", o.getSessionId());
- e.put("ipAddress", o.getIpAddress());
- e.put("error", o.getError());
+ e.put("time", event.getTime());
+ e.put("type", event.getType().toString());
+ e.put("realmId", event.getRealmId());
+ e.put("clientId", event.getClientId());
+ e.put("userId", event.getUserId());
+ e.put("sessionId", event.getSessionId());
+ e.put("ipAddress", event.getIpAddress());
+ e.put("error", event.getError());
BasicDBObject details = new BasicDBObject();
- if (o.getDetails() != null) {
- for (Map.Entry<String, String> entry : o.getDetails().entrySet()) {
+ if (event.getDetails() != null) {
+ for (Map.Entry<String, String> entry : event.getDetails().entrySet()) {
details.put(entry.getKey(), entry.getValue());
}
}
@@ -76,16 +111,16 @@ public class MongoEventStoreProvider implements EventStoreProvider {
return e;
}
- static Event convert(BasicDBObject o) {
- Event e = new Event();
- e.setTime(o.getLong("time"));
- e.setType(EventType.valueOf(o.getString("type")));
- e.setRealmId(o.getString("realmId"));
- e.setClientId(o.getString("clientId"));
- e.setUserId(o.getString("userId"));
- e.setSessionId(o.getString("sessionId"));
- e.setIpAddress(o.getString("ipAddress"));
- e.setError(o.getString("error"));
+ static Event convertEvent(BasicDBObject o) {
+ Event event = new Event();
+ event.setTime(o.getLong("time"));
+ event.setType(EventType.valueOf(o.getString("type")));
+ event.setRealmId(o.getString("realmId"));
+ event.setClientId(o.getString("clientId"));
+ event.setUserId(o.getString("userId"));
+ event.setSessionId(o.getString("sessionId"));
+ event.setIpAddress(o.getString("ipAddress"));
+ event.setError(o.getString("error"));
BasicDBObject d = (BasicDBObject) o.get("details");
if (d != null) {
@@ -93,10 +128,57 @@ public class MongoEventStoreProvider implements EventStoreProvider {
for (Object k : d.keySet()) {
details.put((String) k, d.getString((String) k));
}
- e.setDetails(details);
+ event.setDetails(details);
+ }
+
+ return event;
+ }
+
+ private static DBObject convertAdminEvent(AdminEvent adminEvent, boolean includeRepresentation) {
+ BasicDBObject e = new BasicDBObject();
+ e.put("time", adminEvent.getTime());
+ e.put("realmId", adminEvent.getRealmId());
+ e.put("operationType", adminEvent.getOperationType().toString());
+ setAuthDetails(e, adminEvent.getAuthDetails());
+ e.put("resourcePath", adminEvent.getResourcePath());
+ e.put("error", adminEvent.getError());
+
+ if(includeRepresentation) {
+ e.put("representation", adminEvent.getRepresentation());
}
return e;
}
+
+ static AdminEvent convertAdminEvent(BasicDBObject o) {
+ AdminEvent adminEvent = new AdminEvent();
+ adminEvent.setTime(o.getLong("time"));
+ adminEvent.setRealmId(o.getString("realmId"));
+ adminEvent.setOperationType(OperationType.valueOf(o.getString("operationType")));
+ setAuthDetails(adminEvent, o);
+ adminEvent.setResourcePath(o.getString("resourcePath"));
+ adminEvent.setError(o.getString("error"));
+
+ if(o.getString("representation") != null) {
+ adminEvent.setRepresentation(o.getString("representation"));
+ }
+ return adminEvent;
+ }
+
+ private static void setAuthDetails(BasicDBObject e, AuthDetails authDetails) {
+ e.put("authRealmId", authDetails.getRealmId());
+ e.put("authClientId", authDetails.getClientId());
+ e.put("authUserId", authDetails.getUserId());
+ e.put("authIpAddress", authDetails.getIpAddress());
+ }
+
+ private static void setAuthDetails(AdminEvent adminEvent, BasicDBObject o) {
+ AuthDetails authDetails = new AuthDetails();
+ authDetails.setRealmId(o.getString("authRealmId"));
+ authDetails.setClientId(o.getString("authClientId"));
+ authDetails.setUserId(o.getString("authUserId"));
+ authDetails.setIpAddress(o.getString("authIpAddress"));
+ adminEvent.setAuthDetails(authDetails);
+ }
}
diff --git a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProviderFactory.java b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProviderFactory.java
index db4adeb..cbf41ac 100755
--- a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProviderFactory.java
+++ b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProviderFactory.java
@@ -24,9 +24,12 @@ public class MongoEventStoreProviderFactory implements EventStoreProviderFactory
MongoConnectionProvider connection = session.getProvider(MongoConnectionProvider.class);
DBCollection collection = connection.getDB().getCollection("events");
+ DBCollection adminCollection = connection.getDB().getCollection("adminEvents");
+
collection.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
+ adminCollection.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
- return new MongoEventStoreProvider(collection);
+ return new MongoEventStoreProvider(collection, adminCollection);
}
@Override
diff --git a/events/syslog/src/main/java/org/keycloak/events/log/SysLoggingEventListenerProvider.java b/events/syslog/src/main/java/org/keycloak/events/log/SysLoggingEventListenerProvider.java
index 0536286..14188a8 100755
--- a/events/syslog/src/main/java/org/keycloak/events/log/SysLoggingEventListenerProvider.java
+++ b/events/syslog/src/main/java/org/keycloak/events/log/SysLoggingEventListenerProvider.java
@@ -1,5 +1,6 @@
package org.keycloak.events.log;
+import org.keycloak.events.admin.AdminEvent;
import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.productivity.java.syslog4j.SyslogConstants;
@@ -59,6 +60,33 @@ public class SysLoggingEventListenerProvider implements EventListenerProvider {
}
@Override
+ public void onEvent(AdminEvent adminEvent, boolean includeRepresentation) {
+ int level = adminEvent.getError() != null ? SyslogConstants.LEVEL_ERROR : SyslogConstants.LEVEL_INFO;
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("operationType=");
+ sb.append(adminEvent.getOperationType());
+ sb.append(", realmId=");
+ sb.append(adminEvent.getAuthDetails().getRealmId());
+ sb.append(", clientId=");
+ sb.append(adminEvent.getAuthDetails().getClientId());
+ sb.append(", userId=");
+ sb.append(adminEvent.getAuthDetails().getUserId());
+ sb.append(", ipAddress=");
+ sb.append(adminEvent.getAuthDetails().getIpAddress());
+ sb.append(", resourcePath=");
+ sb.append(adminEvent.getResourcePath());
+
+ if (adminEvent.getError() != null) {
+ sb.append(", error=");
+ sb.append(adminEvent.getError());
+ }
+
+ syslogger.log(level, sb.toString());
+ }
+
+ @Override
public void close() {
}
diff --git a/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 97c5645..9c1bac9 100755
--- a/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -3,7 +3,7 @@
<dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
- <module name="org.apache.httpcomponents" slot="4.3"/>
+ <module name="org.apache.httpcomponents"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/demo-template/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/demo-template/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 97c5645..9c1bac9 100755
--- a/examples/demo-template/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/demo-template/customer-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -3,7 +3,7 @@
<dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
- <module name="org.apache.httpcomponents" slot="4.3"/>
+ <module name="org.apache.httpcomponents"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
\ No newline at end of file
examples/demo-template/pom.xml 21(+21 -0)
diff --git a/examples/demo-template/pom.xml b/examples/demo-template/pom.xml
index 2e10aa1..eb179f0 100755
--- a/examples/demo-template/pom.xml
+++ b/examples/demo-template/pom.xml
@@ -37,4 +37,25 @@
<module>third-party</module>
<module>third-party-cdi</module>
</modules>
+
+ <profiles>
+ <profile>
+ <id>no-keycloak-json</id>
+ <activation>
+ <property>
+ <name>no-keycloak-json</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-war-plugin</artifactId>
+ <configuration>
+ <packagingExcludes>**/keycloak.json</packagingExcludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
</project>
diff --git a/examples/demo-template/product-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/demo-template/product-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 97c5645..9c1bac9 100755
--- a/examples/demo-template/product-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/demo-template/product-app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -3,7 +3,7 @@
<dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
- <module name="org.apache.httpcomponents" slot="4.3"/>
+ <module name="org.apache.httpcomponents"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/demo-template/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/demo-template/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 97c5645..9c1bac9 100755
--- a/examples/demo-template/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/demo-template/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -3,7 +3,7 @@
<dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
- <module name="org.apache.httpcomponents" slot="4.3"/>
+ <module name="org.apache.httpcomponents"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 97c5645..9c1bac9 100755
--- a/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -3,7 +3,7 @@
<dependencies>
<!-- the Demo code uses classes in these modules. These are optional to import if you are not using
Apache Http Client or the HttpClientBuilder that comes with the adapter core -->
- <module name="org.apache.httpcomponents" slot="4.3"/>
+ <module name="org.apache.httpcomponents"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProvider.java b/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProvider.java
index 8bd001f..d81288e 100755
--- a/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProvider.java
+++ b/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProvider.java
@@ -1,5 +1,7 @@
package org.keycloak.examples.providers.events;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventType;
@@ -13,9 +15,11 @@ import java.util.Set;
public class SysoutEventListenerProvider implements EventListenerProvider {
private Set<EventType> excludedEvents;
+ private Set<OperationType> excludedAdminOperations;
- public SysoutEventListenerProvider(Set<EventType> excludedEvents) {
+ public SysoutEventListenerProvider(Set<EventType> excludedEvents, Set<OperationType> excludedAdminOpearations) {
this.excludedEvents = excludedEvents;
+ this.excludedAdminOperations = excludedAdminOpearations;
}
@Override
@@ -28,6 +32,16 @@ public class SysoutEventListenerProvider implements EventListenerProvider {
}
}
+ @Override
+ public void onEvent(AdminEvent event, boolean includeRepresentation) {
+ // Ignore excluded operations
+ if (excludedAdminOperations != null && excludedAdminOperations.contains(event.getOperationType())) {
+ return;
+ } else {
+ System.out.println("EVENT: " + toString(event));
+ }
+ }
+
private String toString(Event event) {
StringBuilder sb = new StringBuilder();
@@ -64,7 +78,31 @@ public class SysoutEventListenerProvider implements EventListenerProvider {
return sb.toString();
}
+
+ private String toString(AdminEvent adminEvent) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("operationType=");
+ sb.append(adminEvent.getOperationType());
+ sb.append(", realmId=");
+ sb.append(adminEvent.getAuthDetails().getRealmId());
+ sb.append(", clientId=");
+ sb.append(adminEvent.getAuthDetails().getClientId());
+ sb.append(", userId=");
+ sb.append(adminEvent.getAuthDetails().getUserId());
+ sb.append(", ipAddress=");
+ sb.append(adminEvent.getAuthDetails().getIpAddress());
+ sb.append(", resourcePath=");
+ sb.append(adminEvent.getResourcePath());
+
+ if (adminEvent.getError() != null) {
+ sb.append(", error=");
+ sb.append(adminEvent.getError());
+ }
+
+ return sb.toString();
+ }
+
@Override
public void close() {
}
diff --git a/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java b/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java
index 3f87d81..e7eb8d5 100755
--- a/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java
+++ b/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java
@@ -4,6 +4,7 @@ import org.keycloak.Config;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventListenerProviderFactory;
import org.keycloak.events.EventType;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
@@ -16,10 +17,11 @@ import java.util.Set;
public class SysoutEventListenerProviderFactory implements EventListenerProviderFactory {
private Set<EventType> excludedEvents;
+ private Set<OperationType> excludedAdminOperations;
@Override
public EventListenerProvider create(KeycloakSession session) {
- return new SysoutEventListenerProvider(excludedEvents);
+ return new SysoutEventListenerProvider(excludedEvents, excludedAdminOperations);
}
@Override
@@ -31,6 +33,14 @@ public class SysoutEventListenerProviderFactory implements EventListenerProvider
excludedEvents.add(EventType.valueOf(e));
}
}
+
+ String[] excludesOperations = config.getArray("excludesOperations");
+ if (excludesOperations != null) {
+ excludedAdminOperations = new HashSet<>();
+ for (String e : excludesOperations) {
+ excludedAdminOperations.add(OperationType.valueOf(e));
+ }
+ }
}
@Override
diff --git a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java
new file mode 100644
index 0000000..6b3a5da
--- /dev/null
+++ b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java
@@ -0,0 +1,174 @@
+package org.keycloak.examples.providers.events;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.OperationType;
+
+/**
+ * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
+ */
+public class MemAdminEventQuery implements AdminEventQuery {
+
+ private List<AdminEvent> adminEvents;
+
+ private int first;
+ private int max;
+
+ public MemAdminEventQuery(List<AdminEvent> events) {
+ this.adminEvents = events;
+ }
+
+
+ @Override
+ public AdminEventQuery realm(String realmId) {
+ Iterator<AdminEvent> itr = adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (!itr.next().getRealmId().equals(realmId)) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery operation(OperationType... operations) {
+ Iterator<AdminEvent> itr = this.adminEvents.iterator();
+ while (itr.hasNext()) {
+ AdminEvent next = itr.next();
+ boolean include = false;
+ for (OperationType e : operations) {
+ if (next.getOperationType().equals(e)) {
+ include = true;
+ break;
+ }
+ }
+ if (!include) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authRealm(String authRealmId) {
+ Iterator<AdminEvent> itr = adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (!itr.next().getAuthDetails().getRealmId().equals(authRealmId)) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authClient(String authClientId) {
+ Iterator<AdminEvent> itr = adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (!itr.next().getAuthDetails().getClientId().equals(authClientId)) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authUser(String authUserId) {
+ Iterator<AdminEvent> itr = adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (!itr.next().getAuthDetails().getUserId().equals(authUserId)) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery authIpAddress(String ipAddress) {
+ Iterator<AdminEvent> itr = adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (!itr.next().getAuthDetails().getIpAddress().equals(ipAddress)) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery resourcePath(String resourcePath) {
+ Iterator<AdminEvent> itr = this.adminEvents.iterator();
+ while (itr.hasNext()) {
+ if(!Pattern.compile(resourcePath).matcher(itr.next().getResourcePath()).find()) {
+ itr.remove();
+ }
+ }
+ return (AdminEventQuery) this;
+ }
+
+ @Override
+ public AdminEventQuery fromTime(String fromTime) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ Long from = null;
+ try {
+ from = df.parse(fromTime).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ Iterator<AdminEvent> itr = this.adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (!(itr.next().getTime() >= from)) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery toTime(String toTime) {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ Long to = null;
+ try {
+ to = df.parse(toTime).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ Iterator<AdminEvent> itr = this.adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (!(itr.next().getTime() <= to)) {
+ itr.remove();
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery firstResult(int result) {
+ this.first = result;
+ return this;
+ }
+
+ @Override
+ public AdminEventQuery maxResults(int results) {
+ this.max = results;
+ return this;
+ }
+
+ @Override
+ public List<AdminEvent> getResultList() {
+ if (adminEvents.size() < first) {
+ return Collections.emptyList();
+ }
+ int end = first + max <= adminEvents.size() ? first + max : adminEvents.size();
+
+ return adminEvents.subList(first, end);
+ }
+
+}
diff --git a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProvider.java b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProvider.java
index 592455c..e0b2d4c 100755
--- a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProvider.java
+++ b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProvider.java
@@ -1,5 +1,8 @@
package org.keycloak.examples.providers.events;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.events.Event;
import org.keycloak.events.EventQuery;
import org.keycloak.events.EventStoreProvider;
@@ -16,10 +19,16 @@ import java.util.Set;
public class MemEventStoreProvider implements EventStoreProvider {
private final List<Event> events;
private final Set<EventType> excludedEvents;
+ private final List<AdminEvent> adminEvents;
+ private final Set<OperationType> excludedOperations;
- public MemEventStoreProvider(List<Event> events, Set<EventType> excludedEvents) {
+ public MemEventStoreProvider(List<Event> events, Set<EventType> excludedEvents,
+ List<AdminEvent> adminEvents, Set<OperationType> excludedOperations) {
this.events = events;
this.excludedEvents = excludedEvents;
+
+ this.adminEvents = adminEvents;
+ this.excludedOperations = excludedOperations;
}
@Override
@@ -65,6 +74,48 @@ public class MemEventStoreProvider implements EventStoreProvider {
}
@Override
+ public AdminEventQuery createAdminQuery() {
+ return new MemAdminEventQuery(new LinkedList<>(adminEvents));
+ }
+
+ @Override
+ public void clearAdmin() {
+
+ }
+
+ @Override
+ public void clearAdmin(String realmId) {
+ synchronized(adminEvents) {
+ Iterator<AdminEvent> itr = adminEvents.iterator();
+ while (itr.hasNext()) {
+ if (itr.next().getRealmId().equals(realmId)) {
+ itr.remove();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void clearAdmin(String realmId, long olderThan) {
+ synchronized(adminEvents) {
+ Iterator<AdminEvent> itr = adminEvents.iterator();
+ while (itr.hasNext()) {
+ AdminEvent e = itr.next();
+ if (e.getRealmId().equals(realmId) && e.getTime() < olderThan) {
+ itr.remove();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onEvent(AdminEvent adminEvent, boolean includeRepresentation) {
+ if (excludedOperations == null || !excludedOperations.contains(adminEvent.getOperationType())) {
+ adminEvents.add(0, adminEvent);
+ }
+ }
+
+ @Override
public void close() {
}
diff --git a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProviderFactory.java b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProviderFactory.java
index 83fd80e..d09b1a3 100755
--- a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProviderFactory.java
+++ b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventStoreProviderFactory.java
@@ -5,6 +5,8 @@ import org.keycloak.events.Event;
import org.keycloak.events.EventStoreProvider;
import org.keycloak.events.EventStoreProviderFactory;
import org.keycloak.events.EventType;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
@@ -20,12 +22,13 @@ import java.util.Set;
public class MemEventStoreProviderFactory implements EventStoreProviderFactory {
private List<Event> events;
-
private Set<EventType> excludedEvents;
+ private List<AdminEvent> adminEvents;
+ private Set<OperationType> excludedOperations;
@Override
public EventStoreProvider create(KeycloakSession session) {
- return new MemEventStoreProvider(events, excludedEvents);
+ return new MemEventStoreProvider(events, excludedEvents, adminEvents, excludedOperations);
}
@Override
@@ -39,6 +42,14 @@ public class MemEventStoreProviderFactory implements EventStoreProviderFactory {
excludedEvents.add(EventType.valueOf(e));
}
}
+
+ String excludesOperations = config.get("excludesOperations");
+ if (excludesOperations != null) {
+ excludedOperations = new HashSet<>();
+ for (String e : excludesOperations.split(",")) {
+ excludedOperations.add(OperationType.valueOf(e));
+ }
+ }
}
@Override
@@ -49,6 +60,8 @@ public class MemEventStoreProviderFactory implements EventStoreProviderFactory {
public void close() {
events = null;
excludedEvents = null;
+ adminEvents = null;
+ excludedOperations = null;
}
@Override
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
index 6ec2960..208cc6a 100644
--- a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class ExportSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "export";
}
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
index b562f3f..90cb6ac 100644
--- a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class ImportSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "import";
}
diff --git a/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java b/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java
index e956b14..2c9843e 100644
--- a/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java
+++ b/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class AccountSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "account";
}
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java
index c3d738b..94db863 100644
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java
@@ -8,6 +8,12 @@ import org.keycloak.provider.Spi;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ThemeSpi implements Spi {
+
+ @Override
+ public boolean isPrivate() {
+ return true;
+ }
+
@Override
public String getName() {
return "theme";
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
index 3ee1fbe..56f6008 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -303,6 +303,18 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'RealmEventsCtrl'
})
+ .when('/realms/:realm/admin-events', {
+ templateUrl : resourceUrl + '/partials/realm-events-admin.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ serverInfo : function(ServerInfoLoader) {
+ return ServerInfoLoader();
+ }
+ },
+ controller : 'RealmAdminEventsCtrl'
+ })
.when('/realms/:realm/events-settings', {
templateUrl : resourceUrl + '/partials/realm-events-config.html',
resolve : {
@@ -1387,7 +1399,6 @@ module.directive('kcReadOnly', function() {
scope.$watch(attrs.kcReadOnly, function(readOnly) {
if (readOnly) {
- console.debug('readonly');
element.find('input').each(disable);
element.find('button').each(disable);
element.find('select').each(disable);
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index f8ad7c3..f60e20e 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -122,10 +122,6 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
$scope.changeRealm = function(selectedRealm) {
$location.url("/realms/" + selectedRealm);
}
-
- $scope.refresh = function() {
- Current.refresh();
- }
});
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, WhoAmI, $location, Dialog, Notifications, Auth) {
@@ -1180,7 +1176,7 @@ module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, real
}
});
-module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmEventsConfig, RealmEvents, realm, serverInfo, $location, Notifications, TimeUnit, Dialog) {
+module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmEventsConfig, RealmEvents, RealmAdminEvents, realm, serverInfo, $location, Notifications, TimeUnit, Dialog) {
$scope.realm = realm;
$scope.eventsConfig = eventsConfig;
@@ -1198,7 +1194,7 @@ module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmE
$scope.eventSelectOptions = {
'multiple': true,
'simple_tags': true,
- 'tags': serverInfo.eventTypes
+ 'tags': serverInfo.enums['eventType']
};
var oldCopy = angular.copy($scope.eventsConfig);
@@ -1238,6 +1234,14 @@ module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmE
});
});
};
+
+ $scope.clearAdminEvents = function() {
+ Dialog.confirmDelete($scope.realm.realm, 'admin-events', function() {
+ RealmAdminEvents.remove({ id : $scope.realm.realm }, function() {
+ Notifications.success("The admin events has been cleared.");
+ });
+ });
+ };
});
module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm, serverInfo) {
@@ -1247,7 +1251,7 @@ module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm, server
$scope.eventSelectOptions = {
'multiple': true,
'simple_tags': true,
- 'tags': serverInfo.eventTypes
+ 'tags': serverInfo.enums['eventType']
};
$scope.query = {
@@ -1308,6 +1312,105 @@ module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm, server
$scope.update();
});
+module.controller('RealmAdminEventsCtrl', function($scope, RealmAdminEvents, realm, serverInfo, $modal, $filter) {
+ $scope.realm = realm;
+ $scope.page = 0;
+
+ $scope.query = {
+ id : realm.realm,
+ max : 5,
+ first : 0
+ }
+
+ $scope.adminEnabledEventOperationsOptions = {
+ 'multiple': true,
+ 'simple_tags': true,
+ 'tags': serverInfo.enums['operationType']
+ };
+
+ $scope.update = function() {
+ $scope.query.first = 0;
+ for (var i in $scope.query) {
+ if ($scope.query[i] === '') {
+ delete $scope.query[i];
+ }
+ }
+ $scope.events = RealmAdminEvents.query($scope.query);
+ }
+
+ $scope.reset = function() {
+ $scope.query.first = 0;
+ $scope.query.max = 5;
+ $scope.query.operationTypes = '';
+ $scope.query.resourcePath = '';
+ $scope.query.authRealm = '';
+ $scope.query.authClient = '';
+ $scope.query.authUser = '';
+ $scope.query.authIpAddress = '';
+ $scope.query.dateFrom = '';
+ $scope.query.dateTo = '';
+
+ $scope.update();
+ }
+
+ $scope.queryUpdate = function() {
+ for (var i in $scope.query) {
+ if ($scope.query[i] === '') {
+ delete $scope.query[i];
+ }
+ }
+ $scope.events = RealmAdminEvents.query($scope.query);
+ }
+
+ $scope.firstPage = function() {
+ $scope.query.first = 0;
+ $scope.queryUpdate();
+ }
+
+ $scope.previousPage = function() {
+ $scope.query.first -= parseInt($scope.query.max);
+ if ($scope.query.first < 0) {
+ $scope.query.first = 0;
+ }
+ $scope.queryUpdate();
+ }
+
+ $scope.nextPage = function() {
+ $scope.query.first += parseInt($scope.query.max);
+ $scope.queryUpdate();
+ }
+
+ $scope.update();
+
+ $scope.viewRepresentation = function(event) {
+ $modal.open({
+ templateUrl: resourceUrl + '/partials/modal/realm-events-admin-representation.html',
+ controller: 'RealmAdminEventsModalCtrl',
+ resolve: {
+ event: function () {
+ return event;
+ }
+ }
+ })
+ }
+
+ $scope.viewAuth = function(event) {
+ $modal.open({
+ templateUrl: resourceUrl + '/partials/modal/realm-events-admin-auth.html',
+ controller: 'RealmAdminEventsModalCtrl',
+ resolve: {
+ event: function () {
+ return event;
+ }
+ }
+ })
+ }
+});
+
+module.controller('RealmAdminEventsModalCtrl', function($scope, $filter, event) {
+ $scope.event = event;
+});
+
module.controller('RealmBruteForceCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications, TimeUnit) {
console.log('RealmBruteForceCtrl');
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
index 7708821..e9f09a2 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -180,6 +180,12 @@ module.factory('RealmEvents', function($resource) {
});
});
+module.factory('RealmAdminEvents', function($resource) {
+ return $resource(authUrl + '/admin/realms/:id/admin-events', {
+ id : '@realm'
+ });
+});
+
module.factory('RealmLDAPConnectionTester', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/testLDAPConnection');
});
@@ -824,15 +830,13 @@ module.factory('ClientOrigins', function($resource) {
});
});
-module.factory('Current', function(Realm, $route) {
+module.factory('Current', function(Realm, $route, $rootScope) {
var current = {};
current.realms = {};
current.realm = null;
- current.clients = {};
- current.client = null;
- current.refresh = function() {
+ $rootScope.$on('$routeChangeStart', function() {
current.realm = null;
current.realms = Realm.query(null, function(realms) {
if ($route.current.params.realm) {
@@ -843,9 +847,7 @@ module.factory('Current', function(Realm, $route) {
}
}
});
- }
-
- current.refresh();
+ });
return current;
});
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-auth.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-auth.html
new file mode 100644
index 0000000..8f765f0
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-auth.html
@@ -0,0 +1,8 @@
+<div style="padding: 20px 20px 0 20px">
+<table class="table table-striped table-bordered">
+ <tr><td width="100px">Realm</td><td>{{event.authDetails.realmId}}</td></tr>
+ <tr><td width="100px">Client</td><td>{{event.authDetails.clientId}}</td></tr>
+ <tr><td width="100px">User</td><td>{{event.authDetails.userId}}</td></tr>
+ <tr><td width="100px">IP Address</td><td>{{event.authDetails.ipAddress}}</td></tr>
+</table>
+</div>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-representation.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-representation.html
new file mode 100644
index 0000000..837a164
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/realm-events-admin-representation.html
@@ -0,0 +1,3 @@
+<div style="padding: 20px 20px 10px 20px">
+ <pre ng-bind = "{{event.representation}} | json"></pre>
+</div>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html
index 7c45014..8df1629 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html
@@ -5,7 +5,8 @@
</h1>
<ul class="nav nav-tabs">
- <li data-ng-class="(path[2] == 'events') && 'active'"><a href="#/realms/{{realm.realm}}/events">View</a></li>
+ <li data-ng-class="(path[2] == 'events') && 'active'"><a href="#/realms/{{realm.realm}}/events">Login Events</a></li>
+ <li data-ng-class="(path[2] == 'admin-events') && 'active'"><a href="#/realms/{{realm.realm}}/admin-events">Admin Events</a></li>
<li data-ng-class="(path[2] == 'events-settings') && 'active'"><a href="#/realms/{{realm.realm}}/events-settings">Config</a></li>
</ul>
@@ -121,4 +122,4 @@
</table>
</div>
-<kc-menu></kc-menu>
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html
new file mode 100755
index 0000000..8469d71
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html
@@ -0,0 +1,127 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+ <h1>
+ <span><strong>Admin Events</strong> {{realm.realm|capitalize}}</span>
+ <kc-tooltip>Displays saved admin events for the realm. Events are related to admin account, for example a realm creation. To enable persisted events go to config.</kc-tooltip>
+ </h1>
+
+ <ul class="nav nav-tabs">
+ <li data-ng-class="(path[2] == 'events') && 'active'"><a href="#/realms/{{realm.realm}}/events">Login Events</a></li>
+ <li data-ng-class="(path[2] == 'admin-events') && 'active'"><a href="#/realms/{{realm.realm}}/admin-events">Admin Events</a></li>
+ <li data-ng-class="(path[2] == 'events-settings') && 'active'"><a href="#/realms/{{realm.realm}}/events-settings">Config</a></li>
+ </ul>
+ <h2></h2>
+
+ <div id="content">
+ <table class="table table-striped table-bordered">
+ <thead>
+ <tr>
+ <th class="kc-table-actions" colspan="5">
+ <div class="pull-right">
+ <select data-ng-model="query.max" data-ng-click="update()" class="btn btn-default">
+ <option>5</option>
+ <option>10</option>
+ <option>50</option>
+ <option>100</option>
+ </select>
+ <button class="btn btn-default" data-ng-click="filter = !filter">
+ <span class="glyphicon glyphicon-plus" data-ng-show="!filter"></span>
+ <span class="glyphicon glyphicon-minus" data-ng-show="filter"></span>
+ Filter
+ </button>
+ <button class="btn btn-default btn-primary" data-ng-click="update()">Update</button>
+ <button class="btn btn-default btn-primary" data-ng-click="reset()">Reset</button>
+ </div>
+ <form class="form-horizontal" data-ng-show="filter">
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="adminEnabledEventOperations">Operation Types</label>
+ <div class="col-sm-5">
+ <input ui-select2="adminEnabledEventOperationsOptions" id="adminEnabledEventOperations" ng-model="query.operationTypes" data-placeholder="Select operations..."/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="resource">Resource Path</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="resource" name="resource" data-ng-model="query.resourcePath">
+ </div>
+ <span tooltip-placement="right" tooltip="Filter by resource path. Supports wildcards '*' to match a single part of the path and '**' matches multiple parts. For example 'realms/*/clients/asbc' matches client with id asbc in any realm, while or 'realms/master/**' matches anything in the master realm." class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="dateFrom">Date (From)</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="date" id="dateFrom" name="dateFrom" data-ng-model="query.dateFrom">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="dateTo">Date (To)</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="date" id="dateTo" name="dateTo" data-ng-model="query.dateTo">
+ </div>
+ </div>
+
+ <fieldset>
+ <legend><span class="text">Authentication Details</span></legend>
+
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="realm">Realm</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="realm" name="realm" data-ng-model="query.authRealm">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="client">Client</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="client" name="client" data-ng-model="query.authClient">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="user">User</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="user" name="user" data-ng-model="query.authUser">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="ipAddress">IP Address</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="ipAddress" name="ipAddress" data-ng-model="query.authIpAddress">
+ </div>
+ </div>
+ </fieldset>
+
+ </form>
+ </th>
+ </tr>
+ <tr>
+ <th width="100px">Time</th>
+ <th width="180px">Operation Type</th>
+ <th width="180px">Resource Path</th>
+ <th>Details</th>
+ </tr>
+ </thead>
+ <tfoot>
+ <tr>
+ <td colspan="7">
+ <button data-ng-click="firstPage()" class="first" ng-disabled="query.first == 0"><i data-ng-class="query.first == 0 && 'text-muted'" class="fa fa-angle-double-left"></i></button>
+ <button data-ng-click="previousPage()" class="prev" ng-disabled="query.first == 0"><i data-ng-class="query.first == 0 && 'text-muted'" class="fa fa-angle-left"></i></button>
+ <button data-ng-click="nextPage()" class="next" ng-disabled="events.length < query.max"><i data-ng-class="events.length < query.max && 'text-muted'" class="fa fa-angle-right"></i></button>
+ </td>
+ </tr>
+ </tfoot>
+ <tbody>
+ <tr data-ng-repeat="event in events">
+ <td>{{event.time|date:'shortDate'}}<br>{{event.time|date:'mediumTime'}}</td>
+ <td data-ng-class="events-error">{{event.operationType}}</td>
+ <td>{{event.resourcePath}}</td>
+ <td>
+ <button type="button" class="btn btn-default btn-xs" data-ng-click="viewAuth(event)">
+ Auth
+ </button>
+ <button type="button" class="btn btn-default btn-xs" data-ng-click="viewRepresentation(event)" data-ng-show="event.representation">
+ Representation
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html
index 1b34385..11c2f00 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html
@@ -1,70 +1,114 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
- <h1><strong>Events</strong> {{realm.realm|capitalize}}</span> Events</h1>
+ <h1>
+ <span><strong>Events Config</strong> {{realm.realm|capitalize}}</span>
+ <kc-tooltip>Displays configuration options to enable persistence of user and admin events.</kc-tooltip>
+ </h1>
<ul class="nav nav-tabs">
- <li data-ng-class="(path[2] == 'events') && 'active'"><a href="#/realms/{{realm.realm}}/events">View</a></li>
+ <li data-ng-class="(path[2] == 'events') && 'active'"><a href="#/realms/{{realm.realm}}/events">Login Events</a></li>
+ <li data-ng-class="(path[2] == 'admin-events') && 'active'"><a href="#/realms/{{realm.realm}}/admin-events">Admin Events</a></li>
<li data-ng-class="(path[2] == 'events-settings') && 'active'"><a href="#/realms/{{realm.realm}}/events-settings">Config</a></li>
</ul>
+ <div id="content">
+ <h2><span>{{realm.realm}}</span> Events Config</h2>
- <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageEvents">
- <fieldset class="border-top">
- <div class="form-group">
- <label class="col-md-2 control-label" for="enabled">Save Events</label>
- <div class="col-md-6">
- <input ng-model="eventsConfig.eventsEnabled" name="enabled" id="enabled" onoffswitch />
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageEvents">
+
+ <fieldset class="border-top">
+ <div class="form-group">
+ <label class="col-md-2 control-label" for="eventsListeners" class="control-label">Event Listeners</label>
+
+ <div class="col-md-6">
+ <select ui-select2 ng-model="eventsConfig.eventsListeners" data-placeholder="Select an action..." multiple>
+ <option ng-repeat="listener in eventListeners" value="{{listener}}">{{listener}}</option>
+ </select>
+ </div>
+
+ <span tooltip-placement="right" tooltip="Configure what listeners receive events for the realm." class="fa fa-info-circle"></span>
</div>
- <kc-tooltip>If enabled events are saved to the database which makes events available to the admin and account management consoles.</kc-tooltip>
- </div>
+ </fieldset>
- <div class="form-group" data-ng-show="eventsConfig.eventsEnabled">
- <label class="col-md-2 control-label" for="enabledEventTypes" class="control-label">Saved Types</label>
+ <fieldset>
+ <legend><span class="text">Login Events Settings</span></legend>
- <div class="col-md-6">
- <input ui-select2="eventSelectOptions" id="enabledEventTypes" ng-model="eventsConfig.enabledEventTypes" data-placeholder="Select event types..."/>
+ <div class="form-group">
+ <label class="col-md-2 control-label" for="enabled">Save Events</label>
+ <div class="col-md-6">
+ <input ng-model="eventsConfig.eventsEnabled" name="enabled" id="enabled" onoffswitch />
+ </div>
+ <span tooltip-placement="right" tooltip="If enabled login events are saved to the database which makes events available to the admin and account management consoles." class="fa fa-info-circle"></span>
</div>
- <kc-tooltip>Configure what event types are saved. By default events related to login and users modifying their accounts are persisted.</kc-tooltip>
- </div>
+ <div class="form-group" data-ng-show="eventsConfig.eventsEnabled">
+ <label class="col-md-2 control-label" for="enabledEventTypes" class="control-label">Saved Types</label>
- <div class="form-group" data-ng-show="access.manageEvents && eventsConfig.eventsEnabled">
- <label class="col-md-2 control-label" for="password">Clear Events</label>
- <div class="col-md-6">
- <button class="btn btn-danger" type="submit" data-ng-click="clearEvents()" >Clear Events</button>
+ <div class="col-md-6">
+ <input ui-select2="eventSelectOptions" id="enabledEventTypes" ng-model="eventsConfig.enabledEventTypes" data-placeholder="Select event types..."/>
+ </div>
+
+ <span tooltip-placement="right" tooltip="Configure what event types are saved. By default events related to login and users modifying their accounts are persisted." class="fa fa-info-circle"></span>
</div>
- <kc-tooltip>Deletes all events in the database.</kc-tooltip>
- </div>
- <div class="form-group input-select" data-ng-show="eventsConfig.eventsEnabled">
- <label class="col-md-2 control-label" for="expiration">Expiration</label>
- <div class="col-md-6 form-inline">
- <input class="form-control" type="number" data-ng-model="eventsConfig.eventsExpiration" id="expiration" name="expiration" min="0"/>
- <select class="form-control" name="expirationUnit" data-ng-model="eventsConfig.expirationUnit" >
- <option>Minutes</option>
- <option>Hours</option>
- <option>Days</option>
- </select>
+
+ <div class="form-group" data-ng-show="access.manageEvents && eventsConfig.eventsEnabled">
+ <label class="col-md-2 control-label" for="password">Clear Events</label>
+ <div class="col-md-6">
+ <button class="btn btn-danger" type="submit" data-ng-click="clearEvents()" >Clear Events</button>
+ </div>
+ <span tooltip-placement="right" tooltip="Deletes all events in the database." class="fa fa-info-circle"></span>
</div>
- <div class="col-sm-1"></div>
- <kc-tooltip>Sets the expiration for events. Expired events are periodically deleted from the database.</kc-tooltip>
- </div>
+ <div class="form-group input-select" data-ng-show="eventsConfig.eventsEnabled">
+ <label class="col-md-2 control-label" for="expiration">Expiration</label>
+ <div class="col-md-6">
+ <input class="form-control" type="number" data-ng-model="eventsConfig.eventsExpiration" id="expiration" name="expiration" min="0"/>
+ </div>
+ <div class="col-md-2 select-kc">
+ <select name="expirationUnit" data-ng-model="eventsConfig.expirationUnit" >
+ <option>Minutes</option>
+ <option>Hours</option>
+ <option>Days</option>
+ </select>
+ <span tooltip-placement="right" tooltip="Sets the expiration for events. Expired events are periodically deleted from the database." class="fa fa-info-circle"></span>
+ </div>
+ </div>
+ </fieldset>
+
+
+ <fieldset>
+ <legend><span class="text">Admin Events Settings</span></legend>
- <div class="form-group">
- <label class="col-md-2 control-label" for="eventsListeners" class="control-label">Listeners</label>
+ <div class="form-group">
+ <label class="col-md-2 control-label" for="adminEventsEnabled">Save Events</label>
+ <div class="col-md-6">
+ <input ng-model="eventsConfig.adminEventsEnabled" name="adminEventsEnabled" id="adminEventsEnabled" onoffswitch />
+ </div>
- <div class="col-md-6">
- <select ui-select2 ng-model="eventsConfig.eventsListeners" data-placeholder="Select an action..." multiple>
- <option ng-repeat="listener in eventListeners" value="{{listener}}">{{listener}}</option>
- </select>
+ <span tooltip-placement="right" tooltip="If enabled admin events are saved to the database which makes events available to the admin console." class="fa fa-info-circle"></span>
</div>
- <kc-tooltip>Configure what listeners receive events for the realm.</kc-tooltip>
- </div>
- </fieldset>
+ <div class="form-group" data-ng-show="eventsConfig.adminEventsEnabled">
+ <label class="col-md-2 control-label" for="adminEventsDetailsEnabled">Include Representation</label>
+ <div class="col-md-6">
+ <input ng-model="eventsConfig.adminEventsDetailsEnabled" name="adminEventsDetailsEnabled" id="adminEventsDetailsEnabled" onoffswitch />
+ </div>
- <div class="pull-right form-actions" data-ng-show="access.manageEvents">
- <button data-kc-reset data-ng-show="changed">Clear changes</button>
- <button data-kc-save data-ng-show="changed">Save</button>
- </div>
- </form>
-</div>
+ <span tooltip-placement="right" tooltip="Include JSON representation for create and update requests." class="fa fa-info-circle"></span>
+ </div>
+
+ <div class="form-group" data-ng-show="access.manageEvents && eventsConfig.adminEventsEnabled">
+ <label class="col-md-2 control-label" for="password">Clear Admin Events</label>
+ <div class="col-md-6">
+ <button class="btn btn-danger" type="submit" data-ng-click="clearAdminEvents()" >Clear Admin Events</button>
+ </div>
+ <span tooltip-placement="right" tooltip="Deletes all admin events in the database." class="fa fa-info-circle"></span>
+ </div>
+
+ </fieldset>
-<kc-menu></kc-menu>
+ <div class="pull-right form-actions" data-ng-show="access.manageEvents">
+ <button data-kc-reset data-ng-show="changed">Clear changes</button>
+ <button data-kc-save data-ng-show="changed">Save</button>
+ </div>
+ </form>
+ </div>
+</div>
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java b/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java
index cb2877b..cde73ce 100644
--- a/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java
+++ b/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java
@@ -8,6 +8,12 @@ import org.keycloak.provider.Spi;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class EmailSpi implements Spi {
+
+ @Override
+ public boolean isPrivate() {
+ return true;
+ }
+
@Override
public String getName() {
return "email";
diff --git a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/beans/AdminEventBean.java b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/beans/AdminEventBean.java
new file mode 100644
index 0000000..ca225fc
--- /dev/null
+++ b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/beans/AdminEventBean.java
@@ -0,0 +1,37 @@
+package org.keycloak.email.freemarker.beans;
+
+import java.util.Date;
+
+import org.keycloak.events.admin.AdminEvent;
+
+/**
+ * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
+ */
+public class AdminEventBean {
+
+ private AdminEvent adminEvent;
+
+ public AdminEventBean(AdminEvent adminEvent) {
+ this.adminEvent = adminEvent;
+ }
+
+ public Date getDate() {
+ return new Date(adminEvent.getTime());
+ }
+
+ public String getOperationType() {
+ return adminEvent.getOperationType().toString().toLowerCase();
+ }
+
+ public String getClient() {
+ return adminEvent.getAuthDetails().getClientId();
+ }
+
+ public String getIpAddress() {
+ return adminEvent.getAuthDetails().getIpAddress();
+ }
+
+ public String getResourcePath() {
+ return adminEvent.getResourcePath();
+ }
+}
diff --git a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java
index 74f5b4a..f99292a 100644
--- a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java
+++ b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java
@@ -8,6 +8,12 @@ import org.keycloak.provider.Spi;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class LoginFormsSpi implements Spi {
+
+ @Override
+ public boolean isPrivate() {
+ return true;
+ }
+
@Override
public String getName() {
return "login";
integration/js/src/main/resources/keycloak.js 24(+12 -12)
diff --git a/integration/js/src/main/resources/keycloak.js b/integration/js/src/main/resources/keycloak.js
index 13b813b..7ff1959 100755
--- a/integration/js/src/main/resources/keycloak.js
+++ b/integration/js/src/main/resources/keycloak.js
@@ -336,6 +336,16 @@
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 (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
@@ -463,16 +473,6 @@
return promise.promise;
}
- function clearToken() {
- if (kc.token) {
- setToken(null, null, null);
- kc.onAuthLogout && kc.onAuthLogout();
- if (kc.loginRequired) {
- kc.login();
- }
- }
- }
-
function setToken(token, refreshToken, idToken) {
if (token) {
kc.token = token;
@@ -697,7 +697,7 @@
if ((!kc.sessionId || kc.sessionId == data.session) && data.loggedIn) {
promise.setSuccess();
} else {
- clearToken();
+ kc.clearToken();
promise.setError();
}
};
@@ -832,7 +832,7 @@
if (error) {
promise.setError();
} else {
- clearToken();
+ kc.clearToken();
promise.setSuccess();
}
});
diff --git a/integration/keycloak-as7-subsystem/pom.xml b/integration/keycloak-as7-subsystem/pom.xml
index 7eb6c22..f1ee2ed 100755
--- a/integration/keycloak-as7-subsystem/pom.xml
+++ b/integration/keycloak-as7-subsystem/pom.xml
@@ -71,25 +71,25 @@
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-naming</artifactId>
- <version>7.1.1.Final</version>
+ <version>${jboss.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-server</artifactId>
- <version>7.1.1.Final</version>
+ <version>${jboss.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-ee</artifactId>
- <version>7.1.1.Final</version>
+ <version>${jboss.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-web</artifactId>
- <version>7.1.1.Final</version>
+ <version>${jboss.version}</version>
</dependency>
<dependency>
integration/pom.xml 4(+1 -3)
diff --git a/integration/pom.xml b/integration/pom.xml
index f79be4e..5c1f132 100755
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -22,9 +22,7 @@
<module>as7-eap6/adapter</module>
<module>jetty</module>
<module>undertow</module>
- <module>wildfly-adapter</module>
- <module>wildfly-extensions</module>
- <module>keycloak-subsystem</module>
+ <module>wildfly</module>
<module>keycloak-as7-subsystem</module>
<module>js</module>
<module>installed</module>
diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProvider.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProvider.java
index 4e50685..153f20c 100644
--- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProvider.java
+++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProvider.java
@@ -6,8 +6,10 @@ import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -17,18 +19,28 @@ import java.util.List;
* @version $Revision: 1 $
*/
public class KeycloakAuthenticationProvider implements AuthenticationProvider {
+ private GrantedAuthoritiesMapper grantedAuthoritiesMapper;
+
+ public void setGrantedAuthoritiesMapper(GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
+ this.grantedAuthoritiesMapper = grantedAuthoritiesMapper;
+ }
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
-
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication;
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
for (String role : token.getAccount().getRoles()) {
grantedAuthorities.add(new KeycloakRole(role));
}
+ return new KeycloakAuthenticationToken(token.getAccount(), mapAuthorities(grantedAuthorities));
+ }
- return new KeycloakAuthenticationToken(token.getAccount(), grantedAuthorities);
+ private Collection<? extends GrantedAuthority> mapAuthorities(
+ Collection<? extends GrantedAuthority> authorities) {
+ return grantedAuthoritiesMapper != null
+ ? grantedAuthoritiesMapper.mapAuthorities(authorities)
+ : authorities;
}
@Override
diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandler.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandler.java
index 2879a06..6a64765 100644
--- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandler.java
+++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandler.java
@@ -1,14 +1,16 @@
package org.keycloak.adapters.springsecurity.authentication;
import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.springsecurity.AdapterDeploymentContextBean;
+import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.Assert;
-import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -22,7 +24,6 @@ import java.io.IOException;
*/
public class KeycloakLogoutHandler implements LogoutHandler {
- public static final String SSO_LOGOUT_COMPLETE_PARAM = "sso_complete";
private static final Logger log = LoggerFactory.getLogger(KeycloakLogoutHandler.class);
private AdapterDeploymentContextBean deploymentContextBean;
@@ -40,30 +41,24 @@ public class KeycloakLogoutHandler implements LogoutHandler {
return;
}
- if (Boolean.valueOf(request.getParameter(SSO_LOGOUT_COMPLETE_PARAM))) {
- // already logged out
- return;
- }
-
try {
handleSingleSignOut(request, response);
} catch (IOException e) {
- throw new IllegalStateException("Unable to redirect to SSO url!", e);
+ throw new IllegalStateException("Unable to make logout admin request!", e);
}
}
- protected String createRedirectUrl(HttpServletRequest request) {
-
- return UriComponentsBuilder.fromHttpUrl(request.getRequestURL().toString())
- .replaceQueryParam(SSO_LOGOUT_COMPLETE_PARAM, true).build().toUriString();
- }
-
protected void handleSingleSignOut(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ KeycloakAuthenticationToken authentication = (KeycloakAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
KeycloakDeployment deployment = deploymentContextBean.getDeployment();
- String redirectUrl = createRedirectUrl(request);
+ RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) authentication.getAccount().getKeycloakSecurityContext();
- response.sendRedirect(deployment.getLogoutUrl().queryParam("redirect_uri", redirectUrl).build().toASCIIString());
+ try {
+ session.logout(deployment);
+ } catch (Exception e) {
+ log.error("Unable to complete Keycloak single sign out", e);
+ }
}
}
diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java
index 34dd14d..6cbcbe6 100644
--- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java
+++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/config/KeycloakWebSecurityConfigurerAdapter.java
@@ -17,8 +17,8 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
-import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
/**
* Provides a convenient base class for creating a {@link WebSecurityConfigurer}
@@ -37,13 +37,11 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
return new AdapterDeploymentContextBean();
}
- @Bean
protected AuthenticationEntryPoint authenticationEntryPoint()
{
return new KeycloakAuthenticationEntryPoint();
}
- @Bean
protected KeycloakAuthenticationProvider keycloakAuthenticationProvider() {
return new KeycloakAuthenticationProvider();
}
@@ -69,7 +67,6 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
return new HttpSessionManager();
}
- @Bean
protected KeycloakLogoutHandler keycloakLogoutHandler() {
return new KeycloakLogoutHandler(adapterDeploymentContextBean());
}
@@ -78,12 +75,20 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
@Override
protected void configure(HttpSecurity http) throws Exception {
+
http
+ .csrf().requireCsrfProtectionMatcher(keycloakCsrfRequestMatcher())
+ .and()
.sessionManagement()
.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
.and()
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
- .addFilterBefore(keycloakAuthenticationProcessingFilter(), X509AuthenticationFilter.class)
- .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
+ .addFilterBefore(keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
+ .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
+ .and()
+ .logout()
+ .addLogoutHandler(keycloakLogoutHandler())
+ .logoutUrl("/sso/logout").permitAll()
+ .logoutSuccessUrl("/");
}
}
diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponse.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponse.java
index c0b5759..ade1b21 100644
--- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponse.java
+++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponse.java
@@ -1,11 +1,15 @@
package org.keycloak.adapters.springsecurity.facade;
import org.keycloak.adapters.HttpFacade.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
/**
* Concrete Keycloak {@link Response response} implementation wrapping an {@link HttpServletResponse}.
@@ -15,6 +19,7 @@ import java.io.OutputStream;
*/
class WrappedHttpServletResponse implements Response {
+ private static final Logger log = LoggerFactory.getLogger(WrappedHttpServletResponse.class);
private final HttpServletResponse response;
/**
@@ -50,11 +55,23 @@ class WrappedHttpServletResponse implements Response {
cookie.setMaxAge(maxAge);
cookie.setSecure(secure);
- cookie.setHttpOnly(httpOnly);
+ this.setHttpOnly(cookie, httpOnly);
response.addCookie(cookie);
}
+ private void setHttpOnly(Cookie cookie, boolean httpOnly) {
+ Method method;
+ try {
+ method = Cookie.class.getMethod("setHttpOnly", boolean.class);
+ method.invoke(cookie, httpOnly);
+ } catch (NoSuchMethodException e) {
+ log.warn("Unable to set httpOnly on cookie [{}]; no such method on javax.servlet.http.Cookie", cookie.getName());
+ } catch (ReflectiveOperationException e) {
+ log.error("Unable to set httpOnly on cookie [{}]", cookie.getName(), e);
+ }
+ }
+
@Override
public void setStatus(int status) {
response.setStatus(status);
diff --git a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProviderTest.java b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProviderTest.java
index a94ea11..6f81c0b 100644
--- a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProviderTest.java
+++ b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakAuthenticationProviderTest.java
@@ -8,6 +8,8 @@ import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.mockito.internal.util.collections.Sets;
import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import java.security.Principal;
@@ -20,14 +22,12 @@ import static org.mockito.Mockito.*;
* Keycloak authentication provider tests.
*/
public class KeycloakAuthenticationProviderTest {
-
private KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
private KeycloakAuthenticationToken token;
private Set<String> roles = Sets.newSet("user", "admin");
@Before
public void setUp() throws Exception {
-
Principal principal = mock(Principal.class);
RefreshableKeycloakSecurityContext securityContext = mock(RefreshableKeycloakSecurityContext.class);
KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, securityContext);
@@ -39,7 +39,7 @@ public class KeycloakAuthenticationProviderTest {
public void testAuthenticate() throws Exception {
Authentication result = provider.authenticate(token);
assertNotNull(result);
- assertEquals(roles.size(), result.getAuthorities().size());
+ assertEquals(roles, AuthorityUtils.authorityListToSet(result.getAuthorities()));
assertTrue(result.isAuthenticated());
assertNotNull(result.getPrincipal());
assertNotNull(result.getCredentials());
@@ -51,4 +51,16 @@ public class KeycloakAuthenticationProviderTest {
assertTrue(provider.supports(KeycloakAuthenticationToken.class));
assertFalse(provider.supports(PreAuthenticatedAuthenticationToken.class));
}
+
+ @Test
+ public void testGrantedAuthoritiesMapper() throws Exception {
+ SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper();
+ grantedAuthorityMapper.setPrefix("ROLE_");
+ grantedAuthorityMapper.setConvertToUpperCase(true);
+ provider.setGrantedAuthoritiesMapper(grantedAuthorityMapper);
+
+ Authentication result = provider.authenticate(token);
+ assertEquals(Sets.newSet("ROLE_USER", "ROLE_ADMIN"),
+ AuthorityUtils.authorityListToSet(result.getAuthorities()));
+ }
}
diff --git a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponseTest.java b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponseTest.java
index 408d9c5..2dd3a8c 100644
--- a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponseTest.java
+++ b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/facade/WrappedHttpServletResponseTest.java
@@ -48,6 +48,7 @@ public class WrappedHttpServletResponseTest {
assertEquals(COOKIE_DOMAIN, mockResponse.getCookie(COOKIE_NAME).getDomain());
assertEquals(maxAge, mockResponse.getCookie(COOKIE_NAME).getMaxAge());
assertEquals(COOKIE_VALUE, mockResponse.getCookie(COOKIE_NAME).getValue());
+ assertEquals(true, mockResponse.getCookie(COOKIE_NAME).isHttpOnly());
}
@Test
integration/wildfly/pom.xml 22(+22 -0)
diff --git a/integration/wildfly/pom.xml b/integration/wildfly/pom.xml
new file mode 100644
index 0000000..25df76d
--- /dev/null
+++ b/integration/wildfly/pom.xml
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <name>Keycloak WildFly Integration</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-wildfly-integration-pom</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>wildfly-adapter</module>
+ <module>wildfly-extensions</module>
+ <module>wildfly-server-subsystem</module>
+ <module>wildfly-adapter-subsystem</module>
+ </modules>
+</project>
\ No newline at end of file
diff --git a/integration/wildfly/wildfly-adapter-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension b/integration/wildfly/wildfly-adapter-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
new file mode 100644
index 0000000..b759b38
--- /dev/null
+++ b/integration/wildfly/wildfly-adapter-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
@@ -0,0 +1 @@
+org.keycloak.subsystem.adapter.extension.KeycloakExtension
diff --git a/integration/wildfly/wildfly-adapter-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml b/integration/wildfly/wildfly-adapter-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml
new file mode 100644
index 0000000..a2187f6
--- /dev/null
+++ b/integration/wildfly/wildfly-adapter-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Template used by WildFly build when directed to include Keycloak subsystem in a configuration. -->
+<config>
+ <extension-module>org.keycloak.keycloak-adapter-subsystem</extension-module>
+ <subsystem xmlns="urn:jboss:domain:keycloak:1.1">
+ </subsystem>
+</config>
integration/wildfly/wildfly-server-subsystem/pom.xml 106(+106 -0)
diff --git a/integration/wildfly/wildfly-server-subsystem/pom.xml b/integration/wildfly/wildfly-server-subsystem/pom.xml
new file mode 100755
index 0000000..71bb0fd
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+~ Copyright 2013 JBoss Inc
+~
+~ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-parent</artifactId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>keycloak-wildfly-server-subsystem</artifactId>
+ <name>Keycloak Server Subsystem</name>
+ <description/>
+ <packaging>jar</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <redirectTestOutputToFile>false</redirectTestOutputToFile>
+ <enableAssertions>true</enableAssertions>
+ <systemProperties>
+ <property>
+ <name>jboss.home</name>
+ <value>${jboss.home}</value>
+ </property>
+ </systemProperties>
+ <includes>
+ <include>**/*TestCase.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.wildfly.core</groupId>
+ <artifactId>wildfly-controller</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly.core</groupId>
+ <artifactId>wildfly-server</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-web-common</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging-annotations</artifactId>
+ <version>${jboss-logging-tools.version}</version>
+ <!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
+ projects that depend on this project.-->
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging-processor</artifactId>
+ <!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
+ projects that depend on this project.-->
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.wildfly.core</groupId>
+ <artifactId>wildfly-subsystem-test-framework</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adapter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java
new file mode 100755
index 0000000..7f86d79
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.keycloak.subsystem.server.extension;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
+
+/**
+ * This service keeps track of the entire Keycloak management model so as to provide
+ * adapter configuration to each deployment at deploy time.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+public final class KeycloakAdapterConfigService {
+
+ private static final KeycloakAdapterConfigService INSTANCE = new KeycloakAdapterConfigService();
+
+ public static KeycloakAdapterConfigService getInstance() {
+ return INSTANCE;
+ }
+
+ // key=auth-server deployment name; value=web-context
+ private final Map<String, String> webContexts = new HashMap<String, String>();
+
+
+
+ private KeycloakAdapterConfigService() {
+ }
+
+ public void addServerDeployment(String deploymentName, String webContext) {
+ this.webContexts.put(deploymentName, webContext);
+ }
+
+ public String getWebContext(String deploymentName) {
+ return webContexts.get(deploymentName);
+ }
+
+ public void removeServerDeployment(String deploymentName) {
+ this.webContexts.remove(deploymentName);
+ }
+
+ public boolean isWebContextUsed(String webContext) {
+ return webContexts.containsValue(webContext);
+ }
+
+ public boolean isKeycloakServerDeployment(String deploymentName) {
+ return this.webContexts.containsKey(deploymentName);
+ }
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakDependencyProcessor.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakDependencyProcessor.java
new file mode 100755
index 0000000..b40eb35
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakDependencyProcessor.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.keycloak.subsystem.server.extension;
+
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.module.ModuleDependency;
+import org.jboss.as.server.deployment.module.ModuleSpecification;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleIdentifier;
+import org.jboss.modules.ModuleLoader;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+public abstract class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
+
+ private static final ModuleIdentifier KEYCLOAK_JBOSS_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-jboss-adapter-core");
+ private static final ModuleIdentifier KEYCLOAK_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-adapter-core");
+ private static final ModuleIdentifier KEYCLOAK_CORE = ModuleIdentifier.create("org.keycloak.keycloak-core");
+
+ @Override
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+
+ // Next phase, need to detect if this is a Keycloak deployment. If not, don't add the modules.
+
+ final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
+ final ModuleLoader moduleLoader = Module.getBootModuleLoader();
+ addCommonModules(moduleSpecification, moduleLoader);
+ addPlatformSpecificModules(moduleSpecification, moduleLoader);
+ }
+
+ private void addCommonModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
+ // ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JBOSS_CORE_ADAPTER, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE_ADAPTER, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE, false, false, false, false));
+ }
+
+ abstract protected void addPlatformSpecificModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader);
+
+ @Override
+ public void undeploy(DeploymentUnit du) {
+
+ }
+
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java
new file mode 100755
index 0000000..145b475
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.keycloak.subsystem.server.extension;
+
+import org.jboss.as.controller.Extension;
+import org.jboss.as.controller.ExtensionContext;
+import org.jboss.as.controller.ModelVersion;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ResourceDefinition;
+import org.jboss.as.controller.SubsystemRegistration;
+import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
+import org.jboss.as.controller.parsing.ExtensionParsingContext;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.keycloak.subsystem.server.extension.authserver.AuthServerDefinition;
+import org.keycloak.subsystem.server.logging.KeycloakLogger;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
+
+
+/**
+ * Main Extension class for the subsystem.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+public class KeycloakExtension implements Extension {
+
+ public static final String SUBSYSTEM_NAME = "keycloak-server";
+ public static final String NAMESPACE = "urn:jboss:domain:keycloak-server:1.1";
+ private static final KeycloakSubsystemParser PARSER = new KeycloakSubsystemParser();
+ static final PathElement PATH_SUBSYSTEM = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
+ private static final String RESOURCE_NAME = KeycloakExtension.class.getPackage().getName() + ".LocalDescriptions";
+ private static final ModelVersion MGMT_API_VERSION = ModelVersion.create(1,1,0);
+ static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
+ private static final ResourceDefinition KEYCLOAK_SUBSYSTEM_RESOURCE = new KeycloakSubsystemDefinition();
+ static final AuthServerDefinition AUTH_SERVER_DEFINITION = new AuthServerDefinition();
+
+ public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
+ StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
+ for (String kp : keyPrefix) {
+ prefix.append('.').append(kp);
+ }
+ return new StandardResourceDescriptionResolver(prefix.toString(), RESOURCE_NAME, KeycloakExtension.class.getClassLoader(), true, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initializeParsers(final ExtensionParsingContext context) {
+ context.setSubsystemXmlMapping(SUBSYSTEM_NAME, KeycloakExtension.NAMESPACE, PARSER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initialize(final ExtensionContext context) {
+ KeycloakLogger.ROOT_LOGGER.debug("Activating Keycloak Extension");
+ final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, MGMT_API_VERSION);
+
+ ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
+ registration.registerSubModel(AUTH_SERVER_DEFINITION);
+ subsystem.registerXMLElementWriter(PARSER);
+ }
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
new file mode 100755
index 0000000..622c010
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.keycloak.subsystem.server.extension;
+
+import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.server.AbstractDeploymentChainStep;
+import org.jboss.as.server.DeploymentProcessorTarget;
+import org.jboss.as.server.deployment.Phase;
+import org.jboss.dmr.ModelNode;
+
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.keycloak.subsystem.server.extension.authserver.KeycloakServerDeploymentProcessor;
+
+/**
+ * The Keycloak subsystem add update handler.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
+
+ static final KeycloakSubsystemAdd INSTANCE = new KeycloakSubsystemAdd();
+
+ @Override
+ protected void performBoottime(final OperationContext context, ModelNode operation, final ModelNode model) {
+ context.addStep(new AbstractDeploymentChainStep() {
+ @Override
+ protected void execute(DeploymentProcessorTarget processorTarget) {
+ processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, 0, chooseDependencyProcessor());
+ processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME,
+ Phase.POST_MODULE, // PHASE
+ Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
+ new KeycloakServerDeploymentProcessor());
+ }
+ }, OperationContext.Stage.RUNTIME);
+ }
+
+ private DeploymentUnitProcessor chooseDependencyProcessor() {
+ return new KeycloakDependencyProcessorWildFly();
+ }
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java
new file mode 100644
index 0000000..f553188
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.keycloak.subsystem.server.extension;
+
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+
+/**
+ * Definition of subsystem=keycloak.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
+ protected KeycloakSubsystemDefinition() {
+ super(KeycloakExtension.SUBSYSTEM_PATH,
+ KeycloakExtension.getResourceDescriptionResolver("subsystem"),
+ KeycloakSubsystemAdd.INSTANCE,
+ ReloadRequiredRemoveStepHandler.INSTANCE
+ );
+ }
+
+ @Override
+ public void registerOperations(ManagementResourceRegistration resourceRegistration) {
+ super.registerOperations(resourceRegistration);
+ resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
+ }
+
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java
new file mode 100755
index 0000000..921c576
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.keycloak.subsystem.server.extension;
+
+import org.keycloak.subsystem.server.extension.authserver.AuthServerDefinition;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
+import org.jboss.as.controller.operations.common.Util;
+import org.jboss.as.controller.parsing.ParseUtils;
+import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.Property;
+import org.jboss.staxmapper.XMLElementReader;
+import org.jboss.staxmapper.XMLElementWriter;
+import org.jboss.staxmapper.XMLExtendedStreamReader;
+import org.jboss.staxmapper.XMLExtendedStreamWriter;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * The subsystem parser, which uses stax to read and write to and from xml
+ */
+class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>, XMLElementWriter<SubsystemMarshallingContext> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> list) throws XMLStreamException {
+ // Require no attributes
+ ParseUtils.requireNoAttributes(reader);
+ ModelNode addKeycloakSub = Util.createAddOperation(PathAddress.pathAddress(KeycloakExtension.PATH_SUBSYSTEM));
+ list.add(addKeycloakSub);
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ if (reader.getLocalName().equals(AuthServerDefinition.TAG_NAME)) {
+ readAuthServer(reader, list);
+ }
+ }
+ }
+
+ // used for debugging
+ private int nextTag(XMLExtendedStreamReader reader) throws XMLStreamException {
+ return reader.nextTag();
+ }
+
+ private void readAuthServer(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
+ String authServerName = readNameAttribute(reader);
+ ModelNode addAuthServer = new ModelNode();
+ addAuthServer.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
+ PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
+ PathElement.pathElement(AuthServerDefinition.TAG_NAME, authServerName));
+ addAuthServer.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ SimpleAttributeDefinition def = AuthServerDefinition.lookup(tagName);
+ if (def == null) throw new XMLStreamException("Unknown auth-server tag " + tagName);
+ def.parseAndSetParameter(reader.getElementText(), addAuthServer, reader);
+ }
+
+ list.add(addAuthServer);
+ }
+
+ // expects that the current tag will have one single attribute called "name"
+ private String readNameAttribute(XMLExtendedStreamReader reader) throws XMLStreamException {
+ String name = null;
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String attr = reader.getAttributeLocalName(i);
+ if (attr.equals("name")) {
+ name = reader.getAttributeValue(i);
+ continue;
+ }
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ if (name == null) {
+ throw ParseUtils.missingRequired(reader, Collections.singleton("name"));
+ }
+ return name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
+ context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
+ writeAuthServers(writer, context);
+ writer.writeEndElement();
+ }
+
+ private void writeAuthServers(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
+ if (!context.getModelNode().get(AuthServerDefinition.TAG_NAME).isDefined()) {
+ return;
+ }
+ for (Property authServer : context.getModelNode().get(AuthServerDefinition.TAG_NAME).asPropertyList()) {
+ writer.writeStartElement(AuthServerDefinition.TAG_NAME);
+ writer.writeAttribute("name", authServer.getName());
+ ModelNode authServerElements = authServer.getValue();
+ for (AttributeDefinition element : AuthServerDefinition.ALL_ATTRIBUTES) {
+ element.marshallAsElement(authServerElements, writer);
+ }
+
+ writer.writeEndElement();
+ }
+ }
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakLogger.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakLogger.java
new file mode 100755
index 0000000..bf6053b
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakLogger.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.keycloak.subsystem.server.logging;
+
+import org.jboss.logging.BasicLogger;
+import org.jboss.logging.Logger;
+import org.jboss.logging.annotations.LogMessage;
+import org.jboss.logging.annotations.Message;
+import org.jboss.logging.annotations.MessageLogger;
+
+import static org.jboss.logging.Logger.Level.INFO;
+
+/**
+ * This interface to be fleshed out later when error messages are fully externalized.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+@MessageLogger(projectCode = "KEYCLOAK")
+public interface KeycloakLogger extends BasicLogger {
+
+ /**
+ * A logger with a category of the package name.
+ */
+ KeycloakLogger ROOT_LOGGER = Logger.getMessageLogger(KeycloakLogger.class, "org.jboss.keycloak");
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakMessages.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakMessages.java
new file mode 100755
index 0000000..710c054
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakMessages.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.keycloak.subsystem.server.logging;
+
+import org.jboss.logging.Messages;
+import org.jboss.logging.annotations.MessageBundle;
+
+/**
+ * This interface to be fleshed out later when error messages are fully externalized.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2012 Red Hat Inc.
+ */
+@MessageBundle(projectCode = "KEYCLOAK")
+public interface KeycloakMessages {
+
+ /**
+ * The messages
+ */
+ KeycloakMessages MESSAGES = Messages.getBundle(KeycloakMessages.class);
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension b/integration/wildfly/wildfly-server-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
new file mode 100644
index 0000000..36b9edb
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
@@ -0,0 +1 @@
+org.keycloak.subsystem.server.extension.KeycloakExtension
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties b/integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties
new file mode 100755
index 0000000..f09e3bd
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties
@@ -0,0 +1,26 @@
+keycloak-server.subsystem=Keycloak subsystem
+keycloak-server.subsystem.add=Operation Adds Keycloak subsystem
+keycloak-server.subsystem.remove=Operation removes Keycloak subsystem
+keycloak-server.subsystem.auth-server=Keycloak Auth Server
+keycloak-server.subsystem.realm=A Keycloak realm.
+keycloak-server.subsystem.secure-deployment=A deployment secured by Keycloak.
+
+
+keycloak-server.auth-server=A Keycloak Auth Server
+keycloak-server.auth-server.add=Add an Auth Server to the subsystem.
+keycloak-server.auth-server.remove=Remove an Auth Server from the subsystem.
+keycloak-server.auth-server.add-provider=Add a provider service jar to the Keycloak auth server.
+keycloak-server.auth-server.add-provider.uploaded-file-name=The file name of the provider service jar to be added or updated.
+keycloak-server.auth-server.add-provider.bytes-to-upload=The bytes of the provider service jar to be added or updated.
+keycloak-server.auth-server.add-provider.redeploy=Redeploy the auth server after adding the provider. Ignored if auth server is disabled.
+keycloak-server.auth-server.add-provider.overwrite=Overwrite even if the uploaded-file-name already exists as an overlay.
+keycloak-server.auth-server.list-overlays=List the overlays uploaded for this auth server.
+keycloak-server.auth-server.remove-overlay=Remove a provider jar, theme jar, or keycloak-server.json that has been uploaded to the auth server.
+keycloak-server.auth-server.remove-overlay.overlay-file-path=The uploaded path and file name of the overlay to be removed.
+keycloak-server.auth-server.remove-overlay.redeploy=Redeploy the auth server after removing the overlay.
+keycloak-server.auth-server.update-server-config=Upload a new keycloak-server.json configuration file for the Keycloak auth server.
+keycloak-server.auth-server.update-server-config.bytes-to-upload=The bytes of the keycloak-server.json file to be added or updated.
+keycloak-server.auth-server.update-server-config.redeploy=Redeploy the auth server after updating the server config.
+keycloak-server.auth-server.update-server-config.overwrite=Overwrite even if keycloak-server.json already exitss as an overlay.
+keycloak-server.auth-server.enabled=Enable or disable the Auth Server.
+keycloak-server.auth-server.web-context=Web context the auth-server will use. Also, the module name of the auth-server deployment.
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd b/integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd
new file mode 100755
index 0000000..a8dd28e
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="urn:jboss:domain:keycloak-server:1.1"
+ xmlns="urn:jboss:domain:keycloak-server:1.1"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ version="1.0">
+
+ <!-- The subsystem root element -->
+ <xs:element name="subsystem" type="subsystem-type"/>
+
+ <xs:complexType name="subsystem-type">
+ <xs:annotation>
+ <xs:documentation>
+ <![CDATA[
+ The Keycloak server subsystem, used to configure the Keycloak server
+ ]]>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="auth-server" maxOccurs="1" minOccurs="0" type="auth-server-type"/>
+ </xs:choice>
+ </xs:complexType>
+
+ <xs:complexType name="auth-server-type">
+ <xs:all>
+ <xs:element name="web-context" type="xs:string" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="enabled" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+ </xs:all>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the war archive containing the Keycloak server web application.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+</xs:schema>
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml b/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
new file mode 100644
index 0000000..9f05130
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
@@ -0,0 +1,30 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
+<config>
+ <extension-module>org.jboss.as.connector</extension-module>
+ <subsystem xmlns="urn:jboss:domain:datasources:3.0">
+ <datasources>
+ <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
+ <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
+ <driver>h2</driver>
+ <security>
+ <user-name>sa</user-name>
+ <password>sa</password>
+ </security>
+ </datasource>
+ <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+ <connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
+ <driver>h2</driver>
+ <security>
+ <user-name>sa</user-name>
+ <password>sa</password>
+ </security>
+ </datasource>
+ <drivers>
+ <driver name="h2" module="com.h2database.h2">
+ <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
+ </driver>
+ </drivers>
+ </datasources>
+ </subsystem>
+</config>
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml b/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml
new file mode 100644
index 0000000..7f66f74
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Template used by WildFly build when directed to include Keycloak subsystem in a configuration. -->
+<config>
+ <extension-module>org.keycloak.keycloak-server-subsystem</extension-module>
+ <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
+ <auth-server name="main-auth-server">
+ <enabled>true</enabled>
+ <web-context>auth</web-context>
+ </auth-server>
+ </subsystem>
+</config>
diff --git a/integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java b/integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java
new file mode 100755
index 0000000..9f29a6f
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.keycloak.subsystem.server.extension;
+
+import java.io.IOException;
+
+import org.jboss.as.subsystem.test.AbstractSubsystemBaseTest;
+import org.jboss.dmr.ModelNode;
+import org.junit.Test;
+
+/**
+ * Tests all management expects for subsystem, parsing, marshaling, model definition and other
+ * Here is an example that allows you a fine grained controller over what is tested and how. So it can give you ideas what can be done and tested.
+ * If you have no need for advanced testing of subsystem you look at {@link AbstractSubsystemBaseTest} that testes same stuff but most of the code
+ * is hidden inside of test harness
+ *
+ * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
+ * @author Tomaz Cerar
+ * @author Marko Strukelj
+ */
+public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
+
+ public SubsystemParsingTestCase() {
+ super(KeycloakExtension.SUBSYSTEM_NAME, new KeycloakExtension());
+ }
+
+ @Test
+ public void testJson() throws Exception {
+ ModelNode node = new ModelNode();
+ node.get("enabled").set(true);
+ node.get("web-context").set("auth");
+
+ System.out.println("json=" + node.toJSONString(false));
+ }
+
+ @Override
+ protected String getSubsystemXml() throws IOException {
+ return readResource("keycloak-server-1.1.xml");
+ }
+
+ @Override
+ protected String getSubsystemXsdPath() throws Exception {
+ return "schema/wildfly-keycloak-server_1_1.xsd";
+ }
+
+ @Override
+ protected String[] getSubsystemTemplatePaths() throws IOException {
+ return new String[]{
+ "/subsystem-templates/keycloak-server.xml"
+ };
+ }
+}
diff --git a/integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml b/integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml
new file mode 100644
index 0000000..f05f8d1
--- /dev/null
+++ b/integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml
@@ -0,0 +1,6 @@
+<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
+ <auth-server name="main-auth-server">
+ <enabled>true</enabled>
+ <web-context>auth</web-context>
+ </auth-server>
+</subsystem>
\ No newline at end of file
misc/UpdatingDatabaseSchema.md 4(+2 -2)
diff --git a/misc/UpdatingDatabaseSchema.md b/misc/UpdatingDatabaseSchema.md
index 274669c..375d909 100644
--- a/misc/UpdatingDatabaseSchema.md
+++ b/misc/UpdatingDatabaseSchema.md
@@ -37,7 +37,7 @@ You can also have Liquibase and Hibernate create one for you. To do this follow
3. Make a copy of the database:
`cp keycloak.h2.db keycloak-old.h2.db`
3. Run KeycloakServer to make Hibernate update the schema:
- `mvn -f testsuite/integration exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='development-update'`
+ `mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='development-update'`
4. Wait until server is completely started, then stop it
5. View the difference:
`mvn -f connections/jpa-liquibase/pom.xml liquibase:diff -Durl=jdbc:h2:keycloak-old -DreferenceUrl=jdbc:h2:keycloak`
@@ -76,4 +76,4 @@ It should be added last to the `DefaultMongoUpdaterProvider#updates` array.
Testing database migration
--------------------------
-Get the database from an old version of Keycloak that includes the demo applications. Start the server with this and test it.
\ No newline at end of file
+Get the database from an old version of Keycloak that includes the demo applications. Start the server with this and test it.
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
index a0e5959..62dcd68 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
@@ -16,16 +16,15 @@ public class MigrationModelManager {
String storedVersion = model.getStoredVersion();
if (MigrationModel.LATEST_VERSION.equals(storedVersion)) return;
ModelVersion stored = null;
- if (storedVersion == null) stored = new ModelVersion(0, 0, 0);
- else stored = new ModelVersion(storedVersion);
+ if (storedVersion != null) new ModelVersion(storedVersion);
- if (stored.lessThan(MigrationTo1_2_0_CR1.VERSION)) {
- logger.info("Migrating older model to 1.2.0.RC1 updates");
+ if (stored == null || stored.lessThan(MigrationTo1_2_0_CR1.VERSION)) {
+ if (stored != null) {
+ logger.debug("Migrating older model to 1.2.0.RC1 updates");
+ }
new MigrationTo1_2_0_CR1().migrate(session);
}
model.setStoredVersion(MigrationModel.LATEST_VERSION);
-
-
}
}
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java b/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java
index f6b768c..e599146 100644
--- a/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class MigrationSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "migration";
}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
index 3c978f9..718a1c5 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
@@ -63,7 +63,10 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private long eventsExpiration;
private List<String> eventsListeners = new ArrayList<String>();
private List<String> enabledEventTypes = new ArrayList<String>();
-
+
+ protected boolean adminEventsEnabled;
+ protected boolean adminEventsDetailsEnabled;
+
private String masterAdminClient;
private boolean internationalizationEnabled;
@@ -391,6 +394,22 @@ public class RealmEntity extends AbstractIdentifiableEntity {
this.enabledEventTypes = enabledEventTypes;
}
+ public boolean isAdminEventsEnabled() {
+ return adminEventsEnabled;
+ }
+
+ public void setAdminEventsEnabled(boolean adminEventsEnabled) {
+ this.adminEventsEnabled = adminEventsEnabled;
+ }
+
+ public boolean isAdminEventsDetailsEnabled() {
+ return adminEventsDetailsEnabled;
+ }
+
+ public void setAdminEventsDetailsEnabled(boolean adminEventsDetailsEnabled) {
+ this.adminEventsDetailsEnabled = adminEventsDetailsEnabled;
+ }
+
public String getMasterAdminClient() {
return masterAdminClient;
}
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 8b901a2..dca2067 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -232,7 +232,15 @@ public interface RealmModel extends RoleContainerModel {
Set<String> getEnabledEventTypes();
void setEnabledEventTypes(Set<String> enabledEventTypes);
+
+ boolean isAdminEventsEnabled();
+
+ void setAdminEventsEnabled(boolean enabled);
+
+ boolean isAdminEventsDetailsEnabled();
+ void setAdminEventsDetailsEnabled(boolean enabled);
+
ClientModel getMasterAdminClient();
void setMasterAdminClient(ClientModel client);
diff --git a/model/api/src/main/java/org/keycloak/models/RealmSpi.java b/model/api/src/main/java/org/keycloak/models/RealmSpi.java
index 1c1429c..f531cd9 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class RealmSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "realm";
}
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java b/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java
index 6a22337..c17c02a 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class UserFederationSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
public String getName() {
return "userFederation";
}
diff --git a/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java b/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java
index e470db5..8755660 100644
--- a/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java
@@ -12,6 +12,11 @@ public class UserSessionSpi implements Spi {
public static final String NAME = "userSessions";
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/model/api/src/main/java/org/keycloak/models/UserSpi.java b/model/api/src/main/java/org/keycloak/models/UserSpi.java
index e68299c..1d6cd74 100755
--- a/model/api/src/main/java/org/keycloak/models/UserSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/UserSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class UserSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "user";
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 2a8da38..84248fd 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -14,6 +14,7 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -192,6 +193,10 @@ public class ModelToRepresentation {
rep.setEnabledEventTypes(new LinkedList<String>(realm.getEnabledEventTypes()));
}
+ rep.setAdminEventsEnabled(realm.isAdminEventsEnabled());
+
+ rep.setAdminEventsDetailsEnabled(realm.isAdminEventsDetailsEnabled());
+
return rep;
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 45221e5..578ecc9 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -410,10 +410,15 @@ public class RepresentationToModel {
if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme());
if (rep.getAdminTheme() != null) realm.setAdminTheme(rep.getAdminTheme());
if (rep.getEmailTheme() != null) realm.setEmailTheme(rep.getEmailTheme());
+
if (rep.isEventsEnabled() != null) realm.setEventsEnabled(rep.isEventsEnabled());
if (rep.getEventsExpiration() != null) realm.setEventsExpiration(rep.getEventsExpiration());
if (rep.getEventsListeners() != null) realm.setEventsListeners(new HashSet<>(rep.getEventsListeners()));
if (rep.getEnabledEventTypes() != null) realm.setEnabledEventTypes(new HashSet<>(rep.getEnabledEventTypes()));
+
+ if (rep.isAdminEventsEnabled() != null) realm.setAdminEventsEnabled(rep.isAdminEventsEnabled());
+ if (rep.isAdminEventsDetailsEnabled() != null) realm.setAdminEventsDetailsEnabled(rep.isAdminEventsDetailsEnabled());
+
if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
diff --git a/model/api/src/main/java/org/keycloak/provider/Spi.java b/model/api/src/main/java/org/keycloak/provider/Spi.java
index 03b9afc..be68251 100644
--- a/model/api/src/main/java/org/keycloak/provider/Spi.java
+++ b/model/api/src/main/java/org/keycloak/provider/Spi.java
@@ -5,6 +5,7 @@ package org.keycloak.provider;
*/
public interface Spi {
+ public boolean isPrivate();
public String getName();
public Class<? extends Provider> getProviderClass();
public Class<? extends ProviderFactory> getProviderFactoryClass();
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
index cdd658a..d835102 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
@@ -959,6 +959,26 @@ public class RealmAdapter implements RealmModel {
}
@Override
+ public boolean isAdminEventsEnabled() {
+ return realm.isAdminEventsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsEnabled(boolean enabled) {
+ realm.setAdminEventsEnabled(enabled);
+ }
+
+ @Override
+ public boolean isAdminEventsDetailsEnabled() {
+ return realm.isAdminEventsDetailsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsDetailsEnabled(boolean enabled) {
+ realm.setAdminEventsDetailsEnabled(enabled);
+ }
+
+ @Override
public ClientModel getMasterAdminClient() {
return this.masterAdminApp;
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java
index f6bbfd5..300b8f0 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java
@@ -11,6 +11,11 @@ import org.keycloak.provider.Spi;
public class CacheRealmProviderSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "realmCache";
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
index 6c0fae5..9e0affa 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
@@ -11,6 +11,11 @@ import org.keycloak.provider.Spi;
public class CacheUserProviderSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "userCache";
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index e490814..22f57a9 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -79,6 +79,9 @@ public class CachedRealm {
private long eventsExpiration;
private Set<String> eventsListeners = new HashSet<String>();
private Set<String> enabledEventTypes = new HashSet<String>();
+ protected boolean adminEventsEnabled;
+ protected Set<String> adminEnabledEventOperations = new HashSet<String>();
+ protected boolean adminEventsDetailsEnabled;
private List<String> defaultRoles = new LinkedList<String>();
private Map<String, String> realmRoles = new HashMap<String, String>();
private Map<String, String> clients = new HashMap<String, String>();
@@ -153,6 +156,10 @@ public class CachedRealm {
eventsExpiration = model.getEventsExpiration();
eventsListeners.addAll(model.getEventsListeners());
enabledEventTypes.addAll(model.getEnabledEventTypes());
+
+ adminEventsEnabled = model.isAdminEventsEnabled();
+ adminEventsDetailsEnabled = model.isAdminEventsDetailsEnabled();
+
defaultRoles.addAll(model.getDefaultRoles());
masterAdminClient = model.getMasterAdminClient().getId();
@@ -350,6 +357,18 @@ public class CachedRealm {
return enabledEventTypes;
}
+ public boolean isAdminEventsEnabled() {
+ return adminEventsEnabled;
+ }
+
+ public Set<String> getAdminEnabledEventOperations() {
+ return adminEnabledEventOperations;
+ }
+
+ public boolean isAdminEventsDetailsEnabled() {
+ return adminEventsDetailsEnabled;
+ }
+
public List<UserFederationProviderModel> getUserFederationProviders() {
return userFederationProviders;
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index 68a65ac..33f2356 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -751,6 +751,30 @@ public class RealmAdapter implements RealmModel {
}
@Override
+ public boolean isAdminEventsEnabled() {
+ if (updated != null) return updated.isAdminEventsEnabled();
+ return cached.isAdminEventsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsEnabled(boolean enabled) {
+ getDelegateForUpdate();
+ updated.setAdminEventsEnabled(enabled);
+ }
+
+ @Override
+ public boolean isAdminEventsDetailsEnabled() {
+ if (updated != null) return updated.isAdminEventsDetailsEnabled();
+ return cached.isAdminEventsDetailsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsDetailsEnabled(boolean enabled) {
+ getDelegateForUpdate();
+ updated.setAdminEventsDetailsEnabled(enabled);
+ }
+
+ @Override
public ClientModel getMasterAdminClient() {
return cacheSession.getRealm(Config.getAdminRealm()).getClientById(cached.getMasterAdminClient());
}
@@ -923,4 +947,5 @@ public class RealmAdapter implements RealmModel {
}
return null;
}
+
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index efdb4a8..cdf314c 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -134,7 +134,13 @@ public class RealmEntity {
@Column(name="VALUE")
@CollectionTable(name="REALM_ENABLED_EVENT_TYPES", joinColumns={ @JoinColumn(name="REALM_ID") })
protected Set<String> enabledEventTypes = new HashSet<String>();
-
+
+ @Column(name="ADMIN_EVENTS_ENABLED")
+ protected boolean adminEventsEnabled;
+
+ @Column(name="ADMIN_EVENTS_DETAILS_ENABLED")
+ protected boolean adminEventsDetailsEnabled;
+
@OneToOne
@JoinColumn(name="MASTER_ADMIN_CLIENT")
protected ClientEntity masterAdminClient;
@@ -437,6 +443,22 @@ public class RealmEntity {
this.enabledEventTypes = enabledEventTypes;
}
+ public boolean isAdminEventsEnabled() {
+ return adminEventsEnabled;
+ }
+
+ public void setAdminEventsEnabled(boolean adminEventsEnabled) {
+ this.adminEventsEnabled = adminEventsEnabled;
+ }
+
+ public boolean isAdminEventsDetailsEnabled() {
+ return adminEventsDetailsEnabled;
+ }
+
+ public void setAdminEventsDetailsEnabled(boolean adminEventsDetailsEnabled) {
+ this.adminEventsDetailsEnabled = adminEventsDetailsEnabled;
+ }
+
public ClientEntity getMasterAdminClient() {
return masterAdminClient;
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 8618ddb..66b94d0 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -22,6 +22,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
+
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
@@ -1065,8 +1066,30 @@ public class RealmAdapter implements RealmModel {
realm.setEnabledEventTypes(enabledEventTypes);
em.flush();
}
+
+ @Override
+ public boolean isAdminEventsEnabled() {
+ return realm.isAdminEventsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsEnabled(boolean enabled) {
+ realm.setAdminEventsEnabled(enabled);
+ em.flush();
+ }
@Override
+ public boolean isAdminEventsDetailsEnabled() {
+ return realm.isAdminEventsDetailsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsDetailsEnabled(boolean enabled) {
+ realm.setAdminEventsDetailsEnabled(enabled);
+ em.flush();
+ }
+
+ @Override
public ClientModel getMasterAdminClient() {
return new ClientAdapter(this, em, session, realm.getMasterAdminClient());
}
@@ -1327,4 +1350,5 @@ public class RealmAdapter implements RealmModel {
mapping.setConfig(config);
return mapping;
}
+
}
\ No newline at end of file
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index fb08290..d797de9 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -2,6 +2,7 @@ package org.keycloak.models.mongo.keycloak.adapters;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
+
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.enums.SslRequired;
import org.keycloak.models.ClientModel;
@@ -985,8 +986,31 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
}
updateRealm();
}
+
+ @Override
+ public boolean isAdminEventsEnabled() {
+ return realm.isAdminEventsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsEnabled(boolean enabled) {
+ realm.setAdminEventsEnabled(enabled);
+ updateRealm();
+
+ }
@Override
+ public boolean isAdminEventsDetailsEnabled() {
+ return realm.isAdminEventsDetailsEnabled();
+ }
+
+ @Override
+ public void setAdminEventsDetailsEnabled(boolean enabled) {
+ realm.setAdminEventsDetailsEnabled(enabled);
+ updateRealm();
+ }
+
+ @Override
public ClientModel getMasterAdminClient() {
MongoClientEntity appData = getMongoStore().loadEntity(MongoClientEntity.class, realm.getMasterAdminClient(), invocationContext);
return appData != null ? new ClientAdapter(session, this, appData, invocationContext) : null;
pom.xml 208(+200 -8)
diff --git a/pom.xml b/pom.xml
index 07246fb..796918a 100755
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
<parent>
<groupId>org.jboss</groupId>
<artifactId>jboss-parent</artifactId>
- <version>14</version>
+ <version>16</version>
</parent>
<name>Keycloak</name>
@@ -20,18 +20,26 @@
<properties>
<apacheds.version>2.0.0-M17</apacheds.version>
<apacheds.codec.version>1.0.0-M23</apacheds.codec.version>
+ <org.apache.james.apache-mime4j.version>0.6</org.apache.james.apache-mime4j.version>
<base64.version>2.3.8</base64.version>
<bouncycastle.crypto.version>1.50</bouncycastle.crypto.version>
<jackson.version>1.9.9</jackson.version>
<apache.httpcomponents.version>4.3.6</apache.httpcomponents.version>
<apache.httpcomponents.httpcore.version>4.3.3</apache.httpcomponents.httpcore.version>
<resteasy.version>3.0.10.Final</resteasy.version>
+ <resteasy.version.latest>3.0.10.Final</resteasy.version.latest>
+ <joda-time.version>2.7</joda-time.version>
+ <keycloak.apache.httpcomponents.version>4.2.1</keycloak.apache.httpcomponents.version>
+ <!-- <undertow.version>1.1.0.Final</undertow.version> -->
<undertow.version>1.1.1.Final</undertow.version>
<picketlink.version>2.7.0.Final</picketlink.version>
<mongo.driver.version>2.11.3</mongo.driver.version>
<jboss.logging.version>3.1.4.GA</jboss.logging.version>
<syslog4j.version>0.9.30</syslog4j.version>
<jboss-logging-tools.version>1.2.0.Beta1</jboss-logging-tools.version>
+ <jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>1.0.4.Final</jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>
+ <io.netty.version>4.0.26.Final</io.netty.version>
+ <xnio.netty.netty-xnio-transport.version>0.1.1.Final</xnio.netty.netty-xnio-transport.version>
<hibernate.javax.persistence.version>1.0.1.Final</hibernate.javax.persistence.version>
<hibernate.entitymanager.version>4.0.1.Final</hibernate.entitymanager.version>
<h2.version>1.3.168</h2.version>
@@ -40,17 +48,22 @@
<dom4j.version>1.6.1</dom4j.version>
<xml-apis.version>1.4.01</xml-apis.version>
<mysql.version>5.1.25</mysql.version>
- <slf4j.version>1.5.10</slf4j.version>
+ <slf4j.version>1.7.7.jbossorg-1</slf4j.version>
+ <wildfly.version>9.0.0.CR1</wildfly.version>
+ <wildfly.core.version>1.0.0.CR1</wildfly.core.version>
+ <wildfly.build-tools.version>1.0.0.Alpha8</wildfly.build-tools.version>
<jboss.version>7.1.1.Final</jboss.version>
- <wildfly.version>8.2.0.Final</wildfly.version>
- <wildfly.core.version>1.0.0.Alpha12</wildfly.core.version>
<servlet.api.30.version>1.0.2.Final</servlet.api.30.version>
<google.zxing.version>2.2</google.zxing.version>
<google.client.version>1.14.1-beta</google.client.version>
+ <github.relaxng.version>2011.1</github.relaxng.version>
<winzipaes.version>1.0.1</winzipaes.version>
<freemarker.version>2.3.20</freemarker.version>
<twitter4j.version>3.0.5</twitter4j.version>
<selenium.version>2.35.0</selenium.version>
+ <sun.istack.version>2.21</sun.istack.version>
+ <sun.jaxb.version>2.2.11</sun.jaxb.version>
+ <sun.xsom.version>20140925</sun.xsom.version>
<javax.mail.version>1.4.5</javax.mail.version>
<infinispan.version>6.0.2.Final</infinispan.version>
<liquibase.version>3.3.2</liquibase.version>
@@ -58,7 +71,7 @@
<osgi.version>4.2.0</osgi.version>
<pax.web.version>3.1.2</pax.web.version>
<jmeter.version>2.10</jmeter.version>
- <junit.version>4.11</junit.version>
+ <junit.version>4.12</junit.version>
<hamcrest.version>1.3</hamcrest.version>
<log4j.version>1.2.17</log4j.version>
<greenmail.version>1.3.1b</greenmail.version>
@@ -141,13 +154,68 @@
<dependencyManagement>
<dependencies>
<dependency>
+ <groupId>com.github.relaxng</groupId>
+ <artifactId>relaxngDatatype</artifactId>
+ <version>${github.relaxng.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.istack</groupId>
+ <artifactId>istack-commons-runtime</artifactId>
+ <version>${sun.istack.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.istack</groupId>
+ <artifactId>istack-commons-tools</artifactId>
+ <version>${sun.istack.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xml.bind.external</groupId>
+ <artifactId>rngom</artifactId>
+ <version>${sun.jaxb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xsom</groupId>
+ <artifactId>xsom</artifactId>
+ <version>${sun.xsom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-core</artifactId>
+ <version>${sun.jaxb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-runtime</artifactId>
+ <version>${sun.jaxb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-xjc</artifactId>
+ <version>${sun.jaxb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>codemodel</artifactId>
+ <version>${sun.jaxb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>txw2</artifactId>
+ <version>${sun.jaxb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ <version>${joda-time.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.crypto.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
- <artifactId>bcpkix-jdk15on</artifactId>
+ <artifactId>bcpkix-jdk15on</artifactId>
<version>${bouncycastle.crypto.version}</version>
</dependency>
<dependency>
@@ -198,6 +266,31 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.jboss.spec.javax.xml.bind</groupId>
+ <artifactId>jboss-jaxb-api_2.2_spec</artifactId>
+ <version>${jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
+ <version>${io.netty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.xnio.netty</groupId>
+ <artifactId>netty-xnio-transport</artifactId>
+ <version>${xnio.netty.netty-xnio-transport.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adapter-subsystem</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-undertow-adapter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${undertow.version}</version>
@@ -418,7 +511,12 @@
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
-
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
+ <!-- Needed for picketlink perf test -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
@@ -441,6 +539,28 @@
<version>${apache.httpcomponents.httpcore.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ <version>${keycloak.apache.httpcomponents.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.james</groupId>
+ <artifactId>apache-mime4j</artifactId>
+ <version>${org.apache.james.apache-mime4j.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-controller</artifactId>
<version>${wildfly.core.version}</version>
@@ -456,6 +576,18 @@
<version>${wildfly.version}</version>
</dependency>
<dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-feature-pack</artifactId>
+ <version>${wildfly.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-web-feature-pack</artifactId>
+ <version>${wildfly.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-subsystem-test</artifactId>
<version>${wildfly.core.version}</version>
@@ -463,6 +595,18 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-undertow</artifactId>
+ <version>${wildfly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly.core</groupId>
+ <artifactId>wildfly-subsystem-test-framework</artifactId>
+ <version>${wildfly.core.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-core-feature-pack</artifactId>
<type>pom</type>
@@ -481,7 +625,7 @@
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
- <artifactId>wildfly-undertow</artifactId>
+ <artifactId>wildfly-web-common</artifactId>
<version>${wildfly.version}</version>
</dependency>
<dependency>
@@ -1098,6 +1242,54 @@
<artifactId>liquibase-maven-plugin</artifactId>
<version>${liquibase.version}</version>
</plugin>
+ <!--plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>buildnumber-maven-plugin</artifactId>
+ <version>1.3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.7</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ <nonFilteredFileExtensions>
+ <nonFilteredFileExtension>jar</nonFilteredFileExtension>
+ <nonFilteredFileExtension>war</nonFilteredFileExtension>
+ <nonFilteredFileExtension>ear</nonFilteredFileExtension>
+ <nonFilteredFileExtension>pdf</nonFilteredFileExtension>
+ <nonFilteredFileExtension>swf</nonFilteredFileExtension>
+ <nonFilteredFileExtension>zip</nonFilteredFileExtension>
+ <nonFilteredFileExtension>bz2</nonFilteredFileExtension>
+ <nonFilteredFileExtension>gz</nonFilteredFileExtension>
+ <nonFilteredFileExtension>acp</nonFilteredFileExtension>
+ <nonFilteredFileExtension>bin</nonFilteredFileExtension>
+ <nonFilteredFileExtension>odt</nonFilteredFileExtension>
+ <nonFilteredFileExtension>doc</nonFilteredFileExtension>
+ <nonFilteredFileExtension>xls</nonFilteredFileExtension>
+ </nonFilteredFileExtensions>
+ </configuration>
+ </plugin-->
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-feature-pack-build-maven-plugin</artifactId>
+ <version>${wildfly.build-tools.version}</version>
+ </plugin>
+ <plugin>
+ <groupId>org.wildfly.build</groupId>
+ <artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
+ <version>${wildfly.build-tools.version}</version>
+ </plugin>
</plugins>
</pluginManagement>
</build>
diff --git a/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java b/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java
index 6fe071e..e59a45a 100755
--- a/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java
+++ b/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class ClientImportSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "client-import";
}
diff --git a/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java b/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
index ef73b34..6ac5496 100755
--- a/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
+++ b/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class LoginProtocolSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "login-protocol";
}
diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
index 421319e..1b98e07 100755
--- a/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
+++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class ProtocolMapperSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
public String getName() {
return "protocol-mapper";
}
diff --git a/services/src/main/java/org/keycloak/services/ErrorResponse.java b/services/src/main/java/org/keycloak/services/ErrorResponse.java
index e7539a1..5937e12 100755
--- a/services/src/main/java/org/keycloak/services/ErrorResponse.java
+++ b/services/src/main/java/org/keycloak/services/ErrorResponse.java
@@ -11,9 +11,7 @@ import javax.ws.rs.core.Response;
public class ErrorResponse {
public static Response exists(String message) {
- ErrorRepresentation error = new ErrorRepresentation();
- error.setErrorMessage(message);
- return Response.status(Response.Status.CONFLICT).entity(error).type(MediaType.APPLICATION_JSON).build();
+ return ErrorResponse.error(message, Response.Status.CONFLICT);
}
public static Response error(String message, Response.Status status) {
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 88d9eb5..f2caef8 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -168,6 +168,9 @@ public class RealmManager {
if(rep.getEnabledEventTypes() != null) {
realm.setEnabledEventTypes(new HashSet<String>(rep.getEnabledEventTypes()));
}
+
+ realm.setAdminEventsEnabled(rep.isAdminEventsEnabled());
+ realm.setAdminEventsDetailsEnabled(rep.isAdminEventsDetailsEnabled());
}
// Should be RealmManager moved to model/api instead of referencing methods this way?
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
new file mode 100644
index 0000000..a0c15f3
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
@@ -0,0 +1,314 @@
+package org.keycloak.services.resources.admin;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.logging.Logger;
+import org.keycloak.ClientConnection;
+import org.keycloak.broker.provider.IdentityProviderFactory;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.EventStoreProvider;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AuthDetails;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.IdentityProviderMapperModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.Time;
+
+public class AdminEventBuilder {
+
+ private static final Logger log = Logger.getLogger(AdminEventBuilder.class);
+
+ private EventStoreProvider store;
+ private List<EventListenerProvider> listeners;
+ private RealmModel realm;
+ private AdminEvent adminEvent;
+
+ public AdminEventBuilder(RealmModel realm, AdminAuth auth, KeycloakSession session, ClientConnection clientConnection) {
+ this.realm = realm;
+ adminEvent = new AdminEvent();
+
+ if (realm.isAdminEventsEnabled()) {
+ EventStoreProvider store = session.getProvider(EventStoreProvider.class);
+ if (store != null) {
+ this.store = store;
+ } else {
+ log.error("Admin Events enabled, but no event store provider configured");
+ }
+ }
+
+ if (realm.getEventsListeners() != null && !realm.getEventsListeners().isEmpty()) {
+ this.listeners = new LinkedList<>();
+ for (String id : realm.getEventsListeners()) {
+ EventListenerProvider listener = session.getProvider(EventListenerProvider.class, id);
+ if (listener != null) {
+ listeners.add(listener);
+ } else {
+ log.error("Event listener '" + id + "' registered, but provider not found");
+ }
+ }
+ }
+
+ authRealm(auth.getRealm());
+ authClient(auth.getClient());
+ authUser(auth.getUser());
+ authIpAddress(clientConnection.getRemoteAddr());
+ }
+
+ public AdminEventBuilder realm(RealmModel realm) {
+ adminEvent.setRealmId(realm.getId());
+ return this;
+ }
+
+ public AdminEventBuilder realm(String realmId) {
+ adminEvent.setRealmId(realmId);
+ return this;
+ }
+
+ public AdminEventBuilder operation(OperationType e) {
+ adminEvent.setOperationType(e);
+ return this;
+ }
+
+ public AdminEventBuilder authRealm(RealmModel realm) {
+ AuthDetails authDetails = adminEvent.getAuthDetails();
+ if(authDetails == null) {
+ authDetails = new AuthDetails();
+ authDetails.setRealmId(realm.getId());
+ } else {
+ authDetails.setRealmId(realm.getId());
+ }
+ adminEvent.setAuthDetails(authDetails);
+ return this;
+ }
+
+ public AdminEventBuilder authRealm(String realmId) {
+ AuthDetails authDetails = adminEvent.getAuthDetails();
+ if(authDetails == null) {
+ authDetails = new AuthDetails();
+ authDetails.setRealmId(realmId);
+ } else {
+ authDetails.setRealmId(realmId);
+ }
+ adminEvent.setAuthDetails(authDetails);
+ return this;
+ }
+
+ public AdminEventBuilder authClient(ClientModel client) {
+ AuthDetails authDetails = adminEvent.getAuthDetails();
+ if(authDetails == null) {
+ authDetails = new AuthDetails();
+ authDetails.setClientId(client.getId());
+ } else {
+ authDetails.setClientId(client.getId());
+ }
+ adminEvent.setAuthDetails(authDetails);
+ return this;
+ }
+
+ public AdminEventBuilder authClient(String clientId) {
+ AuthDetails authDetails = adminEvent.getAuthDetails();
+ if(authDetails == null) {
+ authDetails = new AuthDetails();
+ authDetails.setClientId(clientId);
+ } else {
+ authDetails.setClientId(clientId);
+ }
+ adminEvent.setAuthDetails(authDetails);
+ return this;
+ }
+
+ public AdminEventBuilder authUser(UserModel user) {
+ AuthDetails authDetails = adminEvent.getAuthDetails();
+ if(authDetails == null) {
+ authDetails = new AuthDetails();
+ authDetails.setUserId(user.getId());
+ } else {
+ authDetails.setUserId(user.getId());
+ }
+ adminEvent.setAuthDetails(authDetails);
+ return this;
+ }
+
+ public AdminEventBuilder authUser(String userId) {
+ AuthDetails authDetails = adminEvent.getAuthDetails();
+ if(authDetails == null) {
+ authDetails = new AuthDetails();
+ authDetails.setUserId(userId);
+ } else {
+ authDetails.setUserId(userId);
+ }
+ adminEvent.setAuthDetails(authDetails);
+ return this;
+ }
+
+ public AdminEventBuilder authIpAddress(String ipAddress) {
+ AuthDetails authDetails = adminEvent.getAuthDetails();
+ if(authDetails == null) {
+ authDetails = new AuthDetails();
+ authDetails.setIpAddress(ipAddress);
+ } else {
+ authDetails.setIpAddress(ipAddress);
+ }
+ adminEvent.setAuthDetails(authDetails);
+ return this;
+ }
+
+ public AdminEventBuilder resourcePath(String resourcePath) {
+ adminEvent.setResourcePath(resourcePath);
+ return this;
+ }
+
+ public AdminEventBuilder resourcePath(String resourcePath, boolean segment) {
+ if(segment) {
+ int index = resourcePath.lastIndexOf('/');
+ int subIndex = resourcePath.lastIndexOf('/', index - 1);
+ adminEvent.setResourcePath(resourcePath.substring(subIndex));
+ } else {
+ adminEvent.setResourcePath(resourcePath.substring(resourcePath.lastIndexOf('/')));
+ }
+ return this;
+ }
+
+ public AdminEventBuilder resourcePath(Object model) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getResourcePath(model));
+ adminEvent.setResourcePath(sb.toString());
+ return this;
+ }
+
+ public AdminEventBuilder resourcePath(Object model, String resourcePath) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getResourcePath(model));
+ sb.append(resourcePath.substring(resourcePath.lastIndexOf('/')));
+ adminEvent.setResourcePath(sb.toString());
+ return this;
+ }
+
+ public AdminEventBuilder resourcePath(Object model, String resourcePath, boolean segment) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getResourcePath(model));
+ int index = resourcePath.lastIndexOf('/');
+ int subIndex = resourcePath.lastIndexOf('/', index - 1);
+ sb.append(resourcePath.substring(subIndex));
+ adminEvent.setResourcePath(sb.toString());
+ return this;
+ }
+
+ public AdminEventBuilder resourcePath(Object model, Object subModel, String resourcePath) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getResourcePath(model));
+ int index = resourcePath.lastIndexOf('/');
+ int subIndex = resourcePath.lastIndexOf('/', index - 1);
+ sb.append(resourcePath.substring(subIndex, index+1));
+ sb.append(getResourcePath(subModel));
+ adminEvent.setResourcePath(sb.toString());
+ return this;
+ }
+
+
+ public void error(String error) {
+ adminEvent.setOperationType(OperationType.valueOf(adminEvent.getOperationType().name() + "_ERROR"));
+ adminEvent.setError(error);
+ send();
+ }
+
+ public AdminEventBuilder representation(Object value) {
+ if (value == null || value.equals("")) {
+ return this;
+ }
+ try {
+ adminEvent.setRepresentation(JsonSerialization.writeValueAsString(value));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return this;
+ }
+
+ public AdminEvent getEvent() {
+ return adminEvent;
+ }
+
+ public void success() {
+ send();
+ }
+
+ private void send() {
+ boolean includeRepresentation = false;
+ if(realm.isAdminEventsDetailsEnabled()) {
+ includeRepresentation = true;
+ }
+ adminEvent.setTime(Time.toMillis(Time.currentTime()));
+
+ if (store != null) {
+ try {
+ store.onEvent(adminEvent, includeRepresentation);
+ } catch (Throwable t) {
+ log.error("Failed to save event", t);
+ }
+ }
+
+ if (listeners != null) {
+ for (EventListenerProvider l : listeners) {
+ try {
+ l.onEvent(adminEvent, includeRepresentation);
+ } catch (Throwable t) {
+ log.error("Failed to send type to " + l, t);
+ }
+ }
+ }
+ }
+
+ private String getResourcePath(Object model) {
+
+ StringBuilder sb = new StringBuilder();
+
+ if (model instanceof RealmModel) {
+ RealmModel realm = (RealmModel) model;
+ sb.append("realms/" + realm.getId());
+ } else if (model instanceof ClientModel) {
+ ClientModel client = (ClientModel) model;
+ sb.append("clients/" + client.getId());
+ } else if (model instanceof UserModel) {
+ UserModel user = (UserModel) model;
+ sb.append("users/" + user.getId());
+
+ } else if (model instanceof IdentityProviderModel) {
+ IdentityProviderModel provider = (IdentityProviderModel) model;
+ sb.append("identity-Providers/" + provider.getProviderId());
+ } else if (model instanceof IdentityProviderRepresentation) {
+ IdentityProviderRepresentation provider = (IdentityProviderRepresentation) model;
+ sb.append("identity-Providers/" + provider.getProviderId());
+ } else if (model instanceof IdentityProviderMapperModel) {
+ IdentityProviderMapperModel provider = (IdentityProviderMapperModel) model;
+ sb.append("identity-Provider-Mappers/" + provider.getId());
+ } else if (model instanceof IdentityProviderFactory) {
+ IdentityProviderFactory provider = (IdentityProviderFactory) model;
+ sb.append("identity-Provider-Factory/" + provider.getId());
+
+ } else if (model instanceof ProtocolMapperModel) {
+ ProtocolMapperModel mapper = (ProtocolMapperModel) model;
+ sb.append("protocol-Mappers/" + mapper.getId());
+
+ } else if (model instanceof UserFederationProviderModel) {
+ UserFederationProviderModel provider = (UserFederationProviderModel) model;
+ sb.append("user-Federation-Providers/" + provider.getId());
+
+ } else if (model instanceof RoleModel) {
+ RoleModel role = (RoleModel) model;
+ sb.append("roles/" + role.getId());
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
index 34e8272..55861d0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
@@ -29,6 +29,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
+
import java.io.IOException;
/**
@@ -185,7 +186,7 @@ public class AdminRoot {
}
Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response);
-
+
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
return adminResource;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
index 16a0fbe..3b91e3e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
@@ -6,6 +6,7 @@ import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.NotAcceptableException;
import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -21,6 +22,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -47,11 +49,12 @@ public class ClientAttributeCertificateResource {
private RealmAuth auth;
protected ClientModel client;
protected KeycloakSession session;
+ protected AdminEventBuilder adminEvent;
protected String attributePrefix;
protected String privateAttribute;
protected String certificateAttribute;
- public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix) {
+ public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix, AdminEventBuilder adminEvent) {
this.realm = realm;
this.auth = auth;
this.client = client;
@@ -59,6 +62,7 @@ public class ClientAttributeCertificateResource {
this.attributePrefix = attributePrefix;
this.privateAttribute = attributePrefix + "." + PRIVATE_KEY;
this.certificateAttribute = attributePrefix + "." + X509CERTIFICATE;
+ this.adminEvent = adminEvent;
}
public static class ClientKeyPairInfo {
@@ -129,11 +133,14 @@ public class ClientAttributeCertificateResource {
client.setAttribute(privateAttribute, privateKeyPem);
client.setAttribute(certificateAttribute, certPem);
-
KeycloakModelUtils.generateClientKeyPairCertificate(client);
ClientKeyPairInfo info = new ClientKeyPairInfo();
info.setCertificate(client.getAttribute(certificateAttribute));
info.setPrivateKey(client.getAttribute(privateAttribute));
+
+ adminEvent.operation(OperationType.ACTION)
+ .resourcePath(client, session.getContext().getUri().getPath()).representation(info).success();
+
return info;
}
@@ -190,7 +197,8 @@ public class ClientAttributeCertificateResource {
client.setAttribute(certificateAttribute, certPem);
info.setCertificate(certPem);
}
-
+
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath()).representation(info).success();
return info;
}
@@ -316,6 +324,10 @@ public class ClientAttributeCertificateResource {
stream.flush();
stream.close();
byte[] rtn = stream.toByteArray();
+
+ adminEvent.operation(OperationType.ACTION)
+ .resourcePath(client, session.getContext().getUri().getPath()).success();
+
return rtn;
} catch (Exception e) {
throw new RuntimeException(e);
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 f769101..d9ab8dc 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
@@ -5,6 +5,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
@@ -40,6 +41,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -57,6 +59,7 @@ public class ClientResource {
protected static final Logger logger = Logger.getLogger(ClientResource.class);
protected RealmModel realm;
private RealmAuth auth;
+ private AdminEventBuilder adminEvent;
protected ClientModel client;
protected KeycloakSession session;
@@ -70,18 +73,19 @@ public class ClientResource {
return keycloak;
}
- public ClientResource(RealmModel realm, RealmAuth auth, ClientModel clientModel, KeycloakSession session) {
+ public ClientResource(RealmModel realm, RealmAuth auth, ClientModel clientModel, KeycloakSession session, AdminEventBuilder adminEvent) {
this.realm = realm;
this.auth = auth;
this.client = clientModel;
this.session = session;
+ this.adminEvent = adminEvent;
auth.init(RealmAuth.Resource.CLIENT);
}
@Path("protocol-mappers")
public ProtocolMappersResource getProtocolMappers() {
- ProtocolMappersResource mappers = new ProtocolMappersResource(client, auth);
+ ProtocolMappersResource mappers = new ProtocolMappersResource(client, auth, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(mappers);
return mappers;
}
@@ -98,6 +102,7 @@ public class ClientResource {
try {
RepresentationToModel.updateClient(rep, client);
+ adminEvent.operation(OperationType.UPDATE).resourcePath(client).representation(rep).success();
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
@@ -115,7 +120,6 @@ public class ClientResource {
@Produces(MediaType.APPLICATION_JSON)
public ClientRepresentation getClient() {
auth.requireView();
-
return ModelToRepresentation.toRepresentation(client);
}
@@ -126,7 +130,7 @@ public class ClientResource {
*/
@Path("certificates/{attr}")
public ClientAttributeCertificateResource getCertficateResource(@PathParam("attr") String attributePrefix) {
- return new ClientAttributeCertificateResource(realm, auth, client, session, attributePrefix);
+ return new ClientAttributeCertificateResource(realm, auth, client, session, attributePrefix, adminEvent);
}
@@ -145,6 +149,8 @@ public class ClientResource {
ClientManager clientManager = new ClientManager(new RealmManager(session));
Object rep = clientManager.toInstallationRepresentation(realm, client, getKeycloakApplication().getBaseUri(uriInfo));
+
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath(), true).success();
// TODO Temporary solution to pretty-print
return JsonSerialization.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rep);
@@ -164,6 +170,9 @@ public class ClientResource {
auth.requireView();
ClientManager clientManager = new ClientManager(new RealmManager(session));
+
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath(), true).success();
+
return clientManager.toJBossSubsystemConfig(realm, client, getKeycloakApplication().getBaseUri(uriInfo));
}
@@ -176,6 +185,7 @@ public class ClientResource {
public void deleteClient() {
auth.requireManage();
new ClientManager(new RealmManager(session)).removeClient(realm, client);
+ adminEvent.operation(OperationType.DELETE).resourcePath(client).success();
}
@@ -194,6 +204,7 @@ public class ClientResource {
logger.debug("regenerateSecret");
UserCredentialModel cred = KeycloakModelUtils.generateSecret(client);
CredentialRepresentation rep = ModelToRepresentation.toRepresentation(cred);
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath()).representation(rep).success();
return rep;
}
@@ -222,12 +233,12 @@ public class ClientResource {
*/
@Path("scope-mappings")
public ScopeMappedResource getScopeMappedResource() {
- return new ScopeMappedResource(realm, auth, client, session);
+ return new ScopeMappedResource(realm, auth, client, session, adminEvent);
}
@Path("roles")
public RoleContainerResource getRoleContainerResource() {
- return new RoleContainerResource(realm, auth, client);
+ return new RoleContainerResource(realm, auth, client, adminEvent);
}
/**
@@ -243,7 +254,6 @@ public class ClientResource {
public Set<String> getAllowedOrigins()
{
auth.requireView();
-
return client.getWebOrigins();
}
@@ -261,6 +271,7 @@ public class ClientResource {
auth.requireManage();
client.setWebOrigins(allowedOrigins);
+ adminEvent.operation(OperationType.UPDATE).resourcePath(client, uriInfo.getPath()).representation(client).success();
}
/**
@@ -279,6 +290,7 @@ public class ClientResource {
for (String origin : allowedOrigins) {
client.removeWebOrigin(origin);
}
+ adminEvent.operation(OperationType.DELETE).resourcePath(client, uriInfo.getPath()).success();
}
/**
@@ -289,9 +301,11 @@ public class ClientResource {
@POST
public GlobalRequestResult pushRevocation() {
auth.requireManage();
- return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath()).success();
+ return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
+
}
-
+
/**
* Number of user sessions associated with this client
*
@@ -341,7 +355,9 @@ public class ClientResource {
@POST
public GlobalRequestResult logoutAll() {
auth.requireManage();
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath()).success();
return new ResourceAdminManager(session).logoutClient(uriInfo.getRequestUri(), realm, client);
+
}
/**
@@ -356,7 +372,9 @@ public class ClientResource {
if (user == null) {
throw new NotFoundException("User not found");
}
- new ResourceAdminManager(session).logoutUserFromClient(uriInfo.getRequestUri(), realm, client, user);
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath(), true).success();
+ new ResourceAdminManager(session).logoutUserFromClient(uriInfo.getRequestUri(), realm, client, user);
+
}
/**
@@ -376,6 +394,7 @@ public class ClientResource {
}
if (logger.isDebugEnabled()) logger.debug("Register node: " + node);
client.registerNode(node, Time.currentTime());
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath()).success();
}
/**
@@ -394,8 +413,8 @@ public class ClientResource {
if (time == null) {
throw new NotFoundException("Client does not have a node " + node);
}
-
client.unregisterNode(node);
+ adminEvent.operation(OperationType.DELETE).resourcePath(client, uriInfo.getPath(), true).success();
}
/**
@@ -408,9 +427,10 @@ public class ClientResource {
@NoCache
public GlobalRequestResult testNodesAvailable() {
auth.requireManage();
- logger.debug("Test availability of cluster nodes");
-
+ logger.debug("Test availability of cluster nodes");
+ adminEvent.operation(OperationType.ACTION).resourcePath(client, uriInfo.getPath()).success();
return new ResourceAdminManager(session).testNodesAvailability(uriInfo.getRequestUri(), realm, client);
+
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsByIdResource.java
index 46f2f87..3b273e0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsByIdResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsByIdResource.java
@@ -8,8 +8,8 @@ import org.keycloak.models.RealmModel;
* @version $Revision: 1 $
*/
public class ClientsByIdResource extends ClientsResource {
- public ClientsByIdResource(RealmModel realm, RealmAuth auth) {
- super(realm, auth);
+ public ClientsByIdResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+ super(realm, auth, adminEvent);
}
@Override
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
index f6df036..51c509f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
@@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
@@ -23,6 +24,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+
import java.util.ArrayList;
import java.util.List;
@@ -36,13 +38,15 @@ public class ClientsResource {
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
protected RealmModel realm;
private RealmAuth auth;
-
+ private AdminEventBuilder adminEvent;
+
@Context
protected KeycloakSession session;
- public ClientsResource(RealmModel realm, RealmAuth auth) {
+ public ClientsResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
this.realm = realm;
this.auth = auth;
+ this.adminEvent = adminEvent;
auth.init(RealmAuth.Resource.CLIENT);
}
@@ -72,7 +76,6 @@ public class ClientsResource {
rep.add(client);
}
}
-
return rep;
}
@@ -90,6 +93,9 @@ public class ClientsResource {
try {
ClientModel clientModel = RepresentationToModel.createClient(session, realm, rep, true);
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(clientModel).representation(rep).success();
+
return Response.created(uriInfo.getAbsolutePathBuilder().path(getClientPath(clientModel)).build()).build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
@@ -112,7 +118,7 @@ public class ClientsResource {
if (clientModel == null) {
throw new NotFoundException("Could not find client: " + name);
}
- ClientResource clientResource = new ClientResource(realm, auth, clientModel, session);
+ ClientResource clientResource = new ClientResource(realm, auth, clientModel, session, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(clientResource);
return clientResource;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index 539c410..9b058a5 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -6,6 +6,7 @@ import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.broker.provider.IdentityProviderMapper;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderMapperModel;
@@ -13,7 +14,6 @@ import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation;
@@ -25,7 +25,6 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.ErrorResponse;
-import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.social.SocialIdentityProvider;
import javax.ws.rs.Consumes;
@@ -41,6 +40,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
@@ -58,14 +58,16 @@ public class IdentityProviderResource {
private final RealmModel realm;
private final KeycloakSession session;
private final IdentityProviderModel identityProviderModel;
-
+ private final AdminEventBuilder adminEvent;
+
@Context private UriInfo uriInfo;
- public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel) {
+ public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel, AdminEventBuilder adminEvent) {
this.realm = realm;
this.session = session;
this.identityProviderModel = identityProviderModel;
this.auth = auth;
+ this.adminEvent = adminEvent;
}
@GET
@@ -74,7 +76,6 @@ public class IdentityProviderResource {
public IdentityProviderRepresentation getIdentityProvider() {
this.auth.requireView();
IdentityProviderRepresentation rep = ModelToRepresentation.toRepresentation(this.identityProviderModel);
-
return rep;
}
@@ -84,7 +85,9 @@ public class IdentityProviderResource {
this.auth.requireManage();
this.realm.removeIdentityProviderByAlias(this.identityProviderModel.getAlias());
-
+
+ adminEvent.operation(OperationType.DELETE).resourcePath(identityProviderModel).success();
+
return Response.noContent().build();
}
@@ -108,7 +111,9 @@ public class IdentityProviderResource {
updateUsersAfterProviderAliasChange(this.session.users().getUsers(this.realm), oldProviderId, newProviderId);
}
-
+
+ adminEvent.operation(OperationType.UPDATE).resourcePath(providerRep).representation(providerRep).success();
+
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Identity Provider " + providerRep.getAlias() + " already exists");
@@ -164,6 +169,7 @@ public class IdentityProviderResource {
try {
this.auth.requireView();
IdentityProviderFactory factory = getIdentityProviderFactory();
+ adminEvent.operation(OperationType.ACTION).resourcePath(identityProviderModel, uriInfo.getPath()).success();
return factory.create(identityProviderModel).export(uriInfo, realm, format);
} catch (Exception e) {
return ErrorResponse.error("Could not export public broker configuration for identity provider [" + identityProviderModel.getProviderId() + "].", Response.Status.NOT_FOUND);
@@ -225,6 +231,10 @@ public class IdentityProviderResource {
auth.requireManage();
IdentityProviderMapperModel model = RepresentationToModel.toModel(mapper);
model = realm.addIdentityProviderMapper(model);
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(model, uriInfo.getPath())
+ .representation(mapper).success();
+
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
}
@@ -250,6 +260,8 @@ public class IdentityProviderResource {
if (model == null) throw new NotFoundException("Model not found");
model = RepresentationToModel.toModel(rep);
realm.updateIdentityProviderMapper(model);
+ adminEvent.operation(OperationType.UPDATE).resourcePath(model).representation(rep).success();
+
}
@DELETE
@@ -260,6 +272,8 @@ public class IdentityProviderResource {
IdentityProviderMapperModel model = realm.getIdentityProviderMapperById(id);
if (model == null) throw new NotFoundException("Model not found");
realm.removeIdentityProviderMapper(model);
+ adminEvent.operation(OperationType.DELETE).resourcePath(model).success();
+
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
index ecedae7..3617631 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
@@ -1,183 +1,191 @@
-package org.keycloak.services.resources.admin;
-
-import org.jboss.resteasy.annotations.cache.NoCache;
-import org.jboss.resteasy.plugins.providers.multipart.InputPart;
-import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
-import org.jboss.resteasy.spi.NotFoundException;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.keycloak.broker.provider.IdentityProvider;
-import org.keycloak.broker.provider.IdentityProviderFactory;
-import org.keycloak.connections.httpclient.HttpClientProvider;
-import org.keycloak.models.IdentityProviderModel;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.models.utils.RepresentationToModel;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.representations.idm.IdentityProviderRepresentation;
-import org.keycloak.services.ErrorResponse;
-import org.keycloak.social.SocialIdentityProvider;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-/**
- * @author Pedro Igor
- */
-public class IdentityProvidersResource {
-
- private final RealmModel realm;
- private final KeycloakSession session;
- private RealmAuth auth;
-
- public IdentityProvidersResource(RealmModel realm, KeycloakSession session, RealmAuth auth) {
- this.realm = realm;
- this.session = session;
- this.auth = auth;
- this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
- }
-
- @Path("/providers/{provider_id}")
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public Response getIdentityProviders(@PathParam("provider_id") String providerId) {
- this.auth.requireView();
- IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
-
- if (providerFactory != null) {
- return Response.ok(providerFactory).build();
- }
-
- return Response.status(BAD_REQUEST).build();
- }
-
- @POST
- @Path("import-config")
- @Consumes(MediaType.MULTIPART_FORM_DATA)
- @Produces(MediaType.APPLICATION_JSON)
- public Map<String, String> importFrom(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
- this.auth.requireManage();
- Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
- String providerId = formDataMap.get("providerId").get(0).getBodyAsString();
- InputPart file = formDataMap.get("file").get(0);
- InputStream inputStream = file.getBody(InputStream.class, null);
- IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
- Map<String, String> config = providerFactory.parseConfig(inputStream);
- return config;
- }
-
- @POST
- @Path("import-config")
- @Consumes(MediaType.APPLICATION_JSON)
- @Produces(MediaType.APPLICATION_JSON)
- public Map<String, String> importFrom(@Context UriInfo uriInfo, Map<String, Object> data) throws IOException {
- this.auth.requireManage();
-
- String providerId = data.get("providerId").toString();
- String from = data.get("fromUrl").toString();
- InputStream inputStream = session.getProvider(HttpClientProvider.class).get(from);
- try {
- IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
- Map<String, String> config;
- config = providerFactory.parseConfig(inputStream);
- return config;
- } finally {
- try {
- inputStream.close();
- } catch (IOException e) {
- }
- }
- }
-
- @GET
- @Path("instances")
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public List<IdentityProviderRepresentation> getIdentityProviders() {
- this.auth.requireView();
-
- List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
-
- for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
- representations.add(ModelToRepresentation.toRepresentation(identityProviderModel));
- }
-
- return representations;
- }
-
- @POST
- @Path("instances")
- @Consumes(MediaType.APPLICATION_JSON)
- public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) {
- this.auth.requireManage();
-
- try {
- IdentityProviderModel identityProvider = RepresentationToModel.toModel(representation);
- this.realm.addIdentityProvider(identityProvider);
-
- return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build();
- } catch (ModelDuplicateException e) {
- return ErrorResponse.exists("Identity Provider " + representation.getAlias() + " already exists");
- }
- }
-
- @Path("instances/{alias}")
- public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) {
- this.auth.requireView();
- IdentityProviderModel identityProviderModel = null;
-
- for (IdentityProviderModel storedIdentityProvider : this.realm.getIdentityProviders()) {
- if (storedIdentityProvider.getAlias().equals(alias)
- || storedIdentityProvider.getInternalId().equals(alias)) {
- identityProviderModel = storedIdentityProvider;
- }
- }
-
- if (identityProviderModel == null) {
- throw new NotFoundException("Could not find identity provider: " + alias);
- }
-
- IdentityProviderResource identityProviderResource = new IdentityProviderResource(this.auth, realm, session, identityProviderModel);
- ResteasyProviderFactory.getInstance().injectProperties(identityProviderResource);
-
- return identityProviderResource;
- }
-
- private IdentityProviderFactory getProviderFactorytById(String providerId) {
- List<ProviderFactory> allProviders = getProviderFactories();
-
- for (ProviderFactory providerFactory : allProviders) {
- if (providerFactory.getId().equals(providerId)) {
- return (IdentityProviderFactory) providerFactory;
- }
- }
-
- return null;
- }
-
- private List<ProviderFactory> getProviderFactories() {
- List<ProviderFactory> allProviders = new ArrayList<ProviderFactory>();
-
- allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class));
- allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class));
-
- return allProviders;
- }
+package org.keycloak.services.resources.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.plugins.providers.multipart.InputPart;
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
+import org.jboss.resteasy.spi.NotFoundException;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.broker.provider.IdentityProvider;
+import org.keycloak.broker.provider.IdentityProviderFactory;
+import org.keycloak.connections.httpclient.HttpClientProvider;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.services.ErrorResponse;
+import org.keycloak.social.SocialIdentityProvider;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+/**
+ * @author Pedro Igor
+ */
+public class IdentityProvidersResource {
+
+ private final RealmModel realm;
+ private final KeycloakSession session;
+ private RealmAuth auth;
+ private AdminEventBuilder adminEvent;
+
+ public IdentityProvidersResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) {
+ this.realm = realm;
+ this.session = session;
+ this.auth = auth;
+ this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
+ this.adminEvent = adminEvent;
+ }
+
+ @Path("/providers/{provider_id}")
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getIdentityProviders(@PathParam("provider_id") String providerId) {
+ this.auth.requireView();
+ IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
+ if (providerFactory != null) {
+ return Response.ok(providerFactory).build();
+ }
+ return Response.status(BAD_REQUEST).build();
+ }
+
+ @POST
+ @Path("import-config")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, String> importFrom(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
+ this.auth.requireManage();
+ Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
+ String providerId = formDataMap.get("providerId").get(0).getBodyAsString();
+ InputPart file = formDataMap.get("file").get(0);
+ InputStream inputStream = file.getBody(InputStream.class, null);
+ IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
+ Map<String, String> config = providerFactory.parseConfig(inputStream);
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(providerFactory, uriInfo.getPath()).representation(config).success();
+
+ return config;
+ }
+
+ @POST
+ @Path("import-config")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, String> importFrom(@Context UriInfo uriInfo, Map<String, Object> data) throws IOException {
+ this.auth.requireManage();
+
+ String providerId = data.get("providerId").toString();
+ String from = data.get("fromUrl").toString();
+ InputStream inputStream = session.getProvider(HttpClientProvider.class).get(from);
+ try {
+ IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
+ Map<String, String> config;
+ config = providerFactory.parseConfig(inputStream);
+ adminEvent.operation(OperationType.CREATE).resourcePath(providerFactory, uriInfo.getPath()).representation(config).success();
+ return config;
+ } finally {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ @GET
+ @Path("instances")
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public List<IdentityProviderRepresentation> getIdentityProviders() {
+ this.auth.requireView();
+
+ List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
+
+ for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
+ representations.add(ModelToRepresentation.toRepresentation(identityProviderModel));
+ }
+ return representations;
+ }
+
+ @POST
+ @Path("instances")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) {
+ this.auth.requireManage();
+
+ try {
+ IdentityProviderModel identityProvider = RepresentationToModel.toModel(representation);
+ this.realm.addIdentityProvider(identityProvider);
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(identityProvider)
+ .representation(representation).success();
+
+ return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build();
+ } catch (ModelDuplicateException e) {
+ return ErrorResponse.exists("Identity Provider " + representation.getAlias() + " already exists");
+ }
+ }
+
+ @Path("instances/{alias}")
+ public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) {
+ this.auth.requireView();
+ IdentityProviderModel identityProviderModel = null;
+
+ for (IdentityProviderModel storedIdentityProvider : this.realm.getIdentityProviders()) {
+ if (storedIdentityProvider.getAlias().equals(alias)
+ || storedIdentityProvider.getInternalId().equals(alias)) {
+ identityProviderModel = storedIdentityProvider;
+ }
+ }
+
+ if (identityProviderModel == null) {
+ throw new NotFoundException("Could not find identity provider: " + alias);
+ }
+
+ IdentityProviderResource identityProviderResource = new IdentityProviderResource(this.auth, realm, session, identityProviderModel, adminEvent);
+ ResteasyProviderFactory.getInstance().injectProperties(identityProviderResource);
+
+ return identityProviderResource;
+ }
+
+ private IdentityProviderFactory getProviderFactorytById(String providerId) {
+ List<ProviderFactory> allProviders = getProviderFactories();
+
+ for (ProviderFactory providerFactory : allProviders) {
+ if (providerFactory.getId().equals(providerId)) {
+ return (IdentityProviderFactory) providerFactory;
+ }
+ }
+
+ return null;
+ }
+
+ private List<ProviderFactory> getProviderFactories() {
+ List<ProviderFactory> allProviders = new ArrayList<ProviderFactory>();
+
+ allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class));
+ allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class));
+
+ return allProviders;
+ }
}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
index 36428b8..1f59b68 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
@@ -3,9 +3,11 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
@@ -22,6 +24,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+
import java.util.LinkedList;
import java.util.List;
@@ -33,10 +36,12 @@ import java.util.List;
*/
public class ProtocolMappersResource {
protected static final Logger logger = Logger.getLogger(ProtocolMappersResource.class);
-
+
protected ClientModel client;
protected RealmAuth auth;
+
+ protected AdminEventBuilder adminEvent;
@Context
protected UriInfo uriInfo;
@@ -44,9 +49,10 @@ public class ProtocolMappersResource {
@Context
protected KeycloakSession session;
- public ProtocolMappersResource(ClientModel client, RealmAuth auth) {
+ public ProtocolMappersResource(ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
this.auth = auth;
this.client = client;
+ this.adminEvent = adminEvent;
auth.init(RealmAuth.Resource.USER);
}
@@ -83,6 +89,7 @@ public class ProtocolMappersResource {
auth.requireManage();
ProtocolMapperModel model = RepresentationToModel.toModel(rep);
model = client.addProtocolMapper(model);
+ adminEvent.operation(OperationType.CREATE).resourcePath(model).representation(rep).success();
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
}
/**
@@ -95,10 +102,12 @@ public class ProtocolMappersResource {
@Consumes(MediaType.APPLICATION_JSON)
public void createMapper(List<ProtocolMapperRepresentation> reps) {
auth.requireManage();
+ ProtocolMapperModel model = null;
for (ProtocolMapperRepresentation rep : reps) {
- ProtocolMapperModel model = RepresentationToModel.toModel(rep);
+ model = RepresentationToModel.toModel(rep);
model = client.addProtocolMapper(model);
}
+ adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo.getPath(), false).representation(reps).success();
}
@GET
@@ -135,6 +144,7 @@ public class ProtocolMappersResource {
if (model == null) throw new NotFoundException("Model not found");
model = RepresentationToModel.toModel(rep);
client.updateProtocolMapper(model);
+ adminEvent.operation(OperationType.UPDATE).resourcePath(model).representation(rep).success();
}
@DELETE
@@ -145,6 +155,8 @@ public class ProtocolMappersResource {
ProtocolMapperModel model = client.getProtocolMapperById(id);
if (model == null) throw new NotFoundException("Model not found");
client.removeProtocolMapper(model);
+ adminEvent.operation(OperationType.DELETE).resourcePath(model).success();
+
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index b0d171b..9f2a12f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -1,451 +1,554 @@
-package org.keycloak.services.resources.admin;
-
-import org.jboss.logging.Logger;
-import org.jboss.resteasy.annotations.cache.NoCache;
-import org.jboss.resteasy.spi.NotFoundException;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.keycloak.ClientConnection;
-import org.keycloak.events.Event;
-import org.keycloak.events.EventQuery;
-import org.keycloak.events.EventStoreProvider;
-import org.keycloak.events.EventType;
-import org.keycloak.exportimport.ClientImporter;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserFederationProviderModel;
-import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.cache.CacheRealmProvider;
-import org.keycloak.models.cache.CacheUserProvider;
-import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.models.utils.RepresentationToModel;
-import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.representations.adapters.action.GlobalRequestResult;
-import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
-import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.LDAPConnectionTestManager;
-import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.managers.ResourceAdminManager;
-import org.keycloak.services.managers.UsersSyncManager;
-import org.keycloak.services.ErrorResponse;
-import org.keycloak.timer.TimerProvider;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.PatternSyntaxException;
-
-/**
- * Base resource class for the admin REST api of one realm
- *
- * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
- * @version $Revision: 1 $
- */
-public class RealmAdminResource {
- protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
- protected RealmAuth auth;
- protected RealmModel realm;
- private TokenManager tokenManager;
-
- @Context
- protected KeycloakSession session;
-
- @Context
- protected UriInfo uriInfo;
-
- @Context
- protected ClientConnection connection;
-
- @Context
- protected HttpHeaders headers;
-
- public RealmAdminResource(RealmAuth auth, RealmModel realm, TokenManager tokenManager) {
- this.auth = auth;
- this.realm = realm;
- this.tokenManager = tokenManager;
-
- auth.init(RealmAuth.Resource.REALM);
- }
-
- /**
- * Base path for importing clients under this realm.
- *
- * @return
- */
- @Path("client-importers/{formatId}")
- public Object getClientImporter(@PathParam("formatId") String formatId) {
- ClientImporter importer = session.getProvider(ClientImporter.class, formatId);
- return importer.createJaxrsService(realm, auth);
- }
-
- /**
- * Base path for managing clients under this realm.
- *
- * @return
- */
- @Path("clients")
- public ClientsResource getClients() {
- ClientsResource clientsResource = new ClientsResource(realm, auth);
- ResteasyProviderFactory.getInstance().injectProperties(clientsResource);
- return clientsResource;
- }
-
- /**
- * Base path for managing clients under this realm.
- *
- * @return
- */
- @Path("clients-by-id")
- public ClientsByIdResource getClientsById() {
- ClientsByIdResource clientsResource = new ClientsByIdResource(realm, auth);
- ResteasyProviderFactory.getInstance().injectProperties(clientsResource);
- return clientsResource;
- }
-
- /**
- * base path for managing realm-level roles of this realm
- *
- * @return
- */
- @Path("roles")
- public RoleContainerResource getRoleContainerResource() {
- return new RoleContainerResource(realm, auth, realm);
- }
-
- /**
- * Get the top-level representation of the realm. It will not include nested information like User and Client representations.
- *
- * @return
- */
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public RealmRepresentation getRealm() {
- if (auth.hasView()) {
- RealmRepresentation rep = ModelToRepresentation.toRepresentation(realm, false);
- if (session.realms() instanceof CacheRealmProvider) {
- CacheRealmProvider cacheRealmProvider = (CacheRealmProvider)session.realms();
- rep.setRealmCacheEnabled(cacheRealmProvider.isEnabled());
- }
- if (session.userStorage() instanceof CacheUserProvider) {
- CacheUserProvider cache = (CacheUserProvider)session.userStorage();
- rep.setUserCacheEnabled(cache.isEnabled());
- }
- return rep;
- } else {
- auth.requireAny();
-
- RealmRepresentation rep = new RealmRepresentation();
- rep.setRealm(realm.getName());
- return rep;
- }
- }
-
- /**
- * Update the top-level information of this realm. Any user, roles or client information in the representation
- * will be ignored. This will only update top-level attributes of the realm.
- *
- * @param rep
- * @return
- */
- @PUT
- @Consumes(MediaType.APPLICATION_JSON)
- public Response updateRealm(final RealmRepresentation rep) {
- auth.requireManage();
-
- logger.debug("updating realm: " + realm.getName());
- try {
- RepresentationToModel.updateRealm(rep, realm);
- if (rep.isRealmCacheEnabled() != null && session.realms() instanceof CacheRealmProvider) {
- CacheRealmProvider cacheRealmProvider = (CacheRealmProvider)session.realms();
- cacheRealmProvider.setEnabled(rep.isRealmCacheEnabled());
- }
- if (rep.isUserCacheEnabled() != null && session.userStorage() instanceof CacheUserProvider) {
- CacheUserProvider cache = (CacheUserProvider)session.userStorage();
- cache.setEnabled(rep.isUserCacheEnabled());
- }
-
- // Refresh periodic sync tasks for configured federationProviders
- List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
- UsersSyncManager usersSyncManager = new UsersSyncManager();
- for (final UserFederationProviderModel fedProvider : federationProviders) {
- usersSyncManager.refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), fedProvider, realm.getId());
- }
-
- return Response.noContent().build();
- } catch (PatternSyntaxException e) {
- return ErrorResponse.exists("Specified regex pattern(s) is invalid.");
- } catch (ModelDuplicateException e) {
- return ErrorResponse.exists("Realm " + rep.getRealm() + " already exists.");
- } catch (Exception e) {
- return ErrorResponse.exists("Failed to update " + rep.getRealm() + " Realm.");
- }
- }
-
- /**
- * Delete this realm.
- *
- */
- @DELETE
- public void deleteRealm() {
- auth.requireManage();
-
- if (!new RealmManager(session).removeRealm(realm)) {
- throw new NotFoundException("Realm doesn't exist");
- }
- }
-
- /**
- * Base path for managing users in this realm.
- *
- * @return
- */
- @Path("users")
- public UsersResource users() {
- UsersResource users = new UsersResource(realm, auth, tokenManager);
- ResteasyProviderFactory.getInstance().injectProperties(users);
- //resourceContext.initResource(users);
- return users;
- }
-
- @Path("user-federation")
- public UserFederationResource userFederation() {
- UserFederationResource fed = new UserFederationResource(realm, auth);
- ResteasyProviderFactory.getInstance().injectProperties(fed);
- //resourceContext.initResource(fed);
- return fed;
- }
-
- /**
- * Path for managing all realm-level or client-level roles defined in this realm by it's id.
- *
- * @return
- */
- @Path("roles-by-id")
- public RoleByIdResource rolesById() {
- RoleByIdResource resource = new RoleByIdResource(realm, auth);
- ResteasyProviderFactory.getInstance().injectProperties(resource);
- //resourceContext.initResource(resource);
- return resource;
- }
-
- /**
- * Push the realm's revocation policy to any client that has an admin url associated with it.
- *
- */
- @Path("push-revocation")
- @POST
- public GlobalRequestResult pushRevocation() {
- auth.requireManage();
- return new ResourceAdminManager(session).pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm);
- }
-
- /**
- * Removes all user sessions. Any client that has an admin url will also be told to invalidate any sessions
- * they have.
- *
- */
- @Path("logout-all")
- @POST
- public GlobalRequestResult logoutAll() {
- session.sessions().removeUserSessions(realm);
- return new ResourceAdminManager(session).logoutAll(uriInfo.getRequestUri(), realm);
- }
-
- /**
- * Remove a specific user session. Any client that has an admin url will also be told to invalidate this
- * particular session.
- *
- * @param sessionId
- */
- @Path("sessions/{session}")
- @DELETE
- public void deleteSession(@PathParam("session") String sessionId) {
- UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
- if (userSession == null) throw new NotFoundException("Sesssion not found");
- AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
- }
-
- /**
- * Returns a JSON map. The key is the client name, the value is the number of sessions that currently are active
- * with that client. Only client's that actually have a session associated with them will be in this map.
- *
- * @return
- */
- @Path("client-session-stats")
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- @Deprecated
- public Map<String, Integer> getClientSessionStats() {
- auth.requireView();
- Map<String, Integer> stats = new HashMap<String, Integer>();
- for (ClientModel client : realm.getClients()) {
- int size = session.sessions().getActiveUserSessions(client.getRealm(), client);
- if (size == 0) continue;
- stats.put(client.getClientId(), size);
- }
- return stats;
- }
-
- /**
- * Returns a JSON map. The key is the client id, the value is the number of sessions that currently are active
- * with that client. Only client's that actually have a session associated with them will be in this map.
- *
- * @return
- */
- @Path("client-by-id-session-stats")
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public List<Map<String, String>> getClientByIdSessionStats() {
- auth.requireView();
- List<Map<String, String>> data = new LinkedList<Map<String, String>>();
- for (ClientModel client : realm.getClients()) {
- int size = session.sessions().getActiveUserSessions(client.getRealm(), client);
- if (size == 0) continue;
- Map<String, String> map = new HashMap<String, String>();
- map.put("id", client.getId());
- map.put("clientId", client.getClientId());
- map.put("active", size + "");
- data.add(map);
- }
- return data;
- }
-
- /**
- * View the events provider and how it is configured.
- *
- * @return
- */
- @GET
- @NoCache
- @Path("events/config")
- @Produces(MediaType.APPLICATION_JSON)
- public RealmEventsConfigRepresentation getRealmEventsConfig() {
- auth.init(RealmAuth.Resource.EVENTS).requireView();
-
- return ModelToRepresentation.toEventsConfigReprensetation(realm);
- }
-
- /**
- * Change the events provider and/or it's configuration
- *
- * @param rep
- */
- @PUT
- @Path("events/config")
- @Consumes(MediaType.APPLICATION_JSON)
- public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
- auth.init(RealmAuth.Resource.EVENTS).requireManage();
-
- logger.debug("updating realm events config: " + realm.getName());
- new RealmManager(session).updateRealmEventsConfig(rep, realm);
- }
-
- /**
- * Query events. Returns all events, or will query based on URL query parameters listed here
- *
- * @param client app or oauth client name
- * @param user user id
- * @param ipAddress
- * @param firstResult
- * @param maxResults
- * @return
- */
- @Path("events")
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public List<Event> getEvents(@QueryParam("client") String client,
- @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
- @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
- @QueryParam("max") Integer maxResults) {
- auth.init(RealmAuth.Resource.EVENTS).requireView();
-
- EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
-
- EventQuery query = eventStore.createQuery().realm(realm.getId());
- if (client != null) {
- query.client(client);
- }
-
- List<String> types = uriInfo.getQueryParameters().get("type");
- if (types != null) {
- EventType[] t = new EventType[types.size()];
- for (int i = 0; i < t.length; i++) {
- t[i] = EventType.valueOf(types.get(i));
- }
- query.type(t);
- }
-
- if (user != null) {
- query.user(user);
- }
-
- if(dateFrom != null) {
- query.fromDate(dateFrom);
- }
- if(dateTo != null) {
- query.toDate(dateTo);
- }
-
- if (ipAddress != null) {
- query.ipAddress(ipAddress);
- }
- if (firstResult != null) {
- query.firstResult(firstResult);
- }
- if (maxResults != null) {
- query.maxResults(maxResults);
- }
-
- return query.getResultList();
- }
-
- /**
- * Delete all events.
- *
- */
- @Path("events")
- @DELETE
- public void clearEvents() {
- auth.init(RealmAuth.Resource.EVENTS).requireManage();
-
- EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
- eventStore.clear(realm.getId());
- }
-
- @Path("testLDAPConnection")
- @GET
- @NoCache
- public Response testLDAPConnection(@QueryParam("action") String action, @QueryParam("connectionUrl") String connectionUrl,
- @QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential) {
- auth.init(RealmAuth.Resource.REALM).requireManage();
-
- boolean result = new LDAPConnectionTestManager().testLDAP(action, connectionUrl, bindDn, bindCredential);
- return result ? Response.noContent().build() : ErrorResponse.error("LDAP test error", Response.Status.BAD_REQUEST);
- }
-
- @Path("identity-provider")
- public IdentityProvidersResource getIdentityProviderResource() {
- return new IdentityProvidersResource(realm, session, this.auth);
- }
-}
+package org.keycloak.services.resources.admin;
+
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.NotFoundException;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.ClientConnection;
+import org.keycloak.events.Event;
+import org.keycloak.events.EventQuery;
+import org.keycloak.events.EventStoreProvider;
+import org.keycloak.events.EventType;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.exportimport.ClientImporter;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.cache.CacheRealmProvider;
+import org.keycloak.models.cache.CacheUserProvider;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.representations.adapters.action.GlobalRequestResult;
+import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.LDAPConnectionTestManager;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.managers.ResourceAdminManager;
+import org.keycloak.services.managers.UsersSyncManager;
+import org.keycloak.services.ErrorResponse;
+import org.keycloak.timer.TimerProvider;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * Base resource class for the admin REST api of one realm
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RealmAdminResource {
+ protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
+ protected RealmAuth auth;
+ protected RealmModel realm;
+ private TokenManager tokenManager;
+ private AdminEventBuilder adminEvent;
+
+ @Context
+ protected KeycloakSession session;
+
+ @Context
+ protected UriInfo uriInfo;
+
+ @Context
+ protected ClientConnection connection;
+
+ @Context
+ protected HttpHeaders headers;
+
+ public RealmAdminResource(RealmAuth auth, RealmModel realm, TokenManager tokenManager, AdminEventBuilder adminEvent) {
+ this.auth = auth;
+ this.realm = realm;
+ this.tokenManager = tokenManager;
+ this.adminEvent = adminEvent.realm(realm);
+
+ auth.init(RealmAuth.Resource.REALM);
+ }
+
+ /**
+ * Base path for importing clients under this realm.
+ *
+ * @return
+ */
+ @Path("client-importers/{formatId}")
+ public Object getClientImporter(@PathParam("formatId") String formatId) {
+ ClientImporter importer = session.getProvider(ClientImporter.class, formatId);
+ return importer.createJaxrsService(realm, auth);
+ }
+
+ /**
+ * Base path for managing clients under this realm.
+ *
+ * @return
+ */
+ @Path("clients")
+ public ClientsResource getClients() {
+ ClientsResource clientsResource = new ClientsResource(realm, auth, adminEvent);
+ ResteasyProviderFactory.getInstance().injectProperties(clientsResource);
+ return clientsResource;
+ }
+
+ /**
+ * Base path for managing clients under this realm.
+ *
+ * @return
+ */
+ @Path("clients-by-id")
+ public ClientsByIdResource getClientsById() {
+ ClientsByIdResource clientsResource = new ClientsByIdResource(realm, auth, adminEvent);
+ ResteasyProviderFactory.getInstance().injectProperties(clientsResource);
+ return clientsResource;
+ }
+
+ /**
+ * base path for managing realm-level roles of this realm
+ *
+ * @return
+ */
+ @Path("roles")
+ public RoleContainerResource getRoleContainerResource() {
+ return new RoleContainerResource(realm, auth, realm, adminEvent);
+ }
+
+ /**
+ * Get the top-level representation of the realm. It will not include nested information like User and Client representations.
+ *
+ * @return
+ */
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public RealmRepresentation getRealm() {
+ if (auth.hasView()) {
+ RealmRepresentation rep = ModelToRepresentation.toRepresentation(realm, false);
+ if (session.realms() instanceof CacheRealmProvider) {
+ CacheRealmProvider cacheRealmProvider = (CacheRealmProvider)session.realms();
+ rep.setRealmCacheEnabled(cacheRealmProvider.isEnabled());
+ }
+ if (session.userStorage() instanceof CacheUserProvider) {
+ CacheUserProvider cache = (CacheUserProvider)session.userStorage();
+ rep.setUserCacheEnabled(cache.isEnabled());
+ }
+ return rep;
+ } else {
+ auth.requireAny();
+
+ RealmRepresentation rep = new RealmRepresentation();
+ rep.setRealm(realm.getName());
+ return rep;
+ }
+ }
+
+ /**
+ * Update the top-level information of this realm. Any user, roles or client information in the representation
+ * will be ignored. This will only update top-level attributes of the realm.
+ *
+ * @param rep
+ * @return
+ */
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response updateRealm(final RealmRepresentation rep) {
+ auth.requireManage();
+
+ logger.debug("updating realm: " + realm.getName());
+ try {
+ RepresentationToModel.updateRealm(rep, realm);
+ if (rep.isRealmCacheEnabled() != null && session.realms() instanceof CacheRealmProvider) {
+ CacheRealmProvider cacheRealmProvider = (CacheRealmProvider)session.realms();
+ cacheRealmProvider.setEnabled(rep.isRealmCacheEnabled());
+ }
+ if (rep.isUserCacheEnabled() != null && session.userStorage() instanceof CacheUserProvider) {
+ CacheUserProvider cache = (CacheUserProvider)session.userStorage();
+ cache.setEnabled(rep.isUserCacheEnabled());
+ }
+
+ // Refresh periodic sync tasks for configured federationProviders
+ List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
+ UsersSyncManager usersSyncManager = new UsersSyncManager();
+ for (final UserFederationProviderModel fedProvider : federationProviders) {
+ usersSyncManager.refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), fedProvider, realm.getId());
+ }
+
+ adminEvent.operation(OperationType.UPDATE).representation(rep).success();
+ return Response.noContent().build();
+ } catch (PatternSyntaxException e) {
+ return ErrorResponse.error("Specified regex pattern(s) is invalid.", Response.Status.BAD_REQUEST);
+ } catch (ModelDuplicateException e) {
+ return ErrorResponse.exists("Realm " + rep.getRealm() + " already exists.");
+ } catch (Exception e) {
+ return ErrorResponse.error("Failed to update " + rep.getRealm() + " Realm.", Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * Delete this realm.
+ *
+ */
+ @DELETE
+ public void deleteRealm() {
+ auth.requireManage();
+
+ if (!new RealmManager(session).removeRealm(realm)) {
+ throw new NotFoundException("Realm doesn't exist");
+ } else {
+ clearAdminEvents();
+ }
+ }
+
+ /**
+ * Base path for managing users in this realm.
+ *
+ * @return
+ */
+ @Path("users")
+ public UsersResource users() {
+ UsersResource users = new UsersResource(realm, auth, tokenManager, adminEvent);
+ ResteasyProviderFactory.getInstance().injectProperties(users);
+ //resourceContext.initResource(users);
+ return users;
+ }
+
+ @Path("user-federation")
+ public UserFederationResource userFederation() {
+ UserFederationResource fed = new UserFederationResource(realm, auth, adminEvent);
+ ResteasyProviderFactory.getInstance().injectProperties(fed);
+ //resourceContext.initResource(fed);
+ return fed;
+ }
+
+ /**
+ * Path for managing all realm-level or client-level roles defined in this realm by it's id.
+ *
+ * @return
+ */
+ @Path("roles-by-id")
+ public RoleByIdResource rolesById() {
+ RoleByIdResource resource = new RoleByIdResource(realm, auth, adminEvent);
+ ResteasyProviderFactory.getInstance().injectProperties(resource);
+ //resourceContext.initResource(resource);
+ return resource;
+ }
+
+ /**
+ * Push the realm's revocation policy to any client that has an admin url associated with it.
+ *
+ */
+ @Path("push-revocation")
+ @POST
+ public GlobalRequestResult pushRevocation() {
+ auth.requireManage();
+ adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo.getPath(), false).success();
+ return new ResourceAdminManager(session).pushRealmRevocationPolicy(uriInfo.getRequestUri(), realm);
+ }
+
+ /**
+ * Removes all user sessions. Any client that has an admin url will also be told to invalidate any sessions
+ * they have.
+ *
+ */
+ @Path("logout-all")
+ @POST
+ public GlobalRequestResult logoutAll() {
+ session.sessions().removeUserSessions(realm);
+ adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo.getPath(), false).success();
+ return new ResourceAdminManager(session).logoutAll(uriInfo.getRequestUri(), realm);
+ }
+
+ /**
+ * Remove a specific user session. Any client that has an admin url will also be told to invalidate this
+ * particular session.
+ *
+ * @param sessionId
+ */
+ @Path("sessions/{session}")
+ @DELETE
+ public void deleteSession(@PathParam("session") String sessionId) {
+ UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
+ if (userSession == null) throw new NotFoundException("Sesssion not found");
+ AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
+ adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo.getPath(), true).success();
+
+ }
+
+ /**
+ * Returns a JSON map. The key is the client name, the value is the number of sessions that currently are active
+ * with that client. Only client's that actually have a session associated with them will be in this map.
+ *
+ * @return
+ */
+ @Path("client-session-stats")
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ @Deprecated
+ public Map<String, Integer> getClientSessionStats() {
+ auth.requireView();
+ Map<String, Integer> stats = new HashMap<String, Integer>();
+ for (ClientModel client : realm.getClients()) {
+ int size = session.sessions().getActiveUserSessions(client.getRealm(), client);
+ if (size == 0) continue;
+ stats.put(client.getClientId(), size);
+ }
+ return stats;
+ }
+
+ /**
+ * Returns a JSON map. The key is the client id, the value is the number of sessions that currently are active
+ * with that client. Only client's that actually have a session associated with them will be in this map.
+ *
+ * @return
+ */
+ @Path("client-by-id-session-stats")
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public List<Map<String, String>> getClientByIdSessionStats() {
+ auth.requireView();
+ List<Map<String, String>> data = new LinkedList<Map<String, String>>();
+ for (ClientModel client : realm.getClients()) {
+ int size = session.sessions().getActiveUserSessions(client.getRealm(), client);
+ if (size == 0) continue;
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("id", client.getId());
+ map.put("clientId", client.getClientId());
+ map.put("active", size + "");
+ data.add(map);
+ }
+ return data;
+ }
+
+ /**
+ * View the events provider and how it is configured.
+ *
+ * @return
+ */
+ @GET
+ @NoCache
+ @Path("events/config")
+ @Produces(MediaType.APPLICATION_JSON)
+ public RealmEventsConfigRepresentation getRealmEventsConfig() {
+ auth.init(RealmAuth.Resource.EVENTS).requireView();
+
+ return ModelToRepresentation.toEventsConfigReprensetation(realm);
+ }
+
+ /**
+ * Change the events provider and/or it's configuration
+ *
+ * @param rep
+ */
+ @PUT
+ @Path("events/config")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
+ auth.init(RealmAuth.Resource.EVENTS).requireManage();
+
+ logger.debug("updating realm events config: " + realm.getName());
+ new RealmManager(session).updateRealmEventsConfig(rep, realm);
+ }
+
+ /**
+ * Query events. Returns all events, or will query based on URL query parameters listed here
+ *
+ * @param client app or oauth client name
+ * @param user user id
+ * @param ipAddress
+ * @param dateTo
+ * @param dateFrom
+ * @param firstResult
+ * @param maxResults
+ * @return
+ */
+ @Path("events")
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public List<Event> getEvents(@QueryParam("client") String client,
+ @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
+ @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
+ @QueryParam("max") Integer maxResults) {
+ auth.init(RealmAuth.Resource.EVENTS).requireView();
+
+ EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+
+ EventQuery query = eventStore.createQuery().realm(realm.getId());
+ if (client != null) {
+ query.client(client);
+ }
+
+ List<String> types = uriInfo.getQueryParameters().get("type");
+ if (types != null) {
+ EventType[] t = new EventType[types.size()];
+ for (int i = 0; i < t.length; i++) {
+ t[i] = EventType.valueOf(types.get(i));
+ }
+ query.type(t);
+ }
+
+ if (user != null) {
+ query.user(user);
+ }
+
+ if(dateFrom != null) {
+ query.fromDate(dateFrom);
+ }
+ if(dateTo != null) {
+ query.toDate(dateTo);
+ }
+
+ if (ipAddress != null) {
+ query.ipAddress(ipAddress);
+ }
+ if (firstResult != null) {
+ query.firstResult(firstResult);
+ }
+ if (maxResults != null) {
+ query.maxResults(maxResults);
+ }
+
+ return query.getResultList();
+ }
+
+ /**
+ * Query admin events. Returns all admin events, or will query based on URL query parameters listed here
+ *
+ * @param client app or oauth client name
+ * @param operationTypes operation type
+ * @param authUser user id
+ * @param authIpAddress
+ * @param resourcePath
+ * @param dateTo
+ * @param dateFrom
+ * @param resourcePath
+ * @param firstResult
+ * @param maxResults
+ * @return
+ */
+ @Path("admin-events")
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public List<AdminEvent> getEvents(@QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient,
+ @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
+ @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom,
+ @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
+ @QueryParam("max") Integer maxResults) {
+ auth.init(RealmAuth.Resource.EVENTS).requireView();
+
+ EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+ AdminEventQuery query = eventStore.createAdminQuery().realm(realm.getId());;
+
+ if (authRealm != null) {
+ query.authRealm(authRealm);
+ }
+
+ if (authClient != null) {
+ query.authClient(authClient);
+ }
+
+ if (authUser != null) {
+ query.authUser(authUser);
+ }
+
+ if (authIpAddress != null) {
+ query.authIpAddress(authIpAddress);
+ }
+
+ if (resourcePath != null) {
+ query.resourcePath(resourcePath);
+ }
+
+ List<String> operationTypes = uriInfo.getQueryParameters().get("operationTypes");
+ if (operationTypes != null) {
+ OperationType[] t = new OperationType[operationTypes.size()];
+ for (int i = 0; i < t.length; i++) {
+ t[i] = OperationType.valueOf(operationTypes.get(i));
+ }
+ query.operation(t);
+ }
+
+ if(dateFrom != null) {
+ query.fromTime(dateFrom);
+ }
+ if(dateTo != null) {
+ query.toTime(dateTo);
+ }
+
+ if (firstResult != null) {
+ query.firstResult(firstResult);
+ }
+ if (maxResults != null) {
+ query.maxResults(maxResults);
+ }
+
+ return query.getResultList();
+ }
+
+ /**
+ * Delete all events.
+ *
+ */
+ @Path("events")
+ @DELETE
+ public void clearEvents() {
+ auth.init(RealmAuth.Resource.EVENTS).requireManage();
+
+ EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+ eventStore.clear(realm.getId());
+ }
+
+ /**
+ * Delete all admin events.
+ *
+ */
+ @Path("admin-events")
+ @DELETE
+ public void clearAdminEvents() {
+ auth.init(RealmAuth.Resource.EVENTS).requireManage();
+
+ EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+ eventStore.clearAdmin(realm.getId());
+ }
+
+ @Path("testLDAPConnection")
+ @GET
+ @NoCache
+ public Response testLDAPConnection(@QueryParam("action") String action, @QueryParam("connectionUrl") String connectionUrl,
+ @QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential) {
+ auth.init(RealmAuth.Resource.REALM).requireManage();
+
+ boolean result = new LDAPConnectionTestManager().testLDAP(action, connectionUrl, bindDn, bindCredential);
+ return result ? Response.noContent().build() : ErrorResponse.error("LDAP test error", Response.Status.BAD_REQUEST);
+ }
+
+ @Path("identity-provider")
+ public IdentityProvidersResource getIdentityProviderResource() {
+ return new IdentityProvidersResource(realm, session, this.auth, adminEvent);
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index c9fea3d..fbe401c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -6,6 +6,7 @@ import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.ClientConnection;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
@@ -33,6 +34,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
@@ -52,9 +54,12 @@ public class RealmsAdminResource {
@Context
protected KeycloakSession session;
-
+
@Context
protected KeycloakApplication keycloak;
+
+ @Context
+ protected ClientConnection clientConnection;
public RealmsAdminResource(AdminAuth auth, TokenManager tokenManager) {
this.auth = auth;
@@ -128,7 +133,7 @@ public class RealmsAdminResource {
URI location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build();
logger.debugv("imported realm success, sending back: {0}", location.toString());
-
+
return Response.created(location).build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Realm " + rep.getRealm() + " already exists");
@@ -158,10 +163,11 @@ public class RealmsAdminResource {
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
List<InputPart> inputParts = uploadForm.get("file");
-
+ RealmRepresentation rep = null;
+
for (InputPart inputPart : inputParts) {
// inputPart.getBody doesn't work as content-type is wrong, and inputPart.setMediaType is not supported on AS7 (RestEasy 2.3.2.Final)
- RealmRepresentation rep = JsonSerialization.readValue(inputPart.getBodyAsString(), RealmRepresentation.class);
+ rep = JsonSerialization.readValue(inputPart.getBodyAsString(), RealmRepresentation.class);
RealmModel realm;
try {
realm = realmManager.importRealm(rep);
@@ -170,13 +176,14 @@ public class RealmsAdminResource {
}
grantPermissionsToRealmCreator(realm);
-
+
+ URI location = null;
if (inputParts.size() == 1) {
- URI location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build();
+ location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build();
return Response.created(location).build();
}
}
-
+
return Response.noContent().build();
}
@@ -218,8 +225,10 @@ public class RealmsAdminResource {
} else {
realmAuth = new RealmAuth(auth, realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())));
}
-
- RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager);
+
+ AdminEventBuilder adminEvent = new AdminEventBuilder(realm, auth, session, clientConnection);
+
+ RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager, adminEvent);
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource);
return adminResource;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
index 67d8c12..4ca1667 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
@@ -3,6 +3,7 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -20,6 +21,8 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+
import java.util.List;
import java.util.Set;
@@ -33,15 +36,17 @@ public class RoleByIdResource extends RoleResource {
protected static final Logger logger = Logger.getLogger(RoleByIdResource.class);
private final RealmModel realm;
private final RealmAuth auth;
+ private AdminEventBuilder adminEvent;
@Context
protected KeycloakSession session;
- public RoleByIdResource(RealmModel realm, RealmAuth auth) {
+ public RoleByIdResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
super(realm);
this.realm = realm;
this.auth = auth;
+ this.adminEvent = adminEvent;
}
/**
@@ -57,7 +62,6 @@ public class RoleByIdResource extends RoleResource {
public RoleRepresentation getRole(final @PathParam("role-id") String id) {
RoleModel roleModel = getRoleModel(id);
auth.requireView();
-
return getRole(roleModel);
}
@@ -76,7 +80,6 @@ public class RoleByIdResource extends RoleResource {
r = RealmAuth.Resource.USER;
}
auth.init(r);
-
return roleModel;
}
@@ -92,6 +95,7 @@ public class RoleByIdResource extends RoleResource {
RoleModel role = getRoleModel(id);
auth.requireManage();
deleteRole(role);
+ adminEvent.operation(OperationType.DELETE).resourcePath(role).success();
}
/**
@@ -107,6 +111,7 @@ public class RoleByIdResource extends RoleResource {
RoleModel role = getRoleModel(id);
auth.requireManage();
updateRole(rep, role);
+ adminEvent.operation(OperationType.UPDATE).resourcePath(role).representation(rep).success();
}
/**
@@ -122,6 +127,10 @@ public class RoleByIdResource extends RoleResource {
RoleModel role = getRoleModel(id);
auth.requireManage();
addComposites(roles, role);
+
+ adminEvent.operation(OperationType.ACTION)
+ .resourcePath(role, session.getContext().getUri().getPath()).representation(roles).success();
+
}
/**
@@ -217,6 +226,9 @@ public class RoleByIdResource extends RoleResource {
RoleModel role = getRoleModel(id);
auth.requireManage();
deleteComposites(roles, role);
+
+ adminEvent.operation(OperationType.DELETE)
+ .resourcePath(role, session.getContext().getUri().getPath()).representation(roles).success();
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index fa0064f..de2e3b4 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -2,7 +2,9 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
@@ -23,6 +25,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -35,12 +38,14 @@ public class RoleContainerResource extends RoleResource {
private final RealmModel realm;
private final RealmAuth auth;
protected RoleContainerModel roleContainer;
+ private AdminEventBuilder adminEvent;
- public RoleContainerResource(RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer) {
+ public RoleContainerResource(RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer, AdminEventBuilder adminEvent) {
super(realm);
this.realm = realm;
this.auth = auth;
this.roleContainer = roleContainer;
+ this.adminEvent = adminEvent;
}
/**
@@ -51,7 +56,7 @@ public class RoleContainerResource extends RoleResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
- public List<RoleRepresentation> getRoles() {
+ public List<RoleRepresentation> getRoles(@Context final UriInfo uriInfo) {
auth.requireAny();
Set<RoleModel> roleModels = roleContainer.getRoles();
@@ -77,6 +82,9 @@ public class RoleContainerResource extends RoleResource {
try {
RoleModel role = roleContainer.addRole(rep.getName());
role.setDescription(rep.getDescription());
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(role).representation(rep).success();
+
return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Role with name " + rep.getName() + " already exists");
@@ -93,7 +101,7 @@ public class RoleContainerResource extends RoleResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
- public RoleRepresentation getRole(final @PathParam("role-name") String roleName) {
+ public RoleRepresentation getRole(@Context final UriInfo uriInfo, final @PathParam("role-name") String roleName) {
auth.requireView();
RoleModel roleModel = roleContainer.getRole(roleName);
@@ -112,15 +120,18 @@ public class RoleContainerResource extends RoleResource {
@Path("{role-name}")
@DELETE
@NoCache
- public void deleteRole(final @PathParam("role-name") String roleName) {
+ public void deleteRole(@Context final UriInfo uriInfo, final @PathParam("role-name") String roleName) {
auth.requireManage();
- RoleRepresentation rep = getRole(roleName);
+ RoleRepresentation rep = getRole(uriInfo, roleName);
RoleModel role = roleContainer.getRole(roleName);
if (role == null) {
throw new NotFoundException("Could not find role: " + roleName);
}
deleteRole(role);
+
+ adminEvent.operation(OperationType.DELETE).resourcePath(role).success();
+
}
/**
@@ -133,7 +144,7 @@ public class RoleContainerResource extends RoleResource {
@Path("{role-name}")
@PUT
@Consumes(MediaType.APPLICATION_JSON)
- public Response updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
+ public Response updateRole(@Context final UriInfo uriInfo, final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
auth.requireManage();
RoleModel role = roleContainer.getRole(roleName);
@@ -142,6 +153,9 @@ public class RoleContainerResource extends RoleResource {
}
try {
updateRole(rep, role);
+
+ adminEvent.operation(OperationType.UPDATE).resourcePath(role).representation(rep).success();
+
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("Role with name " + rep.getName() + " already exists");
@@ -157,7 +171,7 @@ public class RoleContainerResource extends RoleResource {
@Path("{role-name}/composites")
@POST
@Consumes(MediaType.APPLICATION_JSON)
- public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
+ public void addComposites(@Context final UriInfo uriInfo, final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
auth.requireManage();
RoleModel role = roleContainer.getRole(roleName);
@@ -165,6 +179,8 @@ public class RoleContainerResource extends RoleResource {
throw new NotFoundException("Could not find role: " + roleName);
}
addComposites(roles, role);
+ adminEvent.operation(OperationType.ACTION).resourcePath(role, uriInfo.getPath()).representation(roles).success();
+
}
/**
@@ -177,7 +193,7 @@ public class RoleContainerResource extends RoleResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
- public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-name") String roleName) {
+ public Set<RoleRepresentation> getRoleComposites(@Context final UriInfo uriInfo, final @PathParam("role-name") String roleName) {
auth.requireManage();
RoleModel role = roleContainer.getRole(roleName);
@@ -197,7 +213,7 @@ public class RoleContainerResource extends RoleResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
- public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) {
+ public Set<RoleRepresentation> getRealmRoleComposites(@Context final UriInfo uriInfo, final @PathParam("role-name") String roleName) {
auth.requireManage();
RoleModel role = roleContainer.getRole(roleName);
@@ -218,7 +234,8 @@ public class RoleContainerResource extends RoleResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
- public Set<RoleRepresentation> getClientRoleComposites(final @PathParam("role-name") String roleName,
+ public Set<RoleRepresentation> getClientRoleComposites(@Context final UriInfo uriInfo,
+ final @PathParam("role-name") String roleName,
final @PathParam("clientId") String clientId) {
auth.requireManage();
@@ -246,7 +263,8 @@ public class RoleContainerResource extends RoleResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
- public Set<RoleRepresentation> getClientByIdRoleComposites(final @PathParam("role-name") String roleName,
+ public Set<RoleRepresentation> getClientByIdRoleComposites(@Context final UriInfo uriInfo,
+ final @PathParam("role-name") String roleName,
final @PathParam("id") String id) {
auth.requireManage();
@@ -272,7 +290,9 @@ public class RoleContainerResource extends RoleResource {
@Path("{role-name}/composites")
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
- public void deleteComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
+ public void deleteComposites(@Context final UriInfo uriInfo,
+ final @PathParam("role-name") String roleName,
+ List<RoleRepresentation> roles) {
auth.requireManage();
RoleModel role = roleContainer.getRole(roleName);
@@ -280,7 +300,7 @@ public class RoleContainerResource extends RoleResource {
throw new NotFoundException("Could not find role: " + roleName);
}
deleteComposites(roles, role);
+ adminEvent.operation(OperationType.DELETE).resourcePath(role, uriInfo.getPath()).success();
}
-
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
index 01fe1d6..7f195c5 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
@@ -2,6 +2,7 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -16,6 +17,7 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -30,13 +32,15 @@ public class ScopeMappedClientResource {
protected ClientModel client;
protected KeycloakSession session;
protected ClientModel scopedClient;
-
- public ScopeMappedClientResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, ClientModel scopedClient) {
+ protected AdminEventBuilder adminEvent;
+
+ public ScopeMappedClientResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, ClientModel scopedClient, AdminEventBuilder adminEvent) {
this.realm = realm;
this.auth = auth;
this.client = client;
this.session = session;
this.scopedClient = scopedClient;
+ this.adminEvent = adminEvent;
}
/**
@@ -106,8 +110,8 @@ public class ScopeMappedClientResource {
throw new NotFoundException("Role not found");
}
client.addScopeMapping(roleModel);
+ adminEvent.operation(OperationType.CREATE).resourcePath(client, "/roles").representation(roles).success();
}
-
}
/**
@@ -135,5 +139,6 @@ public class ScopeMappedClientResource {
client.deleteScopeMapping(roleModel);
}
}
+ adminEvent.operation(OperationType.DELETE).resourcePath(client, "/roles").representation(roles).success();
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
index 8d4e005..97b5e3b 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
@@ -2,6 +2,7 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -18,7 +19,10 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -36,12 +40,14 @@ public class ScopeMappedResource {
private RealmAuth auth;
protected ClientModel client;
protected KeycloakSession session;
+ protected AdminEventBuilder adminEvent;
- public ScopeMappedResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session) {
+ public ScopeMappedResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, AdminEventBuilder adminEvent) {
this.realm = realm;
this.auth = auth;
this.client = client;
this.session = session;
+ this.adminEvent = adminEvent;
}
/**
@@ -176,7 +182,7 @@ public class ScopeMappedResource {
}
client.addScopeMapping(roleModel);
}
-
+ adminEvent.operation(OperationType.CREATE).resourcePath(client, "/roles").representation(roles).success();
}
@@ -206,6 +212,8 @@ public class ScopeMappedResource {
client.deleteScopeMapping(roleModel);
}
}
+ adminEvent.operation(OperationType.DELETE).resourcePath(client, "/roles").representation(roles).success();
+
}
@Path("clients/{clientId}")
@@ -215,8 +223,7 @@ public class ScopeMappedResource {
if (app == null) {
throw new NotFoundException("Role not found");
}
-
- return new ScopeMappedClientResource(realm, auth, client, session, app);
+ return new ScopeMappedClientResource(realm, auth, client, session, app, adminEvent);
}
@Path("clients-by-id/{id}")
@@ -226,7 +233,6 @@ public class ScopeMappedResource {
if (app == null) {
throw new NotFoundException("Client not found");
}
-
- return new ScopeMappedClientResource(realm, auth, client, session, app);
+ return new ScopeMappedClientResource(realm, auth, client, session, app, adminEvent);
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
index f535b19..4e0d8f9 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
@@ -5,6 +5,7 @@ import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventType;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.exportimport.ClientImporter;
import org.keycloak.exportimport.ClientImporterFactory;
import org.keycloak.freemarker.Theme;
@@ -39,6 +40,8 @@ import java.util.Set;
*/
public class ServerInfoAdminResource {
+ private static final Map<String, List<String>> ENUMS = createEnumsMap(EventType.class, OperationType.class);
+
@Context
private KeycloakSession session;
@@ -61,7 +64,7 @@ public class ServerInfoAdminResource {
setProviders(info);
setProtocolMapperTypes(info);
setBuiltinProtocolMappers(info);
- setEventTypes(info);
+ info.setEnums(ENUMS);
return info;
}
@@ -181,15 +184,6 @@ public class ServerInfoAdminResource {
}
}
- private void setEventTypes(ServerInfoRepresentation info) {
- List<String> eventTypes = new LinkedList<>();
- for (EventType t : EventType.values()) {
- eventTypes.add(t.name());
- }
- Collections.sort(eventTypes);
- info.setEventTypes(eventTypes);
- }
-
public static class ServerInfoRepresentation {
private String version;
@@ -209,7 +203,7 @@ public class ServerInfoAdminResource {
private Map<String, List<ProtocolMapperTypeRepresentation>> protocolMapperTypes;
private Map<String, List<ProtocolMapperRepresentation>> builtinProtocolMappers;
- private List<String> eventTypes;
+ private Map<String, List<String>> enums;
public ServerInfoRepresentation() {
}
@@ -262,13 +256,30 @@ public class ServerInfoAdminResource {
this.builtinProtocolMappers = builtinProtocolMappers;
}
- public List<String> getEventTypes() {
- return eventTypes;
+ public Map<String, List<String>> getEnums() {
+ return enums;
+ }
+
+ public void setEnums(Map<String, List<String>> enums) {
+ this.enums = enums;
}
+ }
+
+ private static Map<String, List<String>> createEnumsMap(Class... enums) {
+ Map<String, List<String>> m = new HashMap<>();
+ for (Class e : enums) {
+ String n = e.getSimpleName();
+ n = Character.toLowerCase(n.charAt(0)) + n.substring(1);
+
+ List<String> l = new LinkedList<>();
+ for (Object c : e.getEnumConstants()) {
+ l.add(c.toString());
+ }
+ Collections.sort(l);
- public void setEventTypes(List<String> eventTypes) {
- this.eventTypes = eventTypes;
+ m.put(n, l);
}
+ return m;
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserClientRoleMappingsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserClientRoleMappingsResource.java
index e838333..9bd8160 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserClientRoleMappingsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserClientRoleMappingsResource.java
@@ -3,7 +3,9 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
@@ -16,7 +18,10 @@ import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -33,12 +38,18 @@ public class UserClientRoleMappingsResource {
protected RealmAuth auth;
protected UserModel user;
protected ClientModel client;
+ protected AdminEventBuilder adminEvent;
+
+ @Context
+ protected KeycloakSession session;
+
- public UserClientRoleMappingsResource(RealmModel realm, RealmAuth auth, UserModel user, ClientModel client) {
+ public UserClientRoleMappingsResource(RealmModel realm, RealmAuth auth, UserModel user, ClientModel client, AdminEventBuilder adminEvent) {
this.realm = realm;
this.auth = auth;
this.user = user;
this.client = client;
+ this.adminEvent = adminEvent;
}
/**
@@ -127,6 +138,7 @@ public class UserClientRoleMappingsResource {
}
user.grantRole(roleModel);
}
+ adminEvent.operation(OperationType.CREATE).resourcePath(client, user, "/roles/").representation(roles).success();
}
@@ -159,5 +171,6 @@ public class UserClientRoleMappingsResource {
user.deleteRoleMapping(roleModel);
}
}
+ adminEvent.operation(OperationType.DELETE).resourcePath(client, user, "/roles/").representation(roles).success();
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
index 188cb30..7bc54a9 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
@@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.constants.KerberosConstants;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
@@ -31,6 +32,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+
import java.util.LinkedList;
import java.util.List;
@@ -46,6 +48,8 @@ public class UserFederationResource {
protected RealmModel realm;
protected RealmAuth auth;
+
+ protected AdminEventBuilder adminEvent;
@Context
protected UriInfo uriInfo;
@@ -53,10 +57,11 @@ public class UserFederationResource {
@Context
protected KeycloakSession session;
- public UserFederationResource(RealmModel realm, RealmAuth auth) {
+ public UserFederationResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
this.auth = auth;
this.realm = realm;
-
+ this.adminEvent = adminEvent;
+
auth.init(RealmAuth.Resource.USER);
}
@@ -99,6 +104,8 @@ public class UserFederationResource {
UserFederationProviderFactoryRepresentation rep = new UserFederationProviderFactoryRepresentation();
rep.setId(factory.getId());
rep.setOptions(((UserFederationProviderFactory)factory).getConfigurationOptions());
+
+
return rep;
}
throw new NotFoundException("Could not find provider");
@@ -123,6 +130,9 @@ public class UserFederationResource {
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
checkKerberosCredential(model);
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(model).representation(rep).success();
+
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
}
@@ -146,6 +156,9 @@ public class UserFederationResource {
realm.updateUserFederationProvider(model);
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
checkKerberosCredential(model);
+
+ adminEvent.operation(OperationType.UPDATE).resourcePath(model).representation(rep).success();
+
}
/**
@@ -164,7 +177,6 @@ public class UserFederationResource {
return ModelToRepresentation.toRepresentation(model);
}
}
-
throw new NotFoundException("could not find provider");
}
@@ -182,6 +194,9 @@ public class UserFederationResource {
UserFederationProviderModel model = new UserFederationProviderModel(id, null, null, -1, null, -1, -1, 0);
realm.removeUserFederationProvider(model);
new UsersSyncManager().removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), model);
+
+ adminEvent.operation(OperationType.DELETE).resourcePath(model).success();
+
}
@@ -224,6 +239,7 @@ public class UserFederationResource {
} else if ("triggerChangedUsersSync".equals(action)) {
syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), model);
}
+ adminEvent.operation(OperationType.ACTION).resourcePath(model, "/sync").success();
return Response.noContent().build();
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index ee9dc90..c84b635 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -7,6 +7,7 @@ import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.ClientConnection;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
+import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
@@ -56,6 +57,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -78,6 +80,8 @@ public class UsersResource {
private RealmAuth auth;
+ private AdminEventBuilder adminEvent;
+
@Context
protected ClientConnection clientConnection;
@@ -90,9 +94,10 @@ public class UsersResource {
@Context
protected HttpHeaders headers;
- public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager) {
+ public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager, AdminEventBuilder adminEvent) {
this.auth = auth;
this.realm = realm;
+ this.adminEvent = adminEvent;
auth.init(RealmAuth.Resource.USER);
}
@@ -116,11 +121,11 @@ public class UsersResource {
throw new NotFoundException("User not found");
}
updateUserFromRep(user, rep);
+ adminEvent.operation(OperationType.UPDATE).resourcePath(user).representation(rep).success();
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
-
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return ErrorResponse.exists("User exists with same username or email");
@@ -152,11 +157,13 @@ public class UsersResource {
try {
UserModel user = session.users().addUser(realm, rep.getUsername());
updateUserFromRep(user, rep);
-
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(user).representation(rep).success();
+
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
-
+
return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getUsername()).build()).build();
} catch (ModelDuplicateException e) {
if (session.getTransaction().isActive()) {
@@ -217,7 +224,7 @@ public class UsersResource {
if (user == null) {
throw new NotFoundException("User not found");
}
-
+
UserRepresentation rep = ModelToRepresentation.toRepresentation(user);
if (realm.isIdentityFederationEnabled()) {
@@ -305,7 +312,7 @@ public class UsersResource {
FederatedIdentityModel socialLink = new FederatedIdentityModel(provider, rep.getUserId(), rep.getUserName());
session.users().addFederatedIdentity(realm, user, socialLink);
-
+ adminEvent.operation(OperationType.CREATE).resourcePath(user, uriInfo.getPath(), true).representation(rep).success();
return Response.noContent().build();
}
@@ -321,6 +328,7 @@ public class UsersResource {
if (!session.users().removeFederatedIdentity(realm, user, provider)) {
throw new NotFoundException("Link not found");
}
+ adminEvent.operation(OperationType.DELETE).resourcePath(user, uriInfo.getPath(), true).success();
}
/**
@@ -374,6 +382,7 @@ public class UsersResource {
} else {
throw new NotFoundException("Consent not found for user " + username + " and client " + clientId);
}
+ adminEvent.operation(OperationType.ACTION).resourcePath(user, client, uriInfo.getPath()).success();
}
/**
@@ -395,6 +404,7 @@ public class UsersResource {
for (UserSessionModel userSession : userSessions) {
AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
}
+ adminEvent.operation(OperationType.ACTION).resourcePath(user, uriInfo.getPath()).success();
}
/**
@@ -416,6 +426,7 @@ public class UsersResource {
boolean removed = new UserManager(session).removeUser(realm, user);
if (removed) {
+ adminEvent.operation(OperationType.DELETE).resourcePath(user).success();
return Response.noContent().build();
} else {
return ErrorResponse.error("User couldn't be deleted", Response.Status.BAD_REQUEST);
@@ -628,7 +639,8 @@ public class UsersResource {
}
user.grantRole(roleModel);
}
-
+
+ adminEvent.operation(OperationType.CREATE).resourcePath(user, realm, uriInfo.getPath()).representation(roles).success();
}
@@ -665,6 +677,8 @@ public class UsersResource {
user.deleteRoleMapping(roleModel);
}
}
+
+ adminEvent.operation(OperationType.DELETE).resourcePath(user, realm, uriInfo.getPath()).representation(roles).success();
}
@Path("{username}/role-mappings/clients/{clientId}")
@@ -679,8 +693,7 @@ public class UsersResource {
if (client == null) {
throw new NotFoundException("Client not found");
}
-
- return new UserClientRoleMappingsResource(realm, auth, user, client);
+ return new UserClientRoleMappingsResource(realm, auth, user, client, adminEvent);
}
@Path("{username}/role-mappings/clients-by-id/{id}")
@@ -695,8 +708,8 @@ public class UsersResource {
if (client == null) {
throw new NotFoundException("Client not found");
}
-
- return new UserClientRoleMappingsResource(realm, auth, user, client);
+
+ return new UserClientRoleMappingsResource(realm, auth, user, client, adminEvent);
}
/**
@@ -729,6 +742,8 @@ public class UsersResource {
throw new BadRequestException("Can't reset password as account is read only");
}
if (pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+
+ adminEvent.operation(OperationType.ACTION).resourcePath(user, uriInfo.getPath()).success();
}
/**
@@ -748,6 +763,7 @@ public class UsersResource {
}
user.setTotp(false);
+ adminEvent.operation(OperationType.ACTION).resourcePath(user, uriInfo.getPath()).success();
}
/**
@@ -823,6 +839,9 @@ public class UsersResource {
this.session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendPasswordReset(link, expiration);
//audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
+
+ adminEvent.operation(OperationType.ACTION).resourcePath(user, uriInfo.getPath()).success();
+
return Response.ok().build();
} catch (EmailException e) {
logger.error("Failed to send password reset email", e);
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index d3586bc..b0f02ad 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -25,6 +25,7 @@ import org.keycloak.services.scheduled.ScheduledTaskRunner;
import org.keycloak.services.util.JsonConfigProvider;
import org.keycloak.timer.TimerProvider;
import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.SystemEnvProperties;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Application;
@@ -139,14 +140,8 @@ public class KeycloakApplication extends Application {
}
if (node != null) {
- Properties properties = new Properties();
- properties.putAll(System.getProperties());
- for(Map.Entry<String, String> e : System.getenv().entrySet()) {
- properties.put("env." + e.getKey(), e.getValue());
- }
-
+ Properties properties = new SystemEnvProperties();
Config.init(new JsonConfigProvider(node, properties));
-
return;
} else {
log.warn("Config 'keycloak-server.json' not found");
diff --git a/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java b/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java
index 7cb962d..7734f48 100755
--- a/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java
+++ b/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java
@@ -10,6 +10,11 @@ import org.keycloak.provider.Spi;
public class WellKnownSpi implements Spi {
@Override
+ public boolean isPrivate() {
+ return true;
+ }
+
+ @Override
public String getName() {
return "well-known";
}
diff --git a/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java b/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java
index 949fea7..fd500a8 100644
--- a/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java
+++ b/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java
@@ -29,6 +29,11 @@ public class SocialProviderSpi implements Spi {
public static final String SOCIAL_SPI_NAME = "social";
@Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
public String getName() {
return SOCIAL_SPI_NAME;
}
diff --git a/testsuite/docker-cluster/shared-files/keycloak-base-prepare.sh b/testsuite/docker-cluster/shared-files/keycloak-base-prepare.sh
index 965da9b..c303009 100644
--- a/testsuite/docker-cluster/shared-files/keycloak-base-prepare.sh
+++ b/testsuite/docker-cluster/shared-files/keycloak-base-prepare.sh
@@ -12,8 +12,8 @@ mkdir -p mysql/main && mv /mysql-connector-java-5.1.32.jar mysql/main/
cp /keycloak-docker-cluster/shared-files/mysql-module.xml mysql/main/module.xml
mv mysql $JBOSS_MODULES_HOME/com/
-sed -i -e "s/<extensions>/&\n <extension module=\"org.keycloak.keycloak-subsystem\"\/>/" $JBOSS_HOME/standalone/configuration/standalone-ha.xml
-sed -i -e 's/<profile>/&\n <subsystem xmlns="urn:jboss:domain:keycloak:1.0">\n <auth-server name="main-auth-server">\n <enabled>true<\/enabled>\n <web-context>auth<\/web-context>\n <\/auth-server> \n <\/subsystem>/' $JBOSS_HOME/standalone/configuration/standalone-ha.xml && \
+sed -i -e "s/<extensions>/&\n <extension module=\"org.keycloak.keycloak-server-subsystem\"\/>/" $JBOSS_HOME/standalone/configuration/standalone-ha.xml
+sed -i -e 's/<profile>/&\n <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">\n <auth-server name="main-auth-server">\n <enabled>true<\/enabled>\n <web-context>auth<\/web-context>\n <\/auth-server> \n <\/subsystem>/' $JBOSS_HOME/standalone/configuration/standalone-ha.xml && \
sed -i -e 's/<security-domains>/&\n <security-domain name="keycloak">\n <authentication>\n <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"\/>\n <\/authentication>\n <\/security-domain>/' $JBOSS_HOME/standalone/configuration/standalone-ha.xml && \
sed -i -e 's/<drivers>/&\n <driver name="mysql" module="com.mysql">\n <xa-datasource-class>com.mysql.jdbc.Driver<\/xa-datasource-class>\n <driver-class>com.mysql.jdbc.Driver<\/driver-class>\n <\/driver>/' $JBOSS_HOME/standalone/configuration/standalone-ha.xml && \
sed -i -e 's/<\/periodic-rotating-file-handler>/&\n <logger category=\"org.keycloak\">\n <level name=\"DEBUG\" \/> \n <\/logger>\n <logger category=\"org.jboss.resteasy.core.ResourceLocator\">\n <level name=\"ERROR\" \/> \n <\/logger>/' $JBOSS_HOME/standalone/configuration/standalone-ha.xml
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index 13c181b..ce80527 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -8,6 +8,7 @@ import org.junit.Assert;
import org.junit.rules.TestRule;
import org.junit.runners.model.Statement;
import org.keycloak.Config;
+import org.keycloak.events.admin.AdminEvent;
import org.keycloak.events.Details;
import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
@@ -195,6 +196,12 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
@Override
public void close() {
}
+
+ @Override
+ public void onEvent(AdminEvent event, boolean includeRepresentation) {
+ // TODO Auto-generated method stub
+
+ }
};
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java
new file mode 100644
index 0000000..58c5698
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java
@@ -0,0 +1,226 @@
+package org.keycloak.testsuite.events;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.keycloak.events.EventStoreProvider;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.AuthDetails;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.testsuite.rule.KeycloakRule;
+
+/**
+ * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
+ */
+public class AdminEventStoreProviderTest {
+
+ @ClassRule
+ public static KeycloakRule kc = new KeycloakRule();
+
+ private KeycloakSession session;
+
+ private EventStoreProvider eventStore;
+
+ @Before
+ public void before() {
+ session = kc.startSession();
+ eventStore = session.getProvider(EventStoreProvider.class);
+ }
+
+ @After
+ public void after() {
+ eventStore.clearAdmin();
+ kc.stopSession(session, true);
+ }
+
+ @Test
+ public void save() {
+ eventStore.onEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ }
+
+ @Test
+ public void query() {
+ long oldest = System.currentTimeMillis() - 30000;
+ long newest = System.currentTimeMillis() + 30000;
+
+ eventStore.onEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create("realmId2", OperationType.CREATE, "realmId2", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(oldest, "realmId", OperationType.CREATE, "realmId", "clientId2", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+ resetSession();
+
+ Assert.assertEquals(5, eventStore.createAdminQuery().authClient("clientId").getResultList().size());
+ Assert.assertEquals(5, eventStore.createAdminQuery().authRealm("realmId").getResultList().size());
+ Assert.assertEquals(4, eventStore.createAdminQuery().operation(OperationType.CREATE).getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().operation(OperationType.CREATE, OperationType.ACTION).getResultList().size());
+ Assert.assertEquals(4, eventStore.createAdminQuery().authUser("userId").getResultList().size());
+
+ Assert.assertEquals(1, eventStore.createAdminQuery().authUser("userId").operation(OperationType.ACTION).getResultList().size());
+
+ Assert.assertEquals(2, eventStore.createAdminQuery().maxResults(2).getResultList().size());
+ Assert.assertEquals(1, eventStore.createAdminQuery().firstResult(5).getResultList().size());
+
+ Assert.assertEquals(newest, eventStore.createAdminQuery().maxResults(1).getResultList().get(0).getTime());
+ Assert.assertEquals(oldest, eventStore.createAdminQuery().firstResult(5).maxResults(1).getResultList().get(0).getTime());
+
+ eventStore.clearAdmin("realmId");
+ eventStore.clearAdmin("realmId2");
+
+ Assert.assertEquals(0, eventStore.createAdminQuery().getResultList().size());
+
+ String d1 = new String("2015-03-04");
+ String d2 = new String("2015-03-05");
+ String d3 = new String("2015-03-06");
+ String d4 = new String("2015-03-07");
+
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ Date date1 = null, date2 = null, date3 = null, date4 = null;
+
+ try {
+ date1 = formatter.parse(d1);
+ date2 = formatter.parse(d2);
+ date3 = formatter.parse(d3);
+ date4 = formatter.parse(d4);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ eventStore.onEvent(create(date1, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(date1, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(date2, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(date2, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(date3, "realmId", OperationType.UPDATE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(date3, "realmId", OperationType.DELETE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(date4, "realmId2", OperationType.CREATE, "realmId2", "clientId2", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(date4, "realmId2", OperationType.CREATE, "realmId2", "clientId2", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+ resetSession();
+
+ Assert.assertEquals(6, eventStore.createAdminQuery().authClient("clientId").getResultList().size());
+ Assert.assertEquals(2, eventStore.createAdminQuery().authClient("clientId2").getResultList().size());
+
+ Assert.assertEquals(6, eventStore.createAdminQuery().authRealm("realmId").getResultList().size());
+ Assert.assertEquals(2, eventStore.createAdminQuery().authRealm("realmId2").getResultList().size());
+
+ Assert.assertEquals(4, eventStore.createAdminQuery().authUser("userId").getResultList().size());
+ Assert.assertEquals(4, eventStore.createAdminQuery().authUser("userId2").getResultList().size());
+
+ Assert.assertEquals(2, eventStore.createAdminQuery().operation(OperationType.ACTION).getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().operation(OperationType.CREATE, OperationType.ACTION).getResultList().size());
+ Assert.assertEquals(1, eventStore.createAdminQuery().operation(OperationType.UPDATE).getResultList().size());
+ Assert.assertEquals(1, eventStore.createAdminQuery().operation(OperationType.DELETE).getResultList().size());
+ Assert.assertEquals(4, eventStore.createAdminQuery().operation(OperationType.CREATE).getResultList().size());
+
+ Assert.assertEquals(8, eventStore.createAdminQuery().fromTime("2015-03-04").getResultList().size());
+ Assert.assertEquals(8, eventStore.createAdminQuery().toTime("2015-03-07").getResultList().size());
+
+ Assert.assertEquals(4, eventStore.createAdminQuery().fromTime("2015-03-06").getResultList().size());
+ Assert.assertEquals(4, eventStore.createAdminQuery().toTime("2015-03-05").getResultList().size());
+
+ Assert.assertEquals(0, eventStore.createAdminQuery().fromTime("2015-03-08").getResultList().size());
+ Assert.assertEquals(0, eventStore.createAdminQuery().toTime("2015-03-03").getResultList().size());
+
+ Assert.assertEquals(8, eventStore.createAdminQuery().fromTime("2015-03-04").toTime("2015-03-07").getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().fromTime("2015-03-05").toTime("2015-03-07").getResultList().size());
+ Assert.assertEquals(4, eventStore.createAdminQuery().fromTime("2015-03-04").toTime("2015-03-05").getResultList().size());
+ Assert.assertEquals(4, eventStore.createAdminQuery().fromTime("2015-03-06").toTime("2015-03-07").getResultList().size());
+
+ Assert.assertEquals(0, eventStore.createAdminQuery().fromTime("2015-03-01").toTime("2015-03-03").getResultList().size());
+ Assert.assertEquals(0, eventStore.createAdminQuery().fromTime("2015-03-08").toTime("2015-03-10").getResultList().size());
+
+ }
+
+ @Test
+ public void queryResourcePath() {
+ long oldest = System.currentTimeMillis() - 30000;
+ long newest = System.currentTimeMillis() + 30000;
+
+ eventStore.onEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create("realmId2", OperationType.CREATE, "realmId2", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(oldest, "realmId", OperationType.CREATE, "realmId", "clientId2", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+ resetSession();
+
+ Assert.assertEquals(6, eventStore.createAdminQuery().resourcePath("/admin").getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().resourcePath("/realms").getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().resourcePath("/master").getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().resourcePath("/admin/realms").getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().resourcePath("/realms/master").getResultList().size());
+ Assert.assertEquals(6, eventStore.createAdminQuery().resourcePath("/admin/realms/master").getResultList().size());
+ }
+
+ @Test
+ public void clear() {
+ eventStore.onEvent(create(System.currentTimeMillis() - 30000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis() - 20000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis() - 30000, "realmId2", OperationType.CREATE, "realmId2", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+ resetSession();
+
+ eventStore.clearAdmin("realmId");
+
+ Assert.assertEquals(1, eventStore.createAdminQuery().getResultList().size());
+ }
+
+ @Test
+ public void clearOld() {
+ eventStore.onEvent(create(System.currentTimeMillis() - 30000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis() - 20000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+ eventStore.onEvent(create(System.currentTimeMillis() - 30000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+ resetSession();
+
+ eventStore.clearAdmin("realmId", System.currentTimeMillis() - 10000);
+
+ Assert.assertEquals(2, eventStore.createAdminQuery().getResultList().size());
+ }
+
+ private AdminEvent create(String realmId, OperationType operation, String authRealmId, String authClientId, String authUserId, String authIpAddress, String resourcePath, String error) {
+ return create(System.currentTimeMillis(), realmId, operation, authRealmId, authClientId, authUserId, authIpAddress, resourcePath, error);
+ }
+
+ private AdminEvent create(Date date, String realmId, OperationType operation, String authRealmId, String authClientId, String authUserId, String authIpAddress, String resourcePath, String error) {
+ return create(date.getTime(), realmId, operation, authRealmId, authClientId, authUserId, authIpAddress, resourcePath, error);
+ }
+
+ private AdminEvent create(long time, String realmId, OperationType operation, String authRealmId, String authClientId, String authUserId, String authIpAddress, String resourcePath, String error) {
+ AdminEvent e = new AdminEvent();
+ e.setTime(time);
+ e.setRealmId(realmId);
+ e.setOperationType(operation);
+ AuthDetails authDetails = new AuthDetails();
+ authDetails.setRealmId(authRealmId);
+ authDetails.setClientId(authClientId);
+ authDetails.setUserId(authUserId);
+ authDetails.setIpAddress(authIpAddress);
+ e.setAuthDetails(authDetails);
+ e.setResourcePath(resourcePath);
+ e.setError(error);
+
+ return e;
+ }
+
+ private void resetSession() {
+ kc.stopSession(session, true);
+ session = kc.startSession();
+ eventStore = session.getProvider(EventStoreProvider.class);
+ }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/utils/ListSpi.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/utils/ListSpi.java
new file mode 100644
index 0000000..82695bc
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/utils/ListSpi.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.utils;
+
+import org.keycloak.provider.Spi;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ServiceLoader;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ListSpi {
+
+ public static void main(String[] args) {
+ List<String> l = new LinkedList<>();
+ for (Spi s : ServiceLoader.load(Spi.class)) {
+ l.add(fixedLength(s.getName()) + s.isPrivate());
+ }
+ Collections.sort(l);
+ System.out.println(fixedLength("SPI") + "Private");
+ System.out.println("-------------------------------------");
+ for (String s : l) {
+ System.out.println(s);
+ }
+ }
+
+ public static String fixedLength(String s) {
+ while (s.length() < 30) {
+ s = s + " ";
+ }
+ return s;
+ }
+}
diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties
index d94d2f9..a776341 100755
--- a/testsuite/integration/src/test/resources/log4j.properties
+++ b/testsuite/integration/src/test/resources/log4j.properties
@@ -18,6 +18,7 @@ log4j.logger.org.keycloak=info
# log4j.logger.org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider=debug
# log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
+# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
# Enable to view kerberos/spnego logging
# log4j.logger.org.keycloak.broker.kerberos=trace
diff --git a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
index 15269f2..277a708 100755
--- a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
@@ -48,8 +48,7 @@
"cacheThemes": "${keycloak.theme.cacheThemes:true}",
"folder": {
"dir": "${keycloak.theme.dir}"
- } ,
- "welcomeTheme": "logo-example"
+ }
},
"login": {
testsuite/wildfly/pom.xml 504(+504 -0)
diff --git a/testsuite/wildfly/pom.xml b/testsuite/wildfly/pom.xml
new file mode 100644
index 0000000..4fbbe04
--- /dev/null
+++ b/testsuite/wildfly/pom.xml
@@ -0,0 +1,504 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-testsuite-pom</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.3.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-testsuite-wildfly</artifactId>
+ <name>Keycloak WildFly 9.x Integration TestSuite</name>
+ <description />
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-dependencies-server-all</artifactId>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-admin-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.6.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>jaxrs-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-multipart-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jackson-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-undertow</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.zxing</groupId>
+ <artifactId>javase</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-ldap-federation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-kerberos-federation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-undertow-adapter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adapter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.undertow</groupId>
+ <artifactId>undertow-servlet</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.undertow</groupId>
+ <artifactId>undertow-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-xc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate.javax.persistence</groupId>
+ <artifactId>hibernate-jpa-2.0-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.icegreen</groupId>
+ <artifactId>greenmail</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-java</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-chrome-driver</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-undertow</artifactId>
+ <version>${wildfly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-testsuite-integration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-testsuite-integration</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-jaas</artifactId>
+ <version>${jetty9.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ <version>${jetty9.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-webapp</artifactId>
+ <version>${jetty9.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-security</artifactId>
+ <version>${jetty9.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-servlet</artifactId>
+ <version>${jetty9.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <configuration>
+ <workingDirectory>${project.basedir}</workingDirectory>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>keycloak-server</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <configuration>
+ <mainClass>org.keycloak.testsuite.KeycloakServer</mainClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>mail-server</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <configuration>
+ <mainClass>org.keycloak.testsuite.MailServer</mainClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>totp</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <configuration>
+ <mainClass>org.keycloak.testsuite.TotpGenerator</mainClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>jpa</id>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <keycloak.realm.provider>jpa</keycloak.realm.provider>
+ <keycloak.user.provider>jpa</keycloak.user.provider>
+ <keycloak.eventStore.provider>jpa</keycloak.eventStore.provider>
+ <keycloak.userSessions.provider>jpa</keycloak.userSessions.provider>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>mongo</id>
+
+ <properties>
+ <keycloak.connectionsMongo.host>localhost</keycloak.connectionsMongo.host>
+ <keycloak.connectionsMongo.port>27018</keycloak.connectionsMongo.port>
+ <keycloak.connectionsMongo.db>keycloak</keycloak.connectionsMongo.db>
+ <keycloak.connectionsMongo.clearOnStartup>true</keycloak.connectionsMongo.clearOnStartup>
+ <keycloak.connectionsMongo.bindIp>127.0.0.1</keycloak.connectionsMongo.bindIp>
+ </properties>
+
+ <build>
+ <plugins>
+
+ <!-- Postpone tests to "integration-test" phase, so that we can bootstrap embedded mongo on 27018 before running tests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>test</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <keycloak.realm.provider>mongo</keycloak.realm.provider>
+ <keycloak.user.provider>mongo</keycloak.user.provider>
+ <keycloak.audit.provider>mongo</keycloak.audit.provider>
+ <keycloak.userSessions.provider>mongo</keycloak.userSessions.provider>
+ <keycloak.connectionsMongo.host>${keycloak.connectionsMongo.host}</keycloak.connectionsMongo.host>
+ <keycloak.connectionsMongo.port>${keycloak.connectionsMongo.port}</keycloak.connectionsMongo.port>
+ <keycloak.connectionsMongo.db>${keycloak.connectionsMongo.db}</keycloak.connectionsMongo.db>
+ <keycloak.connectionsMongo.clearOnStartup>${keycloak.connectionsMongo.clearOnStartup}</keycloak.connectionsMongo.clearOnStartup>
+ <keycloak.connectionsMongo.bindIp>${keycloak.connectionsMongo.bindIp}</keycloak.connectionsMongo.bindIp>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ <execution>
+ <id>default-test</id>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Embedded mongo -->
+ <plugin>
+ <groupId>com.github.joelittlejohn.embedmongo</groupId>
+ <artifactId>embedmongo-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>start-mongodb</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>start</goal>
+ </goals>
+ <configuration>
+ <port>${keycloak.connectionsMongo.port}</port>
+ <logging>file</logging>
+ <logFile>${project.build.directory}/mongodb.log</logFile>
+ <bindIp>${keycloak.connectionsMongo.bindIp}</bindIp>
+ </configuration>
+ </execution>
+ <execution>
+ <id>stop-mongodb</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>stop</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ </profile>
+
+ <profile>
+ <id>infinispan</id>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <keycloak.realm.cache.provider>infinispan</keycloak.realm.cache.provider>
+ <keycloak.user.cache.provider>infinispan</keycloak.user.cache.provider>
+ <keycloak.userSessions.provider>infinispan</keycloak.userSessions.provider>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <!-- MySQL -->
+ <profile>
+ <activation>
+ <property>
+ <name>keycloak.connectionsJpa.driver</name>
+ <value>com.mysql.jdbc.Driver</value>
+ </property>
+ </activation>
+ <id>mysql</id>
+ <dependencies>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>${mysql.version}</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <!-- PostgreSQL -->
+ <profile>
+ <activation>
+ <property>
+ <name>keycloak.connectionsJpa.driver</name>
+ <value>org.postgresql.Driver</value>
+ </property>
+ </activation>
+ <id>postgresql</id>
+ <dependencies>
+ <dependency>
+ <groupId>org.postgresql</groupId>
+ <artifactId>postgresql</artifactId>
+ <version>${postgresql.version}</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>clean-jpa</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.liquibase</groupId>
+ <artifactId>liquibase-maven-plugin</artifactId>
+ <configuration>
+ <changeLogFile>META-INF/jpa-changelog-master.xml</changeLogFile>
+
+ <url>${keycloak.connectionsJpa.url}</url>
+ <driver>${keycloak.connectionsJpa.driver}</driver>
+ <username>${keycloak.connectionsJpa.user}</username>
+ <password>${keycloak.connectionsJpa.password}</password>
+
+ <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
+ </configuration>
+ <executions>
+ <execution>
+ <id>clean-jpa</id>
+ <phase>clean</phase>
+ <goals>
+ <goal>dropAll</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/testsuite/wildfly/src/test/config/arq/arquillian.xml b/testsuite/wildfly/src/test/config/arq/arquillian.xml
new file mode 100644
index 0000000..7fcf61c
--- /dev/null
+++ b/testsuite/wildfly/src/test/config/arq/arquillian.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+
+ <defaultProtocol type="jmx-as7" />
+
+ <container qualifier="jboss" default="true">
+ <configuration>
+ <property name="jbossHome">${basedir}/target/jbossas</property>
+ <property name="javaVmArguments">${server.jvm.args} -Djboss.inst=${basedir}/target/jbossas -Dtest.bind.address=${node0}</property>
+ <property name="serverConfig">${jboss.server.config.file.name:standalone.xml}</property>
+ <property name="jbossArguments">${jboss.args}</property>
+ <!-- -Djboss.inst is not necessarily needed, only in case the test case neeeds path to the instance it runs in.
+ In the future, Arquillian should capable of injecting it into @ArquillianResource File or such. -->
+ <property name="allowConnectingToRunningServer">true</property>
+ <property name="managementAddress">${node0:127.0.0.1}</property>
+ <property name="managementPort">${as.managementPort:9990}</property>
+
+ <!-- AS7-4070 -->
+ <property name="waitForPorts">${as.debug.port:8787} ${as.managementPort:9990}</property>
+ <property name="waitForPortsTimeoutInSeconds">8</property>
+ </configuration>
+ </container>
+
+</arquillian>
diff --git a/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java b/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
index d0e57f9..ac92339 100644
--- a/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
+++ b/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
@@ -8,6 +8,12 @@ import org.keycloak.provider.Spi;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class TimerSpi implements Spi {
+
+ @Override
+ public boolean isPrivate() {
+ return true;
+ }
+
@Override
public String getName() {
return "timer";