keycloak-uncached

Merge pull request #855 from ssilvert/subsys-enhancements KEYCLOAK-839

11/12/2014 6:37:39 PM

Changes

distribution/modules/src/main/resources/modules/org/jboss/as/cli/main/wildfly-cli-1.0.0.Alpha11-SNAPSHOT.jar 0(+0 -0)

pom.xml 7(+6 -1)

Details

diff --git a/distribution/modules/pom.xml b/distribution/modules/pom.xml
index 40e03a2..5a3dbb0 100755
--- a/distribution/modules/pom.xml
+++ b/distribution/modules/pom.xml
@@ -1,27 +1,5 @@
 <?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.
--->
-
 <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">
@@ -86,7 +64,6 @@
         <dependency>
             <groupId>org.wildfly.core</groupId>
             <artifactId>wildfly-cli</artifactId>
-            <version>${wildfly.core.version}</version>
         </dependency>
         <dependency>
             <groupId>org.picketlink</groupId>
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
index 8789ef3..5b3cf8d 100644
--- 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
@@ -28,7 +28,7 @@
     </properties>
 
     <resources>
-        <artifact name="org.jboss.aesh:aesh:0.33.12"/>
+        <!-- Insert resources here -->
     </resources>
 
     <dependencies>
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
index c46ff3a..59cb8c7 100644
--- 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
@@ -31,7 +31,7 @@
     <main-class name="org.jboss.as.cli.CommandLineMain"/>
 
     <resources>
-        <resource-root path="wildfly-cli-1.0.0.Alpha11-SNAPSHOT.jar"/>
+        <!-- Insert resources here -->
     </resources>
 
     <dependencies>
diff --git a/docbook/reference/en/en-US/modules/server-installation.xml b/docbook/reference/en/en-US/modules/server-installation.xml
index 74e5411..360f57e 100755
--- a/docbook/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/reference/en/en-US/modules/server-installation.xml
@@ -799,7 +799,7 @@ keycloak-war-dist-all-&project.version;/
             <title>Using CLI and CLI GUI with the Keycloak Subsystem</title>
             <para>
                 Servers can also be added/removed or enabled/disabled at runtime using the <ulink url="https://developer.jboss.org/wiki/CommandLineInterface">CLI</ulink> or 
-                <ulink url="https://developer.jboss.org/wiki/AGUIForTheCommandLineInterface">CLI GUI</ulink> tool.  These are tools that ship with WildFly and also with
+                <ulink url="https://developer.jboss.org/wiki/AGUIForTheCommandLineInterface">CLI GUI</ulink> tool.  These are tools that ship with WildFly/EAP and also with
                 the Keycloak Appliance installation.  See <ulink url="https://developer.jboss.org/wiki/CommandLineInterface">CLI</ulink> or 
                 <ulink url="https://developer.jboss.org/wiki/AGUIForTheCommandLineInterface">CLI GUI</ulink> documentation to learn more about how to start the tools,
                 issue commands, and create CLI scripts.
@@ -812,7 +812,7 @@ cd <APPLIANCE_INSTALL_DIR>/keycloak/bin
 or
 ./jboss.cli.bat --gui]]>
 </programlisting>
-<note>Your Keycloak server must be running to start in --gui mode.</note>
+<note>Your server must be running to start in --gui mode.</note>
 </para>  
             <section>
                 <title>Basic CLI Commands</title>
@@ -842,7 +842,7 @@ The Keycloak server will be immediately deployed or undeployed, but not deleted.
                 <title>Uploading extra configuration using CLI</title>
                 <para>
                     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
+                    CLI operations for this are "update-server-config" and "add-provider".  You may use CLI, CLI GUI, or CLI scripts for these operations.  The following
                     examples are shown using <ulink url="https://developer.jboss.org/wiki/AGUIForTheCommandLineInterface">CLI GUI</ulink> for clarity.
                 </para>
                 <para>
@@ -874,6 +874,39 @@ The Keycloak server will be immediately deployed or undeployed, but not deleted.
                     <imagedata fileref="images/add-provider-dialog.png"/>
                 </para>
             </section>
+            <section>
+                <title>Working with overlays</title>
+                <para>
+                    When you upload a provider jar, theme jar, or keycloak-server.json file, you are creating an overlay.  That is, the file is "overlayed"
+                    onto the Keycloak server at deploy time.  There are two additional operations that help you manage these overlays.  They are "list-overlays" and
+                    "remove-overlay".  Here are CLI examples of these operations.
+                </para>
+<para>
+    <programlisting>
+/subsystem=keycloak/auth-server=my-auth-server/:list-overlays
+{
+    "outcome" => "success",
+    "result" => [
+        "/WEB-INF/classes/META-INF/keycloak-server.json",
+        "/WEB-INF/lib/federation-properties-example.jar"
+    ],
+}</programlisting>
+    <programlisting>
+/subsystem=keycloak/auth-server=my-auth-server/:remove-overlay(overlay-file-path=/WEB-INF/lib/federation-properties-example.jar,redeploy=true)
+{
+    "outcome" => "success",
+}</programlisting>
+</para>
+                <para>
+                    <note>
+                        Notice in the "list-overlays" operation, the full path to the server config is 
+                        /WEB-INF/classes/META-INF/keycloak-server.json.  This is always the uploaded path for an "update-server-config" operation.
+                        If you remove this overlay, the Keycloak server will revert to its default keycloak-server.json.  If you have a 
+                        keycloak-server.json file in your &lt;WILDFLY_HOME&gt;/standalone/configuration directory, it will always take precedence
+                        over both the default and the overlay.
+                    </note>
+                </para>
+            </section>
         </section>
         <section>
             <title>Adding a Keycloak server in Domain Mode</title>
diff --git a/docbook/reference/en/images/add-provider-dialog.png b/docbook/reference/en/images/add-provider-dialog.png
index ee1c44a..976e5e1 100644
Binary files a/docbook/reference/en/images/add-provider-dialog.png 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
index c0f6766..1c2e51a 100644
Binary files a/docbook/reference/en/images/add-provider-select.png and b/docbook/reference/en/images/add-provider-select.png differ
diff --git a/docbook/reference/en/images/update-server-config-dialog.png b/docbook/reference/en/images/update-server-config-dialog.png
index 9c52546..5b07227 100644
Binary files a/docbook/reference/en/images/update-server-config-dialog.png 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
index 2af89df..b9156e6 100644
Binary files a/docbook/reference/en/images/update-server-config-select.png and b/docbook/reference/en/images/update-server-config-select.png differ
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AbstractAddOverlayHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AbstractAddOverlayHandler.java
index e9780a8..c701cf2 100644
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AbstractAddOverlayHandler.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AbstractAddOverlayHandler.java
@@ -21,12 +21,11 @@ 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.ProcessType;
 import org.jboss.as.controller.SimpleAttributeDefinition;
 import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
-import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOYMENT_OVERLAY;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOVE;
 import org.jboss.as.controller.operations.common.Util;
 import org.jboss.as.controller.registry.Resource;
 import org.jboss.dmr.ModelNode;
@@ -48,21 +47,39 @@ public abstract class AbstractAddOverlayHandler implements OperationStepHandler 
             .setAllowNull(false)
             .build();
 
+    static final SimpleAttributeDefinition REDEPLOY_SERVER =
+        new SimpleAttributeDefinitionBuilder("redeploy", ModelType.BOOLEAN, true)
+        .setXmlName("redeploy")
+        .setAllowExpression(true)
+        .setDefaultValue(new ModelNode(false))
+        .build();
+
+    protected static final SimpleAttributeDefinition OVERWRITE =
+        new SimpleAttributeDefinitionBuilder("overwrite", ModelType.BOOLEAN, true)
+        .setXmlName("overwrite")
+        .setAllowExpression(true)
+        .setDefaultValue(new ModelNode(false))
+        .build();
+
     @Override
     public void execute(final OperationContext context, final ModelNode operation) throws OperationFailedException {
         //System.out.println("*** execute operation ***");
         //System.out.println(scrub(operation));
 
         String uploadFileName = operation.get(UPLOADED_FILE_OP_NAME).asString();
+        boolean isRedeploy = isRedeploy(context, operation);
+        boolean isOverwrite = getBooleanFromOperation(operation, OVERWRITE);
+
         String overlayPath = getOverlayPath(uploadFileName);
-        String overlayName = AuthServerUtil.getAuthServerName(operation) + "-keycloak-overlay";
-        PathAddress overlayAddress = PathAddress.pathAddress(PathElement.pathElement(DEPLOYMENT_OVERLAY, overlayName));
+        String overlayName = AuthServerUtil.getOverlayName(operation);
+        PathAddress overlayAddress = AuthServerUtil.getOverlayAddress(overlayName);
+        String deploymentName = AuthServerUtil.getDeploymentName(operation);
 
-        boolean isOverlayExists = isOverlayExists(context, overlayName, PathAddress.EMPTY_ADDRESS);
+        boolean isOverlayExists = AuthServerUtil.isOverlayExists(context, overlayName, PathAddress.EMPTY_ADDRESS);
         if (!isOverlayExists) {
             addOverlay(context, overlayAddress);
             if (!isHostController(context)) {
-                addDeploymentToOverlay(context, overlayAddress, AuthServerUtil.getDeploymentName(operation));
+                addDeploymentToOverlay(context, overlayAddress, deploymentName);
             }
         }
 
@@ -70,36 +87,42 @@ public abstract class AbstractAddOverlayHandler implements OperationStepHandler 
             addOverlayToServerGroups(context, overlayAddress, operation, overlayName);
         }
 
-        // There is no way to do an overwrite of content from here because it involves
-        // removing the overlay service in the runtime phase.  You have to remove
-        // the content in a seperate operation.
         if (isOverlayExists && isContentExists(context, overlayAddress, overlayPath)) {
-            throw new OperationFailedException(pathExistsMessage(overlayAddress, overlayPath));
+            if (isOverwrite) {
+                removeContent(context, overlayAddress, overlayPath);
+            } else {
+                throw new OperationFailedException(pathExistsMessage(overlayAddress, overlayPath));
+            }
         }
 
         addContent(context, overlayAddress, operation.get(BYTES_TO_UPLOAD.getName()).asBytes(), overlayPath);
 
-        context.restartRequired();
+        if (isRedeploy) AuthServerUtil.addStepToRedeployAuthServer(context, deploymentName);
+        if (!isRedeploy) context.restartRequired();
         context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER);
     }
 
+    static void removeContent(OperationContext context, PathAddress overlayAddress, String overlayPath) {
+        PathAddress contentAddress = overlayAddress.append("content", overlayPath);
+        ModelNode operation = Util.createRemoveOperation(contentAddress);
+        context.addStep(operation, getHandler(context, contentAddress, REMOVE), OperationContext.Stage.MODEL);
+    }
+
+    static boolean isRedeploy(OperationContext context, ModelNode operation) {
+        return isAuthServerEnabled(context) && getBooleanFromOperation(operation, REDEPLOY_SERVER);
+    }
+
     private boolean isHostController(OperationContext context) {
         return context.getProcessType() == ProcessType.HOST_CONTROLLER;
     }
 
     private String pathExistsMessage(PathAddress overlayAddress, String overlayPath) {
         PathAddress contentAddress = overlayAddress.append("content", overlayPath);
-        String msg = "Can not update overlay. ";
-        msg += "First remove the overlay with CLI using the following command with the content path in double quotes:  ";
-        msg += contentAddress.toCLIStyleString() + ":remove";
+        String msg = "Can not update overlay at " + contentAddress.toCLIStyleString();
+        msg += "  You may try your request again using the " + OVERWRITE.getName() + " attribute.";
         return msg;
     }
 
-    private boolean isOverlayExists(OperationContext context, String overlayName, PathAddress address) {
-        Resource resource = context.readResourceFromRoot(address);
-        return resource.getChildrenNames("deployment-overlay").contains(overlayName);
-    }
-
     private boolean isContentExists(OperationContext context, PathAddress overlayAddress, String overlayPath) {
         Resource resource = context.readResourceFromRoot(overlayAddress);
         return resource.getChildrenNames("content").contains(overlayPath);
@@ -124,7 +147,7 @@ public abstract class AbstractAddOverlayHandler implements OperationStepHandler 
             ModelNode serverGroupModel = context.readResourceFromRoot(address).getModel();
             if (serverGroupModel.get("profile").asString().equals(myProfile)) {
                 PathAddress serverGroupOverlayAddress = address.append(overlayAddress);
-                boolean isOverlayExists = isOverlayExists(context, overlayName, address);
+                boolean isOverlayExists = AuthServerUtil.isOverlayExists(context, overlayName, address);
                 if (!isOverlayExists) {
                     addOverlay(context, serverGroupOverlayAddress);
                     addDeploymentToOverlay(context, serverGroupOverlayAddress, AuthServerUtil.getDeploymentName(operation));
@@ -160,6 +183,23 @@ public abstract class AbstractAddOverlayHandler implements OperationStepHandler 
         context.addStep(operation, getHandler(context, address, ADD), OperationContext.Stage.MODEL);
     }
 
+    private static boolean isAuthServerEnabled(OperationContext context) {
+        boolean defaultValue = AuthServerDefinition.ENABLED.getDefaultValue().asBoolean();
+        ModelNode authServerModel = context.readResource(PathAddress.EMPTY_ADDRESS).getModel().clone();
+        String attrName = AuthServerDefinition.ENABLED.getName();
+        if (!authServerModel.get(attrName).isDefined()) return defaultValue;
+        return authServerModel.get(attrName).asBoolean();
+    }
+
+    private static boolean getBooleanFromOperation(ModelNode operation, SimpleAttributeDefinition definition) {
+        boolean defaultValue = definition.getDefaultValue().asBoolean();
+        if (!operation.get(definition.getName()).isDefined()) {
+            return defaultValue;
+        } else {
+            return operation.get(definition.getName()).asBoolean();
+        }
+    }
+
     // used for debugging
     private ModelNode scrub(ModelNode op) {
         ModelNode scrubbed = op.clone();
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
index f661891..e2c99ed 100644
--- 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
@@ -17,7 +17,6 @@
 
 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;
@@ -46,8 +45,12 @@ public class AddProviderHandler extends AbstractAddOverlayHandler {
     public static OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OP, AuthServerDefinition.rscDescriptionResolver)
             .addParameter(BYTES_TO_UPLOAD)
             .addParameter(UPLOADED_FILE_NAME)
+            .addParameter(REDEPLOY_SERVER)
+            .addParameter(OVERWRITE)
             .build();
 
+    private AddProviderHandler() {}
+    
     @Override
     String getOverlayPath(String fileName) {
         if (!fileName.toLowerCase().endsWith(".jar")) {
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
index ff43a6f..653d09a 100755
--- 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
@@ -95,6 +95,8 @@ public class AuthServerDefinition extends SimpleResourceDefinition {
         resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
         resourceRegistration.registerOperationHandler(AddProviderHandler.DEFINITION, AddProviderHandler.INSTANCE);
         resourceRegistration.registerOperationHandler(OverlayKeycloakServerJsonHandler.DEFINITION, OverlayKeycloakServerJsonHandler.INSTANCE);
+        resourceRegistration.registerOperationHandler(ListOverlaysHandler.DEFINITION, ListOverlaysHandler.INSTANCE);
+        resourceRegistration.registerOperationHandler(RemoveOverlayHandler.DEFINITION, RemoveOverlayHandler.INSTANCE);
     }
 
     @Override
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
index d4085c9..25b632a 100644
--- 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
@@ -31,6 +31,7 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ARC
 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.DEPLOYMENT_OVERLAY;
 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;
@@ -40,6 +41,7 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UND
 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.as.controller.registry.Resource;
 import org.jboss.dmr.ModelNode;
 import org.jboss.modules.Module;
 import org.jboss.modules.ModuleIdentifier;
@@ -108,7 +110,7 @@ public class AuthServerUtil {
     }
 
     void addStepToUploadAuthServer(OperationContext context, boolean isEnabled) throws OperationFailedException {
-        PathAddress deploymentAddress = deploymentAddress();
+        PathAddress deploymentAddress = deploymentAddress(deploymentName);
         ModelNode op = Util.createOperation(ADD, deploymentAddress);
         op.get(ENABLED).set(isEnabled);
         op.get(PERSISTENT).set(false); // prevents writing this deployment out to standalone.xml
@@ -137,26 +139,27 @@ public class AuthServerUtil {
         return contentItem;
     }
 
-    void addStepToRedeployAuthServer(OperationContext context) {
-        addDeploymentAction(context, REDEPLOY);
+    static void addStepToRedeployAuthServer(OperationContext context, String deploymentName) {
+        addDeploymentAction(context, REDEPLOY, deploymentName);
     }
 
-    void addStepToUndeployAuthServer(OperationContext context) {
-        addDeploymentAction(context, UNDEPLOY);
+    static void addStepToUndeployAuthServer(OperationContext context, String deploymentName) {
+        addDeploymentAction(context, UNDEPLOY, deploymentName);
     }
 
-    void addStepToDeployAuthServer(OperationContext context) {
-        addDeploymentAction(context, DEPLOY);
+    static void addStepToDeployAuthServer(OperationContext context, String deploymentName) {
+        addDeploymentAction(context, DEPLOY, deploymentName);
     }
 
-    private void addDeploymentAction(OperationContext context, String operation) {
-        PathAddress deploymentAddress = deploymentAddress();
+    private static void addDeploymentAction(OperationContext context, String operation, String deploymentName) {
+        if (!context.isNormalServer()) return;
+        PathAddress deploymentAddress = deploymentAddress(deploymentName);
         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() {
+    private static PathAddress deploymentAddress(String deploymentName) {
         return PathAddress.pathAddress(PathElement.pathElement(DEPLOYMENT, deploymentName));
     }
 
@@ -183,4 +186,17 @@ public class AuthServerUtil {
         return PathAddress.pathAddress(operation.get(ADDRESS));
     }
 
+    static PathAddress getOverlayAddress(String overlayName) {
+        return PathAddress.pathAddress(PathElement.pathElement(DEPLOYMENT_OVERLAY, overlayName));
+    }
+
+    static String getOverlayName(ModelNode operation) {
+        return AuthServerUtil.getAuthServerName(operation) + "-keycloak-overlay";
+    }
+
+    static boolean isOverlayExists(OperationContext context, String overlayName, PathAddress address) {
+        Resource resource = context.readResourceFromRoot(address);
+        return resource.getChildrenNames(DEPLOYMENT_OVERLAY).contains(overlayName);
+    }
+
 }
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
index 24decfc..48ffc32 100755
--- 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
@@ -50,23 +50,23 @@ public class AuthServerWriteAttributeHandler extends ModelOnlyWriteAttributeHand
             return;
         }
 
-        AuthServerUtil authServerUtil = new AuthServerUtil(operation);
         boolean isEnabled = isEnabled(model); // is server currently enabled?
+        String deploymentName = AuthServerUtil.getDeploymentName(operation);
 
         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);
+                AuthServerUtil.addStepToRedeployAuthServer(context, deploymentName);
             }
         }
 
         if (attributeName.equals(AuthServerDefinition.ENABLED.getName())) {
             if (!isEnabled) { // we are disabling
-                authServerUtil.addStepToUndeployAuthServer(context);
+                AuthServerUtil.addStepToUndeployAuthServer(context, deploymentName);
             } else { // we are enabling
-                authServerUtil.addStepToDeployAuthServer(context);
+                AuthServerUtil.addStepToDeployAuthServer(context, deploymentName);
             }
         }
 
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/ListOverlaysHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/ListOverlaysHandler.java
new file mode 100644
index 0000000..39c5225
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/ListOverlaysHandler.java
@@ -0,0 +1,76 @@
+/*
+ * 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.util.Set;
+import java.util.TreeSet;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationDefinition;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOYMENT_OVERLAY;
+import org.jboss.as.controller.registry.Resource;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+/**
+ * Operation to list all of the provider jars, theme jars, and keycloak-server.json that
+ * have been uploaded to the auth server.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class ListOverlaysHandler implements OperationStepHandler {
+    static final String LIST_OVERLAYS_OPERATION = "list-overlays";
+
+    static final OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(LIST_OVERLAYS_OPERATION, AuthServerDefinition.rscDescriptionResolver)
+            .setReadOnly()
+            .setRuntimeOnly()
+            .setReplyType(ModelType.LIST)
+            .setReplyValueType(ModelType.STRING)
+            .build();
+
+    static final OperationStepHandler INSTANCE = new ListOverlaysHandler();
+
+    private ListOverlaysHandler() {}
+
+    @Override
+    public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
+        final ModelNode result = context.getResult();
+        result.setEmptyList();
+
+        String overlayName = AuthServerUtil.getOverlayName(operation);
+        boolean isOverlayExists = AuthServerUtil.isOverlayExists(context, overlayName, PathAddress.EMPTY_ADDRESS);
+        if (isOverlayExists) {
+            Set<String> overlays = new TreeSet<String>(getOverlayNames(context, overlayName));
+            for (final String key : overlays) {
+                result.add(key);
+            }
+        }
+
+        context.stepCompleted();
+    }
+
+    private Set<String> getOverlayNames(OperationContext context, String overlayName) {
+        PathAddress overlayAddr = PathAddress.pathAddress(DEPLOYMENT_OVERLAY, overlayName);
+        Resource resource = context.readResourceFromRoot(overlayAddr);
+        return resource.getChildrenNames(CONTENT);
+    }
+}
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
index 485c37d..693ee45 100644
--- 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
@@ -33,8 +33,12 @@ public class OverlayKeycloakServerJsonHandler extends AbstractAddOverlayHandler 
 
     public static OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OP, AuthServerDefinition.rscDescriptionResolver)
             .addParameter(BYTES_TO_UPLOAD)
+            .addParameter(REDEPLOY_SERVER)
+            .addParameter(OVERWRITE)
             .build();
 
+    private OverlayKeycloakServerJsonHandler() {}
+    
     @Override
     String getOverlayPath(String fileName) {
         return "/WEB-INF/classes/META-INF/keycloak-server.json";
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/RemoveOverlayHandler.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/RemoveOverlayHandler.java
new file mode 100644
index 0000000..e2580ba
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/RemoveOverlayHandler.java
@@ -0,0 +1,76 @@
+/*
+ * 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.OperationContext;
+import org.jboss.as.controller.OperationDefinition;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathAddress;
+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 remove a provider jars, theme jars, or keycloak-server.json that
+ * has been uploaded to the auth server.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class RemoveOverlayHandler implements OperationStepHandler {
+    static final String REMOVE_OVERLAY_OPERATION = "remove-overlay";
+
+    protected static final SimpleAttributeDefinition OVERLAY_FILE_PATH =
+            new SimpleAttributeDefinitionBuilder("overlay-file-path", ModelType.STRING, false)
+            .setAllowExpression(true)
+            .setAllowNull(false)
+            .setDefaultValue(new ModelNode().set("/WEB-INF/lib/myprovider.jar"))
+            .build();
+
+    static final OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(REMOVE_OVERLAY_OPERATION, AuthServerDefinition.rscDescriptionResolver)
+            .addParameter(OVERLAY_FILE_PATH)
+            .addParameter(AbstractAddOverlayHandler.REDEPLOY_SERVER)
+            .build();
+
+    static final OperationStepHandler INSTANCE = new RemoveOverlayHandler();
+
+    private RemoveOverlayHandler() {}
+
+    @Override
+    public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
+        String overlayName = AuthServerUtil.getOverlayName(operation);
+        boolean isOverlayExists = AuthServerUtil.isOverlayExists(context, overlayName, PathAddress.EMPTY_ADDRESS);
+        String overlayPath = operation.get(OVERLAY_FILE_PATH.getName()).asString();
+        if (isOverlayExists) {
+            PathAddress overlayAddress = AuthServerUtil.getOverlayAddress(overlayName);
+            AbstractAddOverlayHandler.removeContent(context, overlayAddress, overlayPath);
+        } else {
+            context.setRollbackOnly();
+            throw new OperationFailedException("Overlay path " + overlayPath + " not found.");
+        }
+
+        boolean isRedeploy = AbstractAddOverlayHandler.isRedeploy(context, operation);
+        String deploymentName = AuthServerUtil.getDeploymentName(operation);
+        if (isRedeploy) AuthServerUtil.addStepToRedeployAuthServer(context, deploymentName);
+        if (!isRedeploy) context.restartRequired();
+
+        context.stepCompleted();
+    }
+}
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 3239f14..1756381 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
@@ -12,9 +12,16 @@ 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.add-provider.redeploy=Redeploy the auth server after adding the provider.  Ignored if auth server is disabled.
+keycloak.auth-server.add-provider.overwrite=Overwrite even if the uploaded-file-name already exists as an overlay.
+keycloak.auth-server.list-overlays=List the overlays uploaded for this auth server.
+keycloak.auth-server.remove-overlay=Remove a provider jar, theme jar, or keycloak-server.json that has been uploaded to the auth server.
+keycloak.auth-server.remove-overlay.overlay-file-path=The uploaded path and file name of the overlay to be removed.
+keycloak.auth-server.remove-overlay.redeploy=Redeploy the auth server after removing the overlay.
 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.update-server-config.redeploy=Redeploy the auth server after updating the server config.
+keycloak.auth-server.update-server-config.overwrite=Overwrite even if keycloak-server.json already exitss as an overlay.
 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.
 

pom.xml 7(+6 -1)

diff --git a/pom.xml b/pom.xml
index 0070920..ffeaa5e 100755
--- a/pom.xml
+++ b/pom.xml
@@ -36,7 +36,7 @@
         <slf4j.version>1.5.10</slf4j.version>
         <jboss.version>7.1.1.Final</jboss.version>
         <wildfly.version>8.1.0.Final</wildfly.version>
-        <wildfly.core.version>1.0.0.Alpha9</wildfly.core.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>
@@ -472,6 +472,11 @@
             </dependency>
             <dependency>
                 <groupId>org.wildfly.core</groupId>
+                <artifactId>wildfly-cli</artifactId>
+                <version>${wildfly.core.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.wildfly.core</groupId>
                 <artifactId>wildfly-core-feature-pack</artifactId>
                 <type>zip</type>
                 <version>${wildfly.core.version}</version>