keycloak-memoizeit

Changes

.gitignore 3(+2 -1)

pom.xml 5(+5 -0)

Details

.gitignore 3(+2 -1)

diff --git a/.gitignore b/.gitignore
index 319769b..44612eb 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/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 0bc0ec9..22d6bea 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
@@ -31,6 +31,7 @@
         <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"/>
diff --git a/integration/wildfly-subsystem/pom.xml b/integration/wildfly-subsystem/pom.xml
index d776e60..5247515 100755
--- a/integration/wildfly-subsystem/pom.xml
+++ b/integration/wildfly-subsystem/pom.xml
@@ -42,11 +42,9 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.8.1</version>
                 <configuration>
                     <redirectTestOutputToFile>false</redirectTestOutputToFile>
                     <enableAssertions>true</enableAssertions>
-                    <argLine>-Xmx512m</argLine>
                     <systemProperties>
                         <property>
                             <name>jboss.home</name>
@@ -56,9 +54,34 @@
                     <includes>
                         <include>**/*TestCase.java</include>
                     </includes>
-                    <forkMode>once</forkMode>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>compile</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-server</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>war</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/classes/deployments</outputDirectory>
+                                    <destFileName>auth-server.war</destFileName>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
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 0000000..62c738e
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerAddHandler.java
@@ -0,0 +1,88 @@
+/*
+ * 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.as.controller.ServiceVerificationHandler;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceController;
+
+import java.util.List;
+
+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);
+        }
+
+/*        String serverJsonAttrName = AuthServerDefinition.KEYCLOAK_SERVER_JSON.getName();
+        ModelNode keycloakServerJson = model.get(serverJsonAttrName);
+        if (!keycloakServerJson.isDefined()) {
+            model.get(serverJsonAttrName).set(AuthServerUtil.getDefaultAuthServerJson());
+        } */
+
+        System.out.println("**************************");
+        System.out.println("operation");
+        System.out.println(operation.toString());
+        System.out.println("**************************");
+        System.out.println("model");
+        System.out.println(model.toString());
+        System.out.println("**************************");
+
+        if (!requiresRuntime(context)) return; // not sure I really need this
+
+        ModelNode isEnabled = model.get("enabled");
+        if (!isEnabled.isDefined() || isEnabled.asBoolean()) {
+            String deploymentName = AuthServerUtil.addStepToStartAuthServer(context, operation);
+            //String json = model.get(serverJsonAttrName).asString();
+            ModelNode webContextNode = model.get(AuthServerDefinition.WEB_CONTEXT.getName());
+            if (!webContextNode.isDefined()) webContextNode = AuthServerDefinition.WEB_CONTEXT.getDefaultValue();
+            String webContext = webContextNode.asString();
+            KeycloakAdapterConfigService.INSTANCE.addServerDeployment(deploymentName, json, webContext);
+        }
+    }
+
+    @Override
+    protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
+    }
+}
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 0000000..685a910
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerDefinition.java
@@ -0,0 +1,134 @@
+/*
+ * 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.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(true))
+            .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 SimpleAttributeDefinition KEYCLOAK_SERVER_JSON =
+            new SimpleAttributeDefinitionBuilder("keycloak-server-json", ModelType.STRING, true)
+            .setXmlName("keycloak-server-json")
+            .setAllowExpression(true)
+            .setRestartAllServices()
+            .build(); */
+
+    public static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
+    static {
+        ALL_ATTRIBUTES.add(ENABLED);
+        ALL_ATTRIBUTES.add(WEB_CONTEXT);
+        //ALL_ATTRIBUTES.add(KEYCLOAK_SERVER_JSON);
+    }
+
+    private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
+    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),
+                KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
+                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);
+    }
+
+    @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 0000000..7f92ab2
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerRemoveHandler.java
@@ -0,0 +1,54 @@
+/*
+ * 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.operations.common.Util;
+import org.jboss.dmr.ModelNode;
+import org.keycloak.subsystem.extension.KeycloakAdapterConfigService;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
+
+/**
+ * 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 performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+        //KeycloakAdapterConfigService.INSTANCE.removeAuthServer()
+        System.out.println("*** performRuntime ** operation");
+        System.out.println(operation.toString());
+        System.out.println("*** performRuntime ** model");
+        System.out.println(model.toString());
+        String deploymentName = Util.getNameFromAddress(operation.get(ADDRESS));
+        System.out.println("*** authServerName=" + deploymentName);
+        if (!deploymentName.toLowerCase().endsWith(".war")) {
+            deploymentName += ".war";
+        }
+        KeycloakAdapterConfigService.INSTANCE.removeServerDeployment(deploymentName);
+    }
+}
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 0000000..a7a4fd7
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerUtil.java
@@ -0,0 +1,168 @@
+/*
+ * 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.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+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.CONTENT;
+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.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;
+import org.jboss.modules.Resource;
+import org.jboss.modules.filter.PathFilter;
+
+/**
+ *
+ * @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 static URL authServerUrl = null;
+
+    private static String defaultAuthServerJson = "";
+
+    static String getDefaultAuthServerJson() {
+        if (authServerUrl == null) getWarUrl();
+        return defaultAuthServerJson;
+    }
+
+    // Can return the URL, null, or throw IllegalStateException
+    // This also finds the defaultAuthServerJson and sets the instance var for it.
+    private static URL getWarUrl() throws IllegalStateException {
+        if (authServerUrl != null) { // only need to find this once
+            return authServerUrl;
+        }
+
+        Module module;
+        try {
+            module = Module.getModuleFromCallerModuleLoader(KEYCLOAK_AUTH_SERVER);
+        } catch (ModuleLoadException e) {
+            throw new IllegalStateException("Keycloak Auth Server not installed as a module.", e);
+        }
+
+        URL warUrl = null;
+        try {
+            java.util.Iterator<org.jboss.modules.Resource> rscIterator = module.iterateResources(new PathFilter() {
+                @Override
+                public boolean accept(String string) {
+                    return true;
+                }
+            });
+
+            // There should be only one war resource, the auth server
+            while (rscIterator.hasNext()) {
+                Resource rsc = rscIterator.next();
+                System.out.println("rsc.getName()=" + rsc.getName());
+                URL url = rsc.getURL();
+                if (url.toExternalForm().toLowerCase().endsWith(".war")) {
+                    warUrl = url;
+                    setDefaultAuthServerJson(rsc);
+                    break;
+                }
+            }
+        } catch (ModuleLoadException e) {
+            throw new IllegalStateException(e);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+
+        authServerUrl = warUrl;
+        System.out.println("&&&&& authServerUrl=" + authServerUrl);
+        return authServerUrl;
+    }
+
+    // return deploymentName this will be started under
+    static String addStepToStartAuthServer(OperationContext context, ModelNode operation) throws OperationFailedException {
+
+        PathAddress authServerAddr = PathAddress.pathAddress(operation.get(ADDRESS));
+        String deploymentName = authServerAddr.getElement(1).getValue();
+        if (!deploymentName.toLowerCase().endsWith(".war")) {
+            deploymentName += ".war";
+        }
+
+        PathAddress deploymentAddress = PathAddress.pathAddress(PathElement.pathElement(DEPLOYMENT, deploymentName));
+        ModelNode op = Util.createOperation(ADD, deploymentAddress);
+        op.get(ENABLED).set(true);
+        op.get(PERSISTENT).set(false); // prevents writing this deployment out to standalone.xml
+
+        URL warUrl = null;
+        try {
+            warUrl = getWarUrl();
+        } catch (IllegalStateException e) {
+            throw new OperationFailedException(e);
+        }
+
+        if (warUrl == null) {
+            throw new OperationFailedException("Keycloak Auth Server WAR not found in keycloak-auth-server module");
+        }
+
+        String urlString = warUrl.toExternalForm();
+        System.out.println(warUrl);
+        ModelNode contentItem = new ModelNode();
+        contentItem.get(URL).set(urlString);
+        op.get(CONTENT).add(contentItem);
+        System.out.println("****** operation ************");
+        System.out.println(op.toString());
+        ImmutableManagementResourceRegistration rootResourceRegistration = context.getRootResourceRegistration();
+        OperationStepHandler handler = rootResourceRegistration.getOperationHandler(deploymentAddress, ADD);
+        context.addStep(op, handler, OperationContext.Stage.MODEL);
+
+        return deploymentName;
+    }
+
+    private static void setDefaultAuthServerJson(Resource rsc) throws IOException {
+        JarInputStream jarStream = null;
+        try {
+            jarStream = new JarInputStream(rsc.openStream());
+            JarEntry je;
+            while ((je = jarStream.getNextJarEntry()) != null) {
+                if (!je.getName().equals("WEB-INF/classes/META-INF/keycloak-server.json")) continue;
+
+                int len = 0;
+                byte[] buffer = new byte[1024];
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                while ((len = jarStream.read(buffer)) != -1) {
+                    baos.write(buffer, 0, len);
+                }
+
+                defaultAuthServerJson = baos.toString();
+                return;
+            }
+        } finally {
+            jarStream.close();
+        }
+    }
+}
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 0000000..b7e53ea
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/authserver/AuthServerWriteAttributeHandler.java
@@ -0,0 +1,41 @@
+/*
+ * 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.ReloadRequiredWriteAttributeHandler;
+
+/**
+ * Update an attribute on an Auth Server.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
+ */
+public class AuthServerWriteAttributeHandler extends ReloadRequiredWriteAttributeHandler {
+
+    public AuthServerWriteAttributeHandler(List<SimpleAttributeDefinition> definitions) {
+        this(definitions.toArray(new AttributeDefinition[definitions.size()]));
+    }
+
+    public AuthServerWriteAttributeHandler(AttributeDefinition... definitions) {
+        super(definitions);
+    }
+
+}
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 55e47eb..cc5b73c 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,7 @@ import org.keycloak.subsystem.logging.KeycloakLogger;
 
 import java.util.ArrayList;
 import java.util.List;
+import org.jboss.as.ee.component.EEModuleDescription;
 
 /**
  * Pass authentication data (keycloak.json) as a servlet context param so it can be read by the KeycloakServletExtension.
@@ -45,9 +46,9 @@ 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) {
@@ -73,6 +74,7 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
         String deploymentName = deploymentUnit.getName();
+        System.out.println(">>>>> deploymentName=" + deploymentName);
         KeycloakAdapterConfigService service = KeycloakAdapterConfigService.find(phaseContext.getServiceRegistry());
         //log.info("********* CHECK KEYCLOAK DEPLOYMENT: " + deploymentName);
         if (service.isKeycloakDeployment(deploymentName)) {
@@ -99,6 +101,15 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
             webMetaData = new JBossWebMetaData();
             warMetaData.setMergedJBossWebMetaData(webMetaData);
         }
+
+        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);
+            return;
+        }
+
         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 eb820fc..ee91ef3 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
@@ -53,6 +53,11 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
     private Map<String, ModelNode> realms = new HashMap<String, ModelNode>();
     private Map<String, ModelNode> deployments = new HashMap<String, ModelNode>();
 
+    // key=server deployment name; value=json
+    private Map<String, String> serverDeployments = new HashMap<String, String>();
+    // key=server deployment name; value=web-context
+    private Map<String, String> webContexts = new HashMap<String, String>();
+
     private KeycloakAdapterConfigService() {
 
     }
@@ -72,6 +77,24 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
         return this;
     }
 
+    public void addServerDeployment(String deploymentName, String json, String webContext) {
+        this.serverDeployments.put(deploymentName, json);
+        this.webContexts.put(deploymentName, webContext);
+    }
+
+    public String getWebContext(String deploymentName) {
+        return webContexts.get(deploymentName);
+    }
+
+    public void removeServerDeployment(String deploymentName) {
+        this.serverDeployments.remove(deploymentName);
+        this.webContexts.remove(deploymentName);
+    }
+
+    public boolean isWebContextUsed(String webContext) {
+        return webContexts.containsValue(webContext);
+    }
+
     public void addRealm(ModelNode operation, ModelNode model) {
         this.realms.put(realmNameFromOp(operation), model.clone());
     }
@@ -170,6 +193,10 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
     }
 
     public String getJSON(String deploymentName) {
+        if (serverDeployments.containsKey(deploymentName)) {
+            return serverDeployments.get(deploymentName);
+        }
+
         ModelNode deployment = this.deployments.get(deploymentName);
         String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
         ModelNode realm = this.realms.get(realmName);
@@ -196,7 +223,11 @@ public final class KeycloakAdapterConfigService implements Service<KeycloakAdapt
     public boolean isKeycloakDeployment(String deploymentName) {
         //log.info("********* CHECK KEYCLOAK DEPLOYMENT: deployments.size()" + deployments.size());
 
-        return this.deployments.containsKey(deploymentName);
+        return this.serverDeployments.containsKey(deploymentName) || this.deployments.containsKey(deploymentName);
+    }
+
+    public boolean isKeycloakServerDeployment(String deploymentName) {
+        return this.serverDeployments.containsKey(deploymentName);
     }
 
     static KeycloakAdapterConfigService find(ServiceRegistry registry) {
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
index 1283a2f..941236b 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
@@ -17,6 +17,10 @@
 
 package org.keycloak.subsystem.extension;
 
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import org.jboss.as.server.deployment.Attachments;
 import org.jboss.as.server.deployment.DeploymentPhaseContext;
 import org.jboss.as.server.deployment.DeploymentUnit;
@@ -24,9 +28,14 @@ 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.as.server.deployment.module.MountHandle;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.as.server.deployment.module.TempFileProviderService;
 import org.jboss.modules.Module;
 import org.jboss.modules.ModuleIdentifier;
 import org.jboss.modules.ModuleLoader;
+import org.jboss.vfs.VFS;
+import org.jboss.vfs.VirtualFile;
 
 /**
  *
@@ -44,10 +53,39 @@ public class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
     @Override
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
-        addModules(deploymentUnit);
+
+        String deploymentName = deploymentUnit.getName();
+        KeycloakAdapterConfigService service = KeycloakAdapterConfigService.find(phaseContext.getServiceRegistry());
+
+        if (service.isKeycloakDeployment(deploymentName)) {
+            addModules(deploymentUnit);
+        }
+
+        for (ResourceRoot root : deploymentUnit.getAttachment(Attachments.RESOURCE_ROOTS)) {
+            System.out.println("*** resource root=" + root);
+        }
+
+
+    }
+
+    private void addProvider(DeploymentUnit deploymentUnit) throws IOException, URISyntaxException {
+        System.out.println("#2");
+        deploymentUnit.addToAttachmentList(Attachments.RESOURCE_ROOTS, providerRoot());
+        System.out.println("#4");
+    }
+
+    private ResourceRoot providerRoot() throws IOException, URISyntaxException {
+        System.out.println("#3");
+        URI uri = new URI("file:/C:/GitHub/keycloak-temp/keycloak-appliance-dist-all-1.1.0-Alpha1-SNAPSHOT/keycloak/modules/system/layers/base/org/keycloak/keycloak-auth-server/main/./federation-properties-example.jar");
+        VirtualFile archive = VFS.getChild(uri);
+        Closeable closeable = VFS.mountZip(archive.getPhysicalFile(), archive, TempFileProviderService.provider());
+        return new ResourceRoot(archive.getName(), archive, new MountHandle(closeable));
     }
 
     private void addModules(DeploymentUnit deploymentUnit) {
+        System.out.println("**************************");
+        System.out.println("* Adding Keycloak dependencies to " + deploymentUnit.getName());
+        System.out.println("**************************");
         final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
         final ModuleLoader moduleLoader = Module.getBootModuleLoader();
 
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakExtension.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakExtension.java
index 32837aa..1816ad2 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakExtension.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakExtension.java
@@ -16,6 +16,7 @@
  */
 package org.keycloak.subsystem.extension;
 
+import org.keycloak.subsystem.extension.authserver.AuthServerDefinition;
 import org.jboss.as.controller.Extension;
 import org.jboss.as.controller.ExtensionContext;
 import org.jboss.as.controller.PathElement;
@@ -46,11 +47,12 @@ public class KeycloakExtension implements Extension {
     private static final int MANAGEMENT_API_MICRO_VERSION = 0;
     protected 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();
     static final RealmDefinition REALM_DEFINITION = new RealmDefinition();
     static final SecureDeploymentDefinition SECURE_DEPLOYMENT_DEFINITION = new SecureDeploymentDefinition();
     static final CredentialDefinition CREDENTIAL_DEFINITION = new CredentialDefinition();
 
-    static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
+    public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
         StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
         for (String kp : keyPrefix) {
             prefix.append('.').append(kp);
@@ -76,7 +78,8 @@ public class KeycloakExtension implements Extension {
                 MANAGEMENT_API_MINOR_VERSION, MANAGEMENT_API_MICRO_VERSION);
 
         ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
-        ManagementResourceRegistration realmRegistration = registration.registerSubModel(REALM_DEFINITION);
+        registration.registerSubModel(AUTH_SERVER_DEFINITION);
+        registration.registerSubModel(REALM_DEFINITION);
         ManagementResourceRegistration secureDeploymentRegistration = registration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION);
         secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
 
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakStructureProcessor.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakStructureProcessor.java
new file mode 100755
index 0000000..9f1aa5d
--- /dev/null
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakStructureProcessor.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import java.io.Closeable;
+import java.io.IOException;
+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.as.server.deployment.module.MountHandle;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.as.server.deployment.module.TempFileProviderService;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleIdentifier;
+import org.jboss.modules.ModuleLoader;
+import org.jboss.vfs.VFS;
+import org.jboss.vfs.VirtualFile;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+public class KeycloakStructureProcessor implements DeploymentUnitProcessor {
+
+    @Override
+    public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+        final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+
+        String deploymentName = deploymentUnit.getName();
+        KeycloakAdapterConfigService service = KeycloakAdapterConfigService.find(phaseContext.getServiceRegistry());
+
+        System.out.println("#0");
+        if (service.isKeycloakServerDeployment(deploymentName)) {
+            try {
+                System.out.println("#1");
+                addProvider(deploymentUnit);
+            } catch (IOException e) {
+                throw new DeploymentUnitProcessingException(e);
+            }
+        }
+    }
+
+    private void addProvider(DeploymentUnit deploymentUnit) throws IOException {
+        System.out.println("#2");
+        deploymentUnit.addToAttachmentList(Attachments.RESOURCE_ROOTS, providerRoot());
+        System.out.println("#4");
+    }
+
+    private ResourceRoot providerRoot() throws IOException {
+        System.out.println("#3");
+        VirtualFile archive = VFS.getChild("C:\\GitHub\\keycloak-temp\\keycloak-appliance-dist-all-1.1.0-Alpha1-SNAPSHOT\\keycloak\\modules\\system\\layers\\base\\org\\keycloak\\keycloak-auth-server\\main\\federation-properties-example.jar");
+        Closeable closeable = VFS.mountZip(archive.getPhysicalFile(), archive, TempFileProviderService.provider());
+        return new ResourceRoot(archive.getName(), archive, new MountHandle(closeable));
+    }
+
+    @Override
+    public void undeploy(DeploymentUnit du) {
+
+    }
+
+}
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemAdd.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemAdd.java
index c8f2e1d..8197658 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemAdd.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemAdd.java
@@ -16,6 +16,7 @@
  */
 package org.keycloak.subsystem.extension;
 
+
 import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
 import org.jboss.as.controller.OperationContext;
 import org.jboss.as.controller.OperationFailedException;
@@ -27,6 +28,7 @@ import org.jboss.dmr.ModelNode;
 import org.jboss.msc.service.ServiceController;
 
 import java.util.List;
+import org.jboss.as.controller.registry.Resource;
 
 /**
  * The Keycloak subsystem add update handler.
@@ -38,8 +40,10 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
     static final KeycloakSubsystemAdd INSTANCE = new KeycloakSubsystemAdd();
 
     @Override
-    protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
-        model.setEmptyObject();
+    protected void populateModel(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException {
+        resource.getModel().setEmptyObject();
+
+
     }
 
     @Override
@@ -47,11 +51,12 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
         context.addStep(new AbstractDeploymentChainStep() {
             @Override
             protected void execute(DeploymentProcessorTarget processorTarget) {
+                processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME, Phase.STRUCTURE, 0, new KeycloakStructureProcessor());
                 processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, 0, new KeycloakDependencyProcessor());
                 processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME,
-                                                       KeycloakAdapterConfigDeploymentProcessor.PHASE,
-                                                       KeycloakAdapterConfigDeploymentProcessor.PRIORITY,
-                                                       new KeycloakAdapterConfigDeploymentProcessor());
+                        KeycloakAdapterConfigDeploymentProcessor.PHASE,
+                        KeycloakAdapterConfigDeploymentProcessor.PRIORITY,
+                        new KeycloakAdapterConfigDeploymentProcessor());
             }
         }, OperationContext.Stage.RUNTIME);
     }
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemParser.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemParser.java
index 71b3e45..3cb5fad 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemParser.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakSubsystemParser.java
@@ -16,6 +16,7 @@
  */
 package org.keycloak.subsystem.extension;
 
+import org.keycloak.subsystem.extension.authserver.AuthServerDefinition;
 import org.jboss.as.controller.AttributeDefinition;
 import org.jboss.as.controller.PathAddress;
 import org.jboss.as.controller.PathElement;
@@ -58,6 +59,8 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
             }
             else if (reader.getLocalName().equals(SecureDeploymentDefinition.TAG_NAME)) {
                 readDeployment(reader, list);
+            } else if (reader.getLocalName().equals(AuthServerDefinition.TAG_NAME)) {
+                readAuthServer(reader, list);
             }
         }
     }
@@ -67,6 +70,24 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
         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);
+    }
+
     private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
         String realmName = readNameAttribute(reader);
         ModelNode addRealm = new ModelNode();
@@ -157,11 +178,28 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
     @Override
     public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
         context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
+        writeAuthServers(writer, context);
         writeRealms(writer, context);
         writeSecureDeployments(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();
+        }
+    }
+
     private void writeRealms(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
         if (!context.getModelNode().get(RealmDefinition.TAG_NAME).isDefined()) {
             return;
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 524ae4d..533234b 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,18 @@
 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.enabled=Enable or disable the Auth Server.
+keycloak.auth-server.keycloak-server-json=Externalized version of keycloak-server.json
+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.

pom.xml 5(+5 -0)

diff --git a/pom.xml b/pom.xml
index f6164ff..80d627c 100755
--- a/pom.xml
+++ b/pom.xml
@@ -487,6 +487,11 @@
             <plugins>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <version>2.8</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-surefire-plugin</artifactId>
                     <version>2.16</version>
                     <configuration>
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 a2d5a60..89e5d40 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -41,6 +41,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
+import org.keycloak.adapters.AdapterConstants;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -57,7 +58,7 @@ public class KeycloakApplication extends Application {
     protected String contextPath;
 
     public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
-        loadConfig();
+        loadConfig(context);
 
         this.sessionFactory = createSessionFactory();
 
@@ -102,6 +103,26 @@ public class KeycloakApplication extends Application {
         return uriInfo.getBaseUriBuilder().replacePath(getContextPath()).build();
     }
 
+    private static void loadConfig(ServletContext context) {
+        String json = context.getInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME);
+        if (json == null) {
+            loadConfig(); // from file
+        } else {
+            loadConfig(json); // from ServletContext/Keycloak subsystem
+        }
+    }
+
+    private static void loadConfig(String json) {
+        try {
+            JsonNode node = new ObjectMapper().readTree(json);
+            Config.init(new JsonConfigProvider(node));
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to load config", e);
+        }
+
+        log.info("Loaded config from Keycloak subsystem");
+    }
+
     public static void loadConfig() {
         try {
             URL config = null;