diff --git a/.gitignore b/.gitignore
index 319769bf2a..44612eb8b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,10 +9,11 @@
.settings
.classpath
-
# NetBeans #
############
+nbactions.xml
nb-configuration.xml
+catalog.xml
# Compiled source #
###################
diff --git a/distribution/appliance-dist/assembly.xml b/distribution/appliance-dist/assembly.xml
index 0e788d8c34..53de6bca3c 100755
--- a/distribution/appliance-dist/assembly.xml
+++ b/distribution/appliance-dist/assembly.xml
@@ -22,6 +22,8 @@
**/*.shwelcome-content/***/modules/system/layers/base/org/picketlink/**
+ **/modules/system/layers/base/org/jboss/as/cli/**
+ **/modules/system/layers/base/org/jboss/aesh/**
@@ -39,13 +41,6 @@
org/picketlink/**
-
- ${project.build.directory}/unpacked/deployments
- keycloak/standalone/deployments
-
- keycloak-ds.xml
-
- ${project.build.directory}/unpacked/deployments/auth-server.war/WEB-INF/classes/META-INFkeycloak/standalone/configuration
diff --git a/distribution/appliance-dist/src/main/xslt/standalone.xsl b/distribution/appliance-dist/src/main/xslt/standalone.xsl
index 7b8ba53ed6..3cb32a9d2c 100755
--- a/distribution/appliance-dist/src/main/xslt/standalone.xsl
+++ b/distribution/appliance-dist/src/main/xslt/standalone.xsl
@@ -34,7 +34,12 @@
-
+
+
+ true
+ auth
+
+
@@ -56,7 +61,7 @@
+ longer works -->
@@ -67,14 +72,14 @@
+ longer works -->
-
+
diff --git a/distribution/modules/build.xml b/distribution/modules/build.xml
index 7495cdc077..e1019285c1 100755
--- a/distribution/modules/build.xml
+++ b/distribution/modules/build.xml
@@ -51,6 +51,14 @@
+
+
+
+
+
+
+
+
diff --git a/distribution/modules/lib.xml b/distribution/modules/lib.xml
index 6e2f849367..3d9438a4a4 100755
--- a/distribution/modules/lib.xml
+++ b/distribution/modules/lib.xml
@@ -52,7 +52,12 @@
-
+
+
+
+
diff --git a/distribution/modules/pom.xml b/distribution/modules/pom.xml
index afc41ed6fb..d0a9838a2d 100755
--- a/distribution/modules/pom.xml
+++ b/distribution/modules/pom.xml
@@ -1,26 +1,26 @@
+~ 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.
+-->
org.bouncycastle
bcprov-jdk16
+
+ org.wildfly.core
+ wildfly-cli
+ ${wildfly.core.version}
+ org.picketlinkpicketlink-common
@@ -119,7 +124,10 @@
org.picketlinkpicketlink-impl
-
+
+ org.jboss.aesh
+ aesh
+
@@ -211,6 +219,31 @@
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy
+ compile
+
+ copy
+
+
+
+
+ org.keycloak
+ keycloak-server
+ ${project.version}
+ war
+ true
+ ${project.build.directory}/modules/org/keycloak/keycloak-wildfly-subsystem/main/auth-server
+
+
+
+
+
+
diff --git a/distribution/modules/src/main/resources/modules/org/jboss/aesh/main/module.xml b/distribution/modules/src/main/resources/modules/org/jboss/aesh/main/module.xml
new file mode 100644
index 0000000000..8789ef344e
--- /dev/null
+++ b/distribution/modules/src/main/resources/modules/org/jboss/aesh/main/module.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/modules/src/main/resources/modules/org/jboss/as/cli/main/module.xml b/distribution/modules/src/main/resources/modules/org/jboss/as/cli/main/module.xml
new file mode 100644
index 0000000000..c46ff3aa97
--- /dev/null
+++ b/distribution/modules/src/main/resources/modules/org/jboss/as/cli/main/module.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/modules/src/main/resources/modules/org/jboss/as/cli/main/wildfly-cli-1.0.0.Alpha11-SNAPSHOT.jar b/distribution/modules/src/main/resources/modules/org/jboss/as/cli/main/wildfly-cli-1.0.0.Alpha11-SNAPSHOT.jar
new file mode 100644
index 0000000000..7e9aac263e
Binary files /dev/null and b/distribution/modules/src/main/resources/modules/org/jboss/as/cli/main/wildfly-cli-1.0.0.Alpha11-SNAPSHOT.jar differ
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-subsystem/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-subsystem/main/module.xml
index 0bc0ec9f78..636909dd99 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-subsystem/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-subsystem/main/module.xml
@@ -2,7 +2,7 @@
+
+
+
+
+
+
@@ -31,6 +37,7 @@
+
diff --git a/docbook/reference/en/en-US/modules/server-installation.xml b/docbook/reference/en/en-US/modules/server-installation.xml
index 1fae98c859..74e5411f51 100755
--- a/docbook/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/reference/en/en-US/modules/server-installation.xml
@@ -124,6 +124,14 @@ keycloak-war-dist-all-&project.version;/
If you have Keycloak on JBoss AS 7.1.1 these steps.
+
+ Subsystem Installation
+
+ For WildFly installations, the Keycloak server is not deployed from the /deployments directory. Instead, the Keycloak
+ subsystem module contains the Keycloak server and it is controlled by the subsystem. If you are using the
+ appliance install, this subsystem is already present and a Keycloak server is pre-defined in the subsytem declaration.
+
+ Configuring the Server
@@ -749,4 +757,142 @@ keycloak-war-dist-all-&project.version;/
+
+ Configuring Servers from the Subsystem
+
+ If you are using WildFly, the Keycloak server is deployed and configured from the Keycloak subsystem. This makes provisioning simpler in a domain environment.
+ It also allows you to create more than one Keycloak server instance inside a single WildFly instance. And, you can upload providers, themes, and
+ server configurations without disturbing Keycloak's auth-server.war.
+
+
+ Manually Creating A Server
+
+ A Keycloak server can be declared by editing standalone.xml or domain.xml.
+
+
+
+
+
+
+
+ true
+ auth
+
+
+ false
+ auth2
+
+
+
+]]>
+
+
+
+
+ If you create more than one Keycloak server, you will need to use CLI to fully configure each instance. At the least,
+ you will need to run the update-server-config operation.
+
+
+
+
+ Using CLI and CLI GUI with the Keycloak Subsystem
+
+ Servers can also be added/removed or enabled/disabled at runtime using the CLI or
+ CLI GUI tool. These are tools that ship with WildFly and also with
+ the Keycloak Appliance installation. See CLI or
+ CLI GUI documentation to learn more about how to start the tools,
+ issue commands, and create CLI scripts.
+
+
+To start CLI with the Keycloak Appliance install:
+/keycloak/bin
+./jboss-cli.sh --gui
+or
+./jboss.cli.bat --gui]]>
+
+Your Keycloak server must be running to start in --gui mode.
+
+
+ Basic CLI Commands
+
+Command to add a server in CLI:
+
+
+Because "enabled=true", a new Keycloak server will be immediately deployed. By default "enabled" is set to false.
+
+
+Command to remove a server in CLI:
+
+
+The Keycloak server will be immediately deleted and undeployed.
+
+
+Command to enable or disable a server in CLI:
+
+
+The Keycloak server will be immediately deployed or undeployed, but not deleted.
+
+
+
+ Uploading extra configuration using CLI
+
+ The WildFly Keycloak subsystem allows you to upload keycloak-server.json, provider jars, and theme jars to a Keycloak server instance. The
+ CLI operations for this are "update-server-config" and "add-provider". You may use plain or CLI scripts for these operations. The following
+ examples are shown using CLI GUI for clarity.
+
+
+ To use a new keycloak-server.json file for your server, find your server under the Keycloak subsystem. Then right-click the server,
+ select "update-server-config", and upload your file.
+
+
+
+
+
+
+
+
+
+
+
+ If you use the update-server-config operation, you should delete or rename <WILDFLY_HOME>/standalone/configuration/keycloak-server.json.
+ Otherwise, all Keycloak server instances will use this file instead of your uploaded file.
+
+
+
+ To upload a new provider jar or theme jar to your server, find your server under the Keycloak subsystem. Then right-click the server,
+ select "add-provider", and upload your file.
+
+
+
+
+
+
+
+
+
+
+ Adding a Keycloak server in Domain Mode
+
+ In domain mode, you start the server with the "domain" command instead of the "standalone" command. In this case, the Keycloak subsystem is
+ defined in domain/configuration/domain.xml instead of standalone/configuration.standalone.xml. Inside domain.xml, you will see more than one
+ profile. A Keycloak subsystem can be defined in zero or more of those profiles.
+
+
+ In the example below, a Keycloak server named "foo" is defined in the "full" profile. The "full" profile is assigned to the "main-server-group".
+ Every WildFly instance that belongs to "main-server-group" will get an identically configured deployment of the "foo" Keycloak server.
+
+
+ All operations discussed earlier are valid for a Keycloak server in a domain. You can enable/disable, upload new keyclaok-server.json, and add provider jars.
+ In the following example, any changes that are made to the "foo" server will be automatically propogated to every instance in "main-server-group".
+
+
+
+
+
+
diff --git a/docbook/reference/en/images/add-provider-dialog.png b/docbook/reference/en/images/add-provider-dialog.png
new file mode 100644
index 0000000000..ee1c44a38d
Binary files /dev/null and b/docbook/reference/en/images/add-provider-dialog.png differ
diff --git a/docbook/reference/en/images/add-provider-select.png b/docbook/reference/en/images/add-provider-select.png
new file mode 100644
index 0000000000..c0f67661ba
Binary files /dev/null and b/docbook/reference/en/images/add-provider-select.png differ
diff --git a/docbook/reference/en/images/domain-mode.png b/docbook/reference/en/images/domain-mode.png
new file mode 100644
index 0000000000..9d96bd0624
Binary files /dev/null and b/docbook/reference/en/images/domain-mode.png differ
diff --git a/docbook/reference/en/images/update-server-config-dialog.png b/docbook/reference/en/images/update-server-config-dialog.png
new file mode 100644
index 0000000000..9c52546c65
Binary files /dev/null and b/docbook/reference/en/images/update-server-config-dialog.png differ
diff --git a/docbook/reference/en/images/update-server-config-select.png b/docbook/reference/en/images/update-server-config-select.png
new file mode 100644
index 0000000000..2af89df7d0
Binary files /dev/null and b/docbook/reference/en/images/update-server-config-select.png differ
diff --git a/integration/wildfly-subsystem/pom.xml b/integration/wildfly-subsystem/pom.xml
index d776e6006a..ed0a337428 100755
--- a/integration/wildfly-subsystem/pom.xml
+++ b/integration/wildfly-subsystem/pom.xml
@@ -42,11 +42,9 @@
org.apache.maven.pluginsmaven-surefire-plugin
- 2.8.1falsetrue
- -Xmx512mjboss.home
@@ -56,9 +54,8 @@
**/*TestCase.java
- once
-
+
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java
index 55e47eba7f..ea26666714 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java
@@ -31,6 +31,10 @@ import org.keycloak.subsystem.logging.KeycloakLogger;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import org.jboss.as.ee.component.EEModuleDescription;
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.MountedDeploymentOverlay;
/**
* Pass authentication data (keycloak.json) as a servlet context param so it can be read by the KeycloakServletExtension.
@@ -45,14 +49,14 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
// two places to avoid dependency between Keycloak Subsystem and Keyclaok Undertow Integration.
public static final String AUTH_DATA_PARAM_NAME = "org.keycloak.json.adapterConfig";
- public static final Phase PHASE = Phase.INSTALL;
- // Seems wise to have this run after INSTALL_WAR_DEPLOYMENT
- public static final int PRIORITY = Phase.INSTALL_WAR_DEPLOYMENT - 1;
+ public static final Phase PHASE = Phase.POST_MODULE;
+ // This needs to run just before bean validator factory
+ public static final int PRIORITY = Phase.POST_MODULE_VALIDATOR_FACTORY - 1;
// not sure if we need this yet, keeping here just in case
protected void addSecurityDomain(DeploymentUnit deploymentUnit, KeycloakAdapterConfigService service) {
String deploymentName = deploymentUnit.getName();
- if (!service.isKeycloakDeployment(deploymentName)) {
+ if (!service.isSecureDeployment(deploymentName)) {
return;
}
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
@@ -75,11 +79,16 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
String deploymentName = deploymentUnit.getName();
KeycloakAdapterConfigService service = KeycloakAdapterConfigService.find(phaseContext.getServiceRegistry());
//log.info("********* CHECK KEYCLOAK DEPLOYMENT: " + deploymentName);
- if (service.isKeycloakDeployment(deploymentName)) {
-
+ if (service.isSecureDeployment(deploymentName)) {
addKeycloakAuthData(phaseContext, deploymentName, service);
}
+ if (service.isKeycloakServerDeployment(deploymentName)) {
+ final EEModuleDescription description = deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION);
+ String webContext = service.getWebContext(deploymentName);
+ if (webContext == null) throw new DeploymentUnitProcessingException("Can't determine web context/module for Keycloak Auth Server");
+ description.setModuleName(webContext);
+ }
// FYI, Undertow Extension will find deployments that have auth-method set to KEYCLOAK
// todo notsure if we need this
@@ -99,6 +108,7 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
webMetaData = new JBossWebMetaData();
warMetaData.setMergedJBossWebMetaData(webMetaData);
}
+
LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
if (loginConfig == null) {
loginConfig = new LoginConfigMetaData();
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigService.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigService.java
index eb820fcff8..868f5858d0 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigService.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigService.java
@@ -51,7 +51,12 @@ public final class KeycloakAdapterConfigService implements Service realms = new HashMap();
- private Map deployments = new HashMap();
+
+ // keycloak-secured deployments
+ private Map secureDeployments = new HashMap();
+
+ // key=auth-server deployment name; value=web-context
+ private Map webContexts = new HashMap();
private KeycloakAdapterConfigService() {
@@ -72,6 +77,22 @@ public final class KeycloakAdapterConfigService implements Service 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);
+ }
+
private void readRealm(XMLExtendedStreamReader reader, List list) throws XMLStreamException {
String realmName = readNameAttribute(reader);
ModelNode addRealm = new ModelNode();
@@ -157,11 +178,28 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader
getServerGroupNames(OperationContext context) {
+ return context.readResourceFromRoot(PathAddress.EMPTY_ADDRESS).getChildrenNames("server-group");
+ }
+
+ private void addContent(OperationContext context, PathAddress overlayAddress, byte[] bytes, String overlayPath) throws OperationFailedException {
+ PathAddress contentAddress = overlayAddress.append("content", overlayPath);
+ ModelNode op = Util.createAddOperation(contentAddress);
+
+ ModelNode content = new ModelNode();
+ content.get("bytes").set(bytes);
+ op.get("content").set(content);
+
+ doAddStep(context, contentAddress, op);
+ }
+
+ private void doAddStep(OperationContext context, PathAddress address, ModelNode operation) {
+ //System.out.println("**** Adding Add Step ****");
+ //System.out.println(scrub(operation).toString());
+ context.addStep(operation, getHandler(context, address, ADD), OperationContext.Stage.MODEL);
+ }
+
+ // used for debugging
+ private ModelNode scrub(ModelNode op) {
+ ModelNode scrubbed = op.clone();
+ if (scrubbed.has("content")) {
+ scrubbed.get("content").set("BYTES REMOVED FOR DISPLAY");
+ }
+ if (scrubbed.has("bytes-to-upload")) {
+ scrubbed.get("bytes-to-upload").set("BYTES REMOVED FOR DISPLAY");
+ }
+ return scrubbed;
+ }
+
+ /**
+ * Get the WAR path where the overlay will live.
+ *
+ * @param file The name of the file being uploaded.
+ * @return The overlay path as a String.
+ */
+ abstract String getOverlayPath(String fileName);
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AddProviderHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AddProviderHandler.java
new file mode 100644
index 0000000000..f661891b89
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AddProviderHandler.java
@@ -0,0 +1,59 @@
+/*
+ * 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.extension.authserver;
+
+import java.io.File;
+import org.jboss.as.controller.OperationDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+/**
+ * Operation to add a provider jar to WEB-INF/lib.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class AddProviderHandler extends AbstractAddOverlayHandler {
+
+ public static final String OP = "add-provider";
+
+ public static final AddProviderHandler INSTANCE = new AddProviderHandler();
+
+ protected static final SimpleAttributeDefinition UPLOADED_FILE_NAME =
+ new SimpleAttributeDefinitionBuilder(UPLOADED_FILE_OP_NAME, ModelType.STRING, false)
+ .setAllowExpression(false)
+ .setAllowNull(false)
+ .setDefaultValue(new ModelNode().set("myprovider.jar"))
+ .build();
+
+ public static OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OP, AuthServerDefinition.rscDescriptionResolver)
+ .addParameter(BYTES_TO_UPLOAD)
+ .addParameter(UPLOADED_FILE_NAME)
+ .build();
+
+ @Override
+ String getOverlayPath(String fileName) {
+ if (!fileName.toLowerCase().endsWith(".jar")) {
+ throw new IllegalArgumentException("Uploaded file name must end with .jar");
+ }
+ return "/WEB-INF/lib/" + fileName;
+ }
+
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerAddHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerAddHandler.java
new file mode 100755
index 0000000000..fd3fcddda5
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerAddHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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.extension.authserver;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.dmr.ModelNode;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
+import org.jboss.as.controller.registry.Resource;
+import org.keycloak.subsystem.extension.KeycloakAdapterConfigService;
+
+/**
+ * Add an auth server.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public final class AuthServerAddHandler extends AbstractAddStepHandler {
+
+ public static AuthServerAddHandler INSTANCE = new AuthServerAddHandler();
+
+ private AuthServerAddHandler() {
+ }
+
+ @Override
+ protected void populateModel(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException {
+ // TODO: localize exception. get id number
+ if (!operation.get(OP).asString().equals(ADD)) {
+ throw new OperationFailedException("Unexpected operation for add Auth Server. operation=" + operation.toString());
+ }
+
+ ModelNode model = resource.getModel();
+ for (AttributeDefinition attr : AuthServerDefinition.ALL_ATTRIBUTES) {
+ attr.validateAndSet(operation, model);
+ }
+
+ // returns early if on domain controller
+ if (!requiresRuntime(context)) return;
+
+ // don't want to try to start server on host controller
+ if (!context.isNormalServer()) return;
+
+
+ ModelNode webContextNode = model.get(AuthServerDefinition.WEB_CONTEXT.getName());
+ if (!webContextNode.isDefined()) webContextNode = AuthServerDefinition.WEB_CONTEXT.getDefaultValue();
+ String webContext = webContextNode.asString();
+
+ ModelNode isEnabled = model.get("enabled");
+ boolean enabled = isEnabled.isDefined() && isEnabled.asBoolean();
+
+ AuthServerUtil authServerUtil = new AuthServerUtil(operation);
+ authServerUtil.addStepToUploadAuthServer(context, enabled);
+ KeycloakAdapterConfigService.INSTANCE.addServerDeployment(authServerUtil.getDeploymentName(), webContext);
+ }
+
+ @Override
+ protected boolean requiresRuntimeVerification() {
+ return false;
+ }
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerDefinition.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerDefinition.java
new file mode 100755
index 0000000000..ff43a6f71c
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerDefinition.java
@@ -0,0 +1,131 @@
+/*
+ * 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.extension.authserver;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.descriptions.ResourceDescriptionResolver;
+import org.jboss.as.controller.operations.validation.ParameterValidator;
+import org.jboss.as.controller.registry.OperationEntry;
+import org.keycloak.subsystem.extension.KeycloakAdapterConfigService;
+import org.keycloak.subsystem.extension.KeycloakExtension;
+
+/**
+ * Defines attributes and operations for an Auth Server
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class AuthServerDefinition extends SimpleResourceDefinition {
+
+ public static final String TAG_NAME = "auth-server";
+
+ protected static final SimpleAttributeDefinition ENABLED =
+ new SimpleAttributeDefinitionBuilder("enabled", ModelType.BOOLEAN, true)
+ .setXmlName("enabled")
+ .setAllowExpression(true)
+ .setDefaultValue(new ModelNode(false))
+ .setRestartAllServices()
+ .build();
+
+ protected static final SimpleAttributeDefinition WEB_CONTEXT =
+ new SimpleAttributeDefinitionBuilder("web-context", ModelType.STRING, true)
+ .setXmlName("web-context")
+ .setAllowExpression(true)
+ .setDefaultValue(new ModelNode("auth"))
+ .setValidator(new WebContextValidator())
+ .setRestartAllServices()
+ .build();
+
+ protected static final ResourceDescriptionResolver rscDescriptionResolver = KeycloakExtension.getResourceDescriptionResolver(TAG_NAME);
+
+ public static final List ALL_ATTRIBUTES = new ArrayList();
+ static {
+ ALL_ATTRIBUTES.add(ENABLED);
+ ALL_ATTRIBUTES.add(WEB_CONTEXT);
+ }
+
+ private static final Map DEFINITION_LOOKUP = new HashMap();
+ static {
+ for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
+ DEFINITION_LOOKUP.put(def.getXmlName(), def);
+ }
+ }
+
+ private static AuthServerWriteAttributeHandler attrHandler = new AuthServerWriteAttributeHandler(ALL_ATTRIBUTES);
+
+ public AuthServerDefinition() {
+ super(PathElement.pathElement(TAG_NAME),
+ rscDescriptionResolver,
+ AuthServerAddHandler.INSTANCE,
+ AuthServerRemoveHandler.INSTANCE,
+ null,
+ OperationEntry.Flag.RESTART_ALL_SERVICES);
+ }
+
+ @Override
+ public void registerOperations(ManagementResourceRegistration resourceRegistration) {
+ super.registerOperations(resourceRegistration);
+ resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
+ resourceRegistration.registerOperationHandler(AddProviderHandler.DEFINITION, AddProviderHandler.INSTANCE);
+ resourceRegistration.registerOperationHandler(OverlayKeycloakServerJsonHandler.DEFINITION, OverlayKeycloakServerJsonHandler.INSTANCE);
+ }
+
+ @Override
+ public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+ super.registerAttributes(resourceRegistration);
+ for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
+ resourceRegistration.registerReadWriteAttribute(attrDef, null, attrHandler);
+ }
+ }
+
+ public static SimpleAttributeDefinition lookup(String name) {
+ return DEFINITION_LOOKUP.get(name);
+ }
+
+ private static class WebContextValidator implements ParameterValidator {
+
+ @Override
+ public void validateParameter(String paramName, ModelNode value) throws OperationFailedException {
+ String strValue = value.asString();
+ if (KeycloakAdapterConfigService.INSTANCE.isWebContextUsed(strValue)) {
+ throw new OperationFailedException("Can not set web-context to '" + strValue + "'. web-context must be unique among all deployments.");
+ }
+ }
+
+ @Override
+ public void validateResolvedParameter(String paramName, ModelNode value) throws OperationFailedException {
+ String strValue = value.asString();
+ if (KeycloakAdapterConfigService.INSTANCE.isWebContextUsed(strValue)) {
+ throw new OperationFailedException("Can not set web-context to '" + strValue + "'. web-context must be unique among all deployments.");
+ }
+ }
+
+ }
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerRemoveHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerRemoveHandler.java
new file mode 100644
index 0000000000..f84e45ffe1
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerRemoveHandler.java
@@ -0,0 +1,67 @@
+/*
+ * 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.extension.authserver;
+
+import org.jboss.as.controller.AbstractRemoveStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.operations.common.Util;
+import org.jboss.dmr.ModelNode;
+import org.keycloak.subsystem.extension.KeycloakAdapterConfigService;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOYMENT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOVE;
+import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
+
+/**
+ * Remove an auth-server from a realm.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public final class AuthServerRemoveHandler extends AbstractRemoveStepHandler {
+
+ public static AuthServerRemoveHandler INSTANCE = new AuthServerRemoveHandler();
+
+ private AuthServerRemoveHandler() {}
+
+ @Override
+ protected void performRemove(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ String deploymentName = AuthServerUtil.getDeploymentName(operation);
+ KeycloakAdapterConfigService.INSTANCE.removeServerDeployment(deploymentName);
+
+ if (requiresRuntime(context)) { // don't do this on a domain controller
+ addStepToRemoveAuthServer(context, deploymentName);
+ }
+
+ super.performRemove(context, operation, model);
+ }
+
+ private void addStepToRemoveAuthServer(OperationContext context, String deploymentName) {
+ PathAddress deploymentAddress = PathAddress.pathAddress(PathElement.pathElement(DEPLOYMENT, deploymentName));
+ ModelNode op = Util.createOperation(REMOVE, deploymentAddress);
+ context.addStep(op, getRemoveHandler(context, deploymentAddress), OperationContext.Stage.MODEL);
+ }
+
+ private OperationStepHandler getRemoveHandler(OperationContext context, PathAddress address) {
+ ImmutableManagementResourceRegistration rootResourceRegistration = context.getRootResourceRegistration();
+ return rootResourceRegistration.getOperationHandler(address, REMOVE);
+ }
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerUtil.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerUtil.java
new file mode 100644
index 0000000000..d4085c998c
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerUtil.java
@@ -0,0 +1,186 @@
+/*
+ * 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.extension.authserver;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.PathElement;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ARCHIVE;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOY;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOYMENT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ENABLED;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PERSISTENT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PATH;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REDEPLOY;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RUNTIME_NAME;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UNDEPLOY;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.URL;
+import org.jboss.as.controller.operations.common.Util;
+import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleIdentifier;
+import org.jboss.modules.ModuleLoadException;
+
+/**
+ * Utility methods that help assemble and start an auth server.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class AuthServerUtil {
+
+ private static final ModuleIdentifier KEYCLOAK_SUBSYSTEM = ModuleIdentifier.create("org.keycloak.keycloak-wildfly-subsystem");
+
+ private final String authServerName;
+ private final PathAddress pathAddress;
+ private final String deploymentName;
+
+ //private String overlayName;
+ private final Module subsysModule;
+ private final String keycloakVersion;
+ private final boolean isAuthServerExploded;
+
+ //private File overlaysDir;
+ private final URI authServerUri;
+ //private URL serverConfig = null;
+ //private Set spiUrls = new HashSet();
+
+ AuthServerUtil(ModelNode operation) {
+ this.authServerName = getAuthServerName(operation);
+ this.pathAddress = getPathAddress(operation);
+ this.deploymentName = getDeploymentName(operation);
+ this.subsysModule = findSubsysModule();
+ this.keycloakVersion = subsysModule.getProperty("keycloak-version");
+ this.isAuthServerExploded = Boolean.parseBoolean(subsysModule.getProperty("auth-server-exploded"));
+ this.authServerUri = findAuthServerUri();
+ }
+
+ String getDeploymentName() {
+ return this.deploymentName;
+ }
+
+ private Module findSubsysModule() {
+ try {
+ return Module.getModuleFromCallerModuleLoader(KEYCLOAK_SUBSYSTEM);
+ } catch (ModuleLoadException e) {
+ throw new IllegalStateException("Can't find Keycloak subsystem.", e);
+ }
+ }
+
+ private URI findAuthServerUri() throws IllegalStateException {
+ try {
+ URL subsysJar = this.subsysModule.getExportedResource("keycloak-wildfly-subsystem-" + this.keycloakVersion + ".jar");
+ File subsysDir = new File(subsysJar.toURI()).getParentFile();
+ File authServerDir = new File(subsysDir, "auth-server");
+ if (this.isAuthServerExploded) {
+ return authServerDir.toURI();
+ } else {
+ return new File(authServerDir, "keycloak-server-" + keycloakVersion + ".war").toURI();
+ }
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException(e);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ void addStepToUploadAuthServer(OperationContext context, boolean isEnabled) throws OperationFailedException {
+ PathAddress deploymentAddress = deploymentAddress();
+ ModelNode op = Util.createOperation(ADD, deploymentAddress);
+ op.get(ENABLED).set(isEnabled);
+ op.get(PERSISTENT).set(false); // prevents writing this deployment out to standalone.xml
+
+ if (authServerUri == null) {
+ throw new OperationFailedException("Keycloak Auth Server WAR not found in keycloak-wildfly-subsystem module");
+ }
+
+ op.get(CONTENT).add(makeContentItem());
+
+ context.addStep(op, getHandler(context, deploymentAddress, ADD), OperationContext.Stage.MODEL);
+ }
+
+ private ModelNode makeContentItem() throws OperationFailedException {
+ ModelNode contentItem = new ModelNode();
+
+ if (this.isAuthServerExploded) {
+ String urlString = new File(authServerUri).getAbsolutePath();
+ contentItem.get(PATH).set(urlString);
+ contentItem.get(ARCHIVE).set(false);
+ } else {
+ String urlString = authServerUri.toString();
+ contentItem.get(URL).set(urlString);
+ }
+
+ return contentItem;
+ }
+
+ void addStepToRedeployAuthServer(OperationContext context) {
+ addDeploymentAction(context, REDEPLOY);
+ }
+
+ void addStepToUndeployAuthServer(OperationContext context) {
+ addDeploymentAction(context, UNDEPLOY);
+ }
+
+ void addStepToDeployAuthServer(OperationContext context) {
+ addDeploymentAction(context, DEPLOY);
+ }
+
+ private void addDeploymentAction(OperationContext context, String operation) {
+ PathAddress deploymentAddress = deploymentAddress();
+ ModelNode op = Util.createOperation(operation, deploymentAddress);
+ op.get(RUNTIME_NAME).set(deploymentName);
+ context.addStep(op, getHandler(context, deploymentAddress, operation), OperationContext.Stage.MODEL);
+ }
+
+ private PathAddress deploymentAddress() {
+ return PathAddress.pathAddress(PathElement.pathElement(DEPLOYMENT, deploymentName));
+ }
+
+ static OperationStepHandler getHandler(OperationContext context, PathAddress address, String opName) {
+ ImmutableManagementResourceRegistration rootResourceRegistration = context.getRootResourceRegistration();
+ return rootResourceRegistration.getOperationHandler(address, opName);
+ }
+
+ static String getDeploymentName(ModelNode operation) {
+ String deploymentName = Util.getNameFromAddress(operation.get(ADDRESS));
+ if (!deploymentName.toLowerCase().endsWith(".war")) {
+ deploymentName += ".war";
+ }
+
+ return deploymentName;
+ }
+
+ static String getAuthServerName(ModelNode operation) {
+ PathAddress pathAddr = getPathAddress(operation);
+ return pathAddr.getElement(pathAddr.size() - 1).getValue();
+ }
+
+ static PathAddress getPathAddress(ModelNode operation) {
+ return PathAddress.pathAddress(operation.get(ADDRESS));
+ }
+
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerWriteAttributeHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerWriteAttributeHandler.java
new file mode 100755
index 0000000000..24decfcc02
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerWriteAttributeHandler.java
@@ -0,0 +1,91 @@
+/*
+ * 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.extension.authserver;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+
+import java.util.List;
+import org.jboss.as.controller.ModelOnlyWriteAttributeHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.registry.Resource;
+import org.jboss.dmr.ModelNode;
+import org.keycloak.subsystem.extension.KeycloakAdapterConfigService;
+
+/**
+ * Update an attribute on an Auth Server.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class AuthServerWriteAttributeHandler extends ModelOnlyWriteAttributeHandler { //extends ReloadRequiredWriteAttributeHandler {
+
+ public AuthServerWriteAttributeHandler(List definitions) {
+ this(definitions.toArray(new AttributeDefinition[definitions.size()]));
+ }
+
+ public AuthServerWriteAttributeHandler(AttributeDefinition... definitions) {
+ super(definitions);
+ }
+
+ @Override
+ protected void finishModelStage(OperationContext context, ModelNode operation, String attributeName, ModelNode newValue, ModelNode oldValue, Resource model) throws OperationFailedException {
+ if (!context.isNormalServer() || attribNotChanging(attributeName, newValue, oldValue)) {
+ super.finishModelStage(context, operation, attributeName, newValue, oldValue, model);
+ return;
+ }
+
+ AuthServerUtil authServerUtil = new AuthServerUtil(operation);
+ boolean isEnabled = isEnabled(model); // is server currently enabled?
+
+ if (attributeName.equals(AuthServerDefinition.WEB_CONTEXT.getName())) {
+ String deploymentName = AuthServerUtil.getDeploymentName(operation);
+ KeycloakAdapterConfigService.INSTANCE.removeServerDeployment(deploymentName);
+ KeycloakAdapterConfigService.INSTANCE.addServerDeployment(deploymentName, newValue.asString());
+ if (isEnabled) {
+ authServerUtil.addStepToRedeployAuthServer(context);
+ }
+ }
+
+ if (attributeName.equals(AuthServerDefinition.ENABLED.getName())) {
+ if (!isEnabled) { // we are disabling
+ authServerUtil.addStepToUndeployAuthServer(context);
+ } else { // we are enabling
+ authServerUtil.addStepToDeployAuthServer(context);
+ }
+ }
+
+ super.finishModelStage(context, operation, attributeName, newValue, oldValue, model);
+ }
+
+ // Is auth server currently enabled?
+ private boolean isEnabled(Resource model) {
+ ModelNode authServer = model.getModel();
+ ModelNode isEnabled = authServer.get(AuthServerDefinition.ENABLED.getName());
+ if (!isEnabled.isDefined()) isEnabled = AuthServerDefinition.ENABLED.getDefaultValue();
+ return isEnabled.asBoolean();
+ }
+
+ private boolean attribNotChanging(String attributeName, ModelNode newValue, ModelNode oldValue) {
+ SimpleAttributeDefinition attribDef = AuthServerDefinition.lookup(attributeName);
+ if (!oldValue.isDefined()) oldValue = attribDef.getDefaultValue();
+ if (!newValue.isDefined()) newValue = attribDef.getDefaultValue();
+ return newValue.equals(oldValue);
+ }
+
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/OverlayKeycloakServerJsonHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/OverlayKeycloakServerJsonHandler.java
new file mode 100644
index 0000000000..485c37dd29
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/OverlayKeycloakServerJsonHandler.java
@@ -0,0 +1,43 @@
+/*
+ * 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.extension.authserver;
+
+import org.jboss.as.controller.OperationDefinition;
+import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
+
+/**
+ * Operation to overlay keycloak-server.json.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class OverlayKeycloakServerJsonHandler extends AbstractAddOverlayHandler {
+
+ public static final String OP = "update-server-config";
+
+ public static final OverlayKeycloakServerJsonHandler INSTANCE = new OverlayKeycloakServerJsonHandler();
+
+ public static OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OP, AuthServerDefinition.rscDescriptionResolver)
+ .addParameter(BYTES_TO_UPLOAD)
+ .build();
+
+ @Override
+ String getOverlayPath(String fileName) {
+ return "/WEB-INF/classes/META-INF/keycloak-server.json";
+ }
+
+}
diff --git a/integration/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/extension/LocalDescriptions.properties b/integration/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/extension/LocalDescriptions.properties
index 524ae4d60c..3239f14040 100755
--- a/integration/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/extension/LocalDescriptions.properties
+++ b/integration/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/extension/LocalDescriptions.properties
@@ -1,9 +1,23 @@
keycloak.subsystem=Keycloak subsystem
keycloak.subsystem.add=Operation Adds Keycloak subsystem
keycloak.subsystem.remove=Operation removes Keycloak subsystem
+keycloak.subsystem.auth-server=Keycloak Auth Server
keycloak.subsystem.realm=A Keycloak realm.
keycloak.subsystem.secure-deployment=A deployment secured by Keycloak.
+
+keycloak.auth-server=A Keycloak Auth Server
+keycloak.auth-server.add=Add an Auth Server to the subsystem.
+keycloak.auth-server.remove=Remove an Auth Server from the subsystem.
+keycloak.auth-server.add-provider=Add a provider service jar to the Keycloak auth server.
+keycloak.auth-server.add-provider.uploaded-file-name=The file name of the provider service jar to be added or updated.
+keycloak.auth-server.add-provider.bytes-to-upload=The bytes of the provider service jar to be added or updated.
+keycloak.auth-server.update-server-config=Upload a new keycloak-server.json configuration file for the Keycloak auth server.
+keycloak.auth-server.update-server-config.uploaded-file-name=Should be the name keycloak-server.json.
+keycloak.auth-server.update-server-config.bytes-to-upload=The bytes of the keycloak-server.json file to be added or updated.
+keycloak.auth-server.enabled=Enable or disable the Auth Server.
+keycloak.auth-server.web-context=Web context the auth-server will use. Also, the module name of the auth-server deployment.
+
keycloak.realm=A Keycloak realm.
keycloak.realm.add=Add a realm definition to the subsystem.
keycloak.realm.remove=Remove a realm from the subsystem.
diff --git a/pom.xml b/pom.xml
index 40305f343c..14ee353381 100755
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,7 @@
pom
+ 0.33.121.461.9.94.2.1
@@ -35,7 +36,7 @@
1.5.107.1.1.Final8.1.0.Final
- 1.0.0.Alpha5
+ 1.0.0.Alpha91.0.2.Final2.21.14.1-beta
@@ -143,6 +144,17 @@
mail${javax.mail.version}
+
+ org.jboss.aesh
+ aesh
+ ${aesh.version}
+
+
+ junit
+ junit
+
+
+ org.jboss.resteasyjaxrs-api
@@ -347,24 +359,24 @@
${twitter4j.version}
-
+
- com.google.zxing
- core
- ${google.zxing.version}
-
+ com.google.zxing
+ core
+ ${google.zxing.version}
+
- com.google.zxing
- javase
- ${google.zxing.version}
-
+ com.google.zxing
+ javase
+ ${google.zxing.version}
+
-
-
- com.icegreen
- greenmail
- 1.3.1b
-
+
+
+ com.icegreen
+ greenmail
+ 1.3.1b
+
@@ -373,18 +385,18 @@
${winzipaes.version}
-
-
- org.seleniumhq.selenium
- selenium-java
- ${selenium.version}
-
-
- org.seleniumhq.selenium
- selenium-chrome-driver
- ${selenium.version}
+
+
+ org.seleniumhq.selenium
+ selenium-java
+ ${selenium.version}
+
+
+ org.seleniumhq.selenium
+ selenium-chrome-driver
+ ${selenium.version}test
-
+ org.mongodbmongo-java-driver
@@ -424,12 +436,12 @@
${mysql.version}
+
+ org.apache.httpcomponents
+ httpclient
+ ${keycloak.apache.httpcomponents.version}
+
+ -->
org.wildfly.corewildfly-controller
@@ -452,6 +464,18 @@
pomtest
+
+ org.wildfly.core
+ wildfly-core-feature-pack
+ pom
+ ${wildfly.core.version}
+
+
+ org.wildfly.core
+ wildfly-core-feature-pack
+ zip
+ ${wildfly.core.version}
+ org.wildflywildfly-undertow
@@ -486,6 +510,11 @@
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.8
+ org.apache.maven.pluginsmaven-surefire-plugin
@@ -593,14 +622,14 @@
maven-deploy-plugin2.5
-
- org.apache.maven.plugins
- maven-war-plugin
- 2.3
-
- false
-
-
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 2.3
+
+ false
+
+ com.lazerycode.jmeterjmeter-maven-plugin