diff --git a/.gitignore b/.gitignore
index 319769bf2a3..44612eb8b4a 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 0bc0ec9f78a..22d6beacb8f 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 @@
+
diff --git a/integration/wildfly-subsystem/pom.xml b/integration/wildfly-subsystem/pom.xml
index d776e6006a9..52475151c9d 100755
--- a/integration/wildfly-subsystem/pom.xml
+++ b/integration/wildfly-subsystem/pom.xml
@@ -42,11 +42,9 @@
org.apache.maven.plugins
maven-surefire-plugin
- 2.8.1
false
true
- -Xmx512m
jboss.home
@@ -56,9 +54,34 @@
**/*TestCase.java
- once
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy
+ compile
+
+ copy
+
+
+
+
+ org.keycloak
+ keycloak-server
+ ${project.version}
+ war
+ true
+ ${project.build.directory}/classes/deployments
+ auth-server.war
+
+
+
+
+
+
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 55e47eba7fd..cc5b73c5da4 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 eb820fcff85..ee91ef3152b 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 realms = new HashMap();
private Map deployments = new HashMap();
+ // key=server deployment name; value=json
+ private Map serverDeployments = new HashMap();
+ // key=server deployment name; value=web-context
+ private Map webContexts = new HashMap();
+
private KeycloakAdapterConfigService() {
}
@@ -72,6 +77,24 @@ public final class KeycloakAdapterConfigService implements Service list) throws XMLStreamException {
+ String authServerName = readNameAttribute(reader);
+ ModelNode addAuthServer = new ModelNode();
+ addAuthServer.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
+ PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
+ PathElement.pathElement(AuthServerDefinition.TAG_NAME, authServerName));
+ addAuthServer.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ SimpleAttributeDefinition def = AuthServerDefinition.lookup(tagName);
+ if (def == null) throw new XMLStreamException("Unknown auth-server tag " + tagName);
+ def.parseAndSetParameter(reader.getElementText(), addAuthServer, reader);
+ }
+
+ list.add(addAuthServer);
+ }
+
private void readRealm(XMLExtendedStreamReader reader, List list) throws XMLStreamException {
String realmName = readNameAttribute(reader);
ModelNode addRealm = new ModelNode();
@@ -157,11 +178,28 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader> 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 00000000000..685a9103552
--- /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 ALL_ATTRIBUTES = new ArrayList();
+ static {
+ ALL_ATTRIBUTES.add(ENABLED);
+ ALL_ATTRIBUTES.add(WEB_CONTEXT);
+ //ALL_ATTRIBUTES.add(KEYCLOAK_SERVER_JSON);
+ }
+
+ private static final Map DEFINITION_LOOKUP = new HashMap();
+ static {
+ for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
+ DEFINITION_LOOKUP.put(def.getXmlName(), def);
+ }
+ }
+
+ private static AuthServerWriteAttributeHandler attrHandler = new AuthServerWriteAttributeHandler(ALL_ATTRIBUTES);
+
+ public AuthServerDefinition() {
+ super(PathElement.pathElement(TAG_NAME),
+ 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 00000000000..7f92ab2ae8b
--- /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 00000000000..a7a4fd798d1
--- /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 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 00000000000..b7e53ea7534
--- /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 definitions) {
+ this(definitions.toArray(new AttributeDefinition[definitions.size()]));
+ }
+
+ public AuthServerWriteAttributeHandler(AttributeDefinition... definitions) {
+ super(definitions);
+ }
+
+}
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 524ae4d60c7..533234b85d4 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.
diff --git a/pom.xml b/pom.xml
index f6164ff8280..80d627c49a0 100755
--- a/pom.xml
+++ b/pom.xml
@@ -485,6 +485,11 @@
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.8
+
org.apache.maven.plugins
maven-surefire-plugin
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 a2d5a60d297..89e5d40d7c7 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 Bill Burke
@@ -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;