KEYCLOAK-274 Create Keycloak subsystem
This commit is contained in:
parent
41d631d20e
commit
c81a08385f
31 changed files with 2454 additions and 5 deletions
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ JBoss, Home of Professional Open Source.
|
||||||
|
~ Copyright 2010, Red Hat, Inc., and individual contributors
|
||||||
|
~ as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
~ distribution for a full listing of individual contributors.
|
||||||
|
~
|
||||||
|
~ This is free software; you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU Lesser General Public License as
|
||||||
|
~ published by the Free Software Foundation; either version 2.1 of
|
||||||
|
~ the License, or (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This software is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
~ Lesser General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Lesser General Public
|
||||||
|
~ License along with this software; if not, write to the Free
|
||||||
|
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-subsystem">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="org.jboss.staxmapper"/>
|
||||||
|
<module name="org.jboss.as.controller"/>
|
||||||
|
<module name="org.jboss.as.server"/>
|
||||||
|
<module name="org.jboss.modules"/>
|
||||||
|
<module name="org.jboss.msc"/>
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="org.jboss.vfs"/>
|
||||||
|
<module name="org.jboss.as.web-common"/>
|
||||||
|
<module name="org.jboss.metadata"/>
|
||||||
|
</dependencies>
|
||||||
|
</module>
|
|
@ -11,6 +11,7 @@ import io.undertow.servlet.api.AuthMethodConfig;
|
||||||
import io.undertow.servlet.api.DeploymentInfo;
|
import io.undertow.servlet.api.DeploymentInfo;
|
||||||
import io.undertow.servlet.api.LoginConfig;
|
import io.undertow.servlet.api.LoginConfig;
|
||||||
import io.undertow.servlet.api.ServletSessionConfig;
|
import io.undertow.servlet.api.ServletSessionConfig;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.config.RealmConfiguration;
|
import org.keycloak.adapters.config.RealmConfiguration;
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
|
@ -25,6 +26,11 @@ import java.util.Map;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class KeycloakServletExtension implements ServletExtension {
|
public class KeycloakServletExtension implements ServletExtension {
|
||||||
|
// This param name is defined again in Keycloak Subsystem class
|
||||||
|
// org.keycloak.subsystem.extensionKeycloakAdapterConfigDeploymentProcessor. We have this value in
|
||||||
|
// two places to avoid dependency between Keycloak Subsystem and Keyclaok Undertow Integration.
|
||||||
|
public static final String AUTH_DATA_PARAM_NAME = "org.keycloak.json.adapterConfig";
|
||||||
|
|
||||||
protected Logger log = Logger.getLogger(KeycloakServletExtension.class);
|
protected Logger log = Logger.getLogger(KeycloakServletExtension.class);
|
||||||
|
|
||||||
// todo when this DeploymentInfo method of the same name is fixed.
|
// todo when this DeploymentInfo method of the same name is fixed.
|
||||||
|
@ -40,6 +46,13 @@ public class KeycloakServletExtension implements ServletExtension {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getJSONFromServletContext(ServletContext servletContext) {
|
||||||
|
String json = servletContext.getInitParameter(AUTH_DATA_PARAM_NAME);
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ByteArrayInputStream(json.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) {
|
public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) {
|
||||||
|
@ -49,7 +62,10 @@ public class KeycloakServletExtension implements ServletExtension {
|
||||||
}
|
}
|
||||||
log.info("KeycloakServletException initialization");
|
log.info("KeycloakServletException initialization");
|
||||||
InputStream is = servletContext.getResourceAsStream("/WEB-INF/keycloak.json");
|
InputStream is = servletContext.getResourceAsStream("/WEB-INF/keycloak.json");
|
||||||
if (is == null) throw new RuntimeException("Unable to find /WEB-INF/keycloak.json configuration file");
|
if (is == null) {
|
||||||
|
is = getJSONFromServletContext(servletContext);
|
||||||
|
}
|
||||||
|
if (is == null) throw new RuntimeException("Unable to find realm config in /WEB-INF/keycloak.json or in keycloak subsystem.");
|
||||||
RealmConfigurationLoader loader = new RealmConfigurationLoader(is);
|
RealmConfigurationLoader loader = new RealmConfigurationLoader(is);
|
||||||
loader.init(true);
|
loader.init(true);
|
||||||
AdapterConfig keycloakConfig = loader.getAdapterConfig();
|
AdapterConfig keycloakConfig = loader.getAdapterConfig();
|
||||||
|
|
34
pom.xml
34
pom.xml
|
@ -18,6 +18,7 @@
|
||||||
<picketlink.version>2.5.0.Beta6</picketlink.version>
|
<picketlink.version>2.5.0.Beta6</picketlink.version>
|
||||||
<mongo.driver.version>2.11.2</mongo.driver.version>
|
<mongo.driver.version>2.11.2</mongo.driver.version>
|
||||||
<jboss.logging.version>3.1.1.GA</jboss.logging.version>
|
<jboss.logging.version>3.1.1.GA</jboss.logging.version>
|
||||||
|
<jboss-logging-tools.version>1.2.0.Beta1</jboss-logging-tools.version>
|
||||||
<hibernate.javax.persistence.version>1.0.1.Final</hibernate.javax.persistence.version>
|
<hibernate.javax.persistence.version>1.0.1.Final</hibernate.javax.persistence.version>
|
||||||
<hibernate.entitymanager.version>4.0.1.Final</hibernate.entitymanager.version>
|
<hibernate.entitymanager.version>4.0.1.Final</hibernate.entitymanager.version>
|
||||||
<h2.version>1.3.161</h2.version>
|
<h2.version>1.3.161</h2.version>
|
||||||
|
@ -87,6 +88,7 @@
|
||||||
<module>examples</module>
|
<module>examples</module>
|
||||||
<module>testsuite</module>
|
<module>testsuite</module>
|
||||||
<module>server</module>
|
<module>server</module>
|
||||||
|
<module>subsystem</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
@ -340,6 +342,38 @@
|
||||||
<version>${keycloak.apache.httpcomponents.version}</version>
|
<version>${keycloak.apache.httpcomponents.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
-->
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-controller</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-server</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-ee</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-subsystem-test</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-undertow</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging-processor</artifactId>
|
||||||
|
<version>${jboss-logging-tools.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
|
115
subsystem/pom.xml
Normal file
115
subsystem/pom.xml
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2013 JBoss Inc
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<version>1.0-alpha-2-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-subsystem</artifactId>
|
||||||
|
<version>1.0-alpha-2-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<name>Keycloak Subsystem</name>
|
||||||
|
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<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>
|
||||||
|
<value>${jboss.home}</value>
|
||||||
|
</property>
|
||||||
|
</systemProperties>
|
||||||
|
<includes>
|
||||||
|
<include>**/*TestCase.java</include>
|
||||||
|
</includes>
|
||||||
|
<forkMode>once</forkMode>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-controller</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-ee</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-undertow</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging-annotations</artifactId>
|
||||||
|
<version>${jboss-logging-tools.version}</version>
|
||||||
|
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
||||||
|
projects that depend on this project.-->
|
||||||
|
<scope>provided</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging-processor</artifactId>
|
||||||
|
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
||||||
|
projects that depend on this project.-->
|
||||||
|
<scope>provided</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-subsystem-test</artifactId>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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.util.List;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a credential to a deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class CredentialAddHandler extends AbstractAddStepHandler {
|
||||||
|
|
||||||
|
public CredentialAddHandler(AttributeDefinition... attributes) {
|
||||||
|
super(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.addCredential(operation, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.ModelOnlyWriteAttributeHandler;
|
||||||
|
import org.jboss.as.controller.PathElement;
|
||||||
|
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.operations.validation.StringLengthValidator;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
import org.jboss.dmr.ModelType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes and operations for a credential.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class CredentialDefinition extends SimpleResourceDefinition {
|
||||||
|
|
||||||
|
public static final String TAG_NAME = "credential";
|
||||||
|
|
||||||
|
protected static final AttributeDefinition VALUE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("value", ModelType.STRING, false)
|
||||||
|
.setXmlName("value")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public CredentialDefinition() {
|
||||||
|
super(PathElement.pathElement(TAG_NAME),
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
|
||||||
|
new CredentialAddHandler(VALUE),
|
||||||
|
CredentialRemoveHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerOperations(resourceRegistration);
|
||||||
|
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerAttributes(resourceRegistration);
|
||||||
|
resourceRegistration.registerReadWriteAttribute(VALUE, null, new CredentialReadWriteAttributeHandler());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* 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 org.jboss.as.controller.AbstractWriteAttributeHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a credential value.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class CredentialReadWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode resolvedValue, ModelNode currentValue, AbstractWriteAttributeHandler.HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
|
||||||
|
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.updateCredential(operation, attributeName, resolvedValue);
|
||||||
|
|
||||||
|
hh.setHandback(ckService);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
|
||||||
|
ckService.updateCredential(operation, attributeName, valueToRestore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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 org.jboss.as.controller.AbstractRemoveStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a credential from a deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class CredentialRemoveHandler extends AbstractRemoveStepHandler {
|
||||||
|
|
||||||
|
public static CredentialRemoveHandler INSTANCE = new CredentialRemoveHandler();
|
||||||
|
|
||||||
|
private CredentialRemoveHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.removeCredential(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* 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.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
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.Phase;
|
||||||
|
import org.jboss.as.web.common.WarMetaData;
|
||||||
|
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
|
||||||
|
import org.jboss.metadata.web.jboss.JBossWebMetaData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass authentication data (keycloak.json) as a servlet context param so it can be read by the KeycloakServletExtension.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitProcessor {
|
||||||
|
// This param name is defined again in Keycloak Undertow Integration class
|
||||||
|
// org.keycloak.adapters.undertow.KeycloakServletExtension. We have this value in
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
|
||||||
|
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||||
|
String deploymentName = deploymentUnit.getName();
|
||||||
|
|
||||||
|
KeycloakAdapterConfigService service = KeycloakAdapterConfigService.find(phaseContext.getServiceRegistry());
|
||||||
|
if (service.isKeycloakDeployment(deploymentName)) {
|
||||||
|
addKeycloakAuthData(phaseContext, deploymentName, service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addKeycloakAuthData(DeploymentPhaseContext phaseContext, String deploymentName, KeycloakAdapterConfigService service) {
|
||||||
|
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||||
|
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
|
||||||
|
|
||||||
|
//TODO: Find context root properly
|
||||||
|
String resourceName = deploymentName.substring(0, deploymentName.lastIndexOf('.'));
|
||||||
|
|
||||||
|
addJSONData(service.getJSON(deploymentName, resourceName), warMetaData);
|
||||||
|
//addJSONData(getJSON(), warMetaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove this.
|
||||||
|
private String getJSON() {
|
||||||
|
return "{\n" +
|
||||||
|
" \"realm\": \"demo\",\n" +
|
||||||
|
" \"realm-public-key\": \"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB\",\n" +
|
||||||
|
" \"auth-server-url\": \"http://localhost:8080/auth\",\n" +
|
||||||
|
" \"ssl-not-required\": true,\n" +
|
||||||
|
" \"resource\": \"customer-portal-subsys\",\n" +
|
||||||
|
" \"credentials\": {\n" +
|
||||||
|
" \"password\": \"password\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"use-resource-role-mappings\": false,\n" +
|
||||||
|
" \"enable-cors\": false,\n" +
|
||||||
|
" \"cors-max-age\": -1,\n" +
|
||||||
|
" \"expose-token\": false,\n" +
|
||||||
|
" \"bearer-only\": false\n" +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addJSONData(String json, WarMetaData warMetaData) {
|
||||||
|
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
|
||||||
|
if (webMetaData == null) {
|
||||||
|
webMetaData = new JBossWebMetaData();
|
||||||
|
warMetaData.setMergedJBossWebMetaData(webMetaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ParamValueMetaData> contextParams = webMetaData.getContextParams();
|
||||||
|
if (contextParams == null) {
|
||||||
|
contextParams = new ArrayList<ParamValueMetaData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamValueMetaData param = new ParamValueMetaData();
|
||||||
|
param.setParamName(AUTH_DATA_PARAM_NAME);
|
||||||
|
param.setParamValue(json);
|
||||||
|
contextParams.add(param);
|
||||||
|
|
||||||
|
webMetaData.setContextParams(contextParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undeploy(DeploymentUnit du) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,207 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.Property;
|
||||||
|
import org.jboss.msc.service.Service;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
import org.jboss.msc.service.ServiceName;
|
||||||
|
import org.jboss.msc.service.ServiceRegistry;
|
||||||
|
import org.jboss.msc.service.StartContext;
|
||||||
|
import org.jboss.msc.service.StartException;
|
||||||
|
import org.jboss.msc.service.StopContext;
|
||||||
|
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This service keeps track of the entire Keycloak management model so as to provide
|
||||||
|
* adapter configuration to each deployment at deploy time.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakAdapterConfigService implements Service<KeycloakAdapterConfigService> {
|
||||||
|
private static final String CREDENTIALS_JSON_NAME = "credentials";
|
||||||
|
|
||||||
|
// Right now this is used as a service, but I'm not sure it really needs to be implemented that way.
|
||||||
|
// It's also a singleton serving the entire subsystem, but the INSTANCE variable is currently only
|
||||||
|
// used during initialization of the subsystem.
|
||||||
|
public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("KeycloakAdapterConfigService");
|
||||||
|
public static final KeycloakAdapterConfigService INSTANCE = new KeycloakAdapterConfigService();
|
||||||
|
|
||||||
|
private Map<String, ModelNode> realms = new HashMap<String, ModelNode>();
|
||||||
|
private Map<String, ModelNode> deployments = new HashMap<String, ModelNode>();
|
||||||
|
|
||||||
|
private KeycloakAdapterConfigService() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(StartContext sc) throws StartException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(StopContext sc) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeycloakAdapterConfigService getValue() throws IllegalStateException, IllegalArgumentException {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRealm(ModelNode operation, ModelNode model) {
|
||||||
|
this.realms.put(realmNameFromOp(operation), model.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateRealm(ModelNode operation, String attrName, ModelNode resolvedValue) {
|
||||||
|
ModelNode realm = this.realms.get(realmNameFromOp(operation));
|
||||||
|
realm.get(attrName).set(resolvedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRealm(ModelNode operation) {
|
||||||
|
this.realms.remove(realmNameFromOp(operation));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSecureDeployment(ModelNode operation, ModelNode model) {
|
||||||
|
ModelNode deployment = model.clone();
|
||||||
|
deployment.get(RealmDefinition.TAG_NAME).set(realmNameFromOp(operation));
|
||||||
|
this.deployments.put(deploymentNameFromOp(operation), deployment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSecureDeployment(ModelNode operation, String attrName, ModelNode resolvedValue) {
|
||||||
|
ModelNode deployment = this.deployments.get(deploymentNameFromOp(operation));
|
||||||
|
deployment.get(attrName).set(resolvedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSecureDeployment(ModelNode operation) {
|
||||||
|
this.deployments.remove(deploymentNameFromOp(operation));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCredential(ModelNode operation, ModelNode model) {
|
||||||
|
ModelNode credentials = credentialsFromOp(operation);
|
||||||
|
if (!credentials.isDefined()) {
|
||||||
|
credentials = new ModelNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
String credentialName = credentialNameFromOp(operation);
|
||||||
|
credentials.get(credentialName).set(model.get("value").asString());
|
||||||
|
|
||||||
|
ModelNode deployment = this.deployments.get(deploymentNameFromOp(operation));
|
||||||
|
deployment.get(CREDENTIALS_JSON_NAME).set(credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeCredential(ModelNode operation) {
|
||||||
|
ModelNode credentials = credentialsFromOp(operation);
|
||||||
|
if (!credentials.isDefined()) {
|
||||||
|
throw new RuntimeException("Can not remove credential. No credential defined for deployment in op " + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String credentialName = credentialNameFromOp(operation);
|
||||||
|
credentials.remove(credentialName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCredential(ModelNode operation, String attrName, ModelNode resolvedValue) {
|
||||||
|
ModelNode credentials = credentialsFromOp(operation);
|
||||||
|
if (!credentials.isDefined()) {
|
||||||
|
throw new RuntimeException("Can not update credential. No credential defined for deployment in op " + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String credentialName = credentialNameFromOp(operation);
|
||||||
|
credentials.get(credentialName).set(resolvedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelNode credentialsFromOp(ModelNode operation) {
|
||||||
|
ModelNode deployment = this.deployments.get(deploymentNameFromOp(operation));
|
||||||
|
return deployment.get(CREDENTIALS_JSON_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String realmNameFromOp(ModelNode operation) {
|
||||||
|
return valueFromOpAddress(RealmDefinition.TAG_NAME, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String deploymentNameFromOp(ModelNode operation) {
|
||||||
|
return valueFromOpAddress(SecureDeploymentDefinition.TAG_NAME, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String credentialNameFromOp(ModelNode operation) {
|
||||||
|
return valueFromOpAddress(CredentialDefinition.TAG_NAME, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String valueFromOpAddress(String addrElement, ModelNode operation) {
|
||||||
|
String deploymentName = getValueOfAddrElement(operation.get(ADDRESS), addrElement);
|
||||||
|
if (deploymentName == null) throw new RuntimeException("Can't find '" + addrElement + "' in address " + operation.toString());
|
||||||
|
return deploymentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValueOfAddrElement(ModelNode address, String elementName) {
|
||||||
|
for (ModelNode element : address.asList()) {
|
||||||
|
if (element.has(elementName)) return element.get(elementName).asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJSON(String deploymentName, String resourceName) {
|
||||||
|
ModelNode deployment = this.deployments.get(deploymentName);
|
||||||
|
String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
|
||||||
|
ModelNode realm = this.realms.get(realmName);
|
||||||
|
|
||||||
|
ModelNode json = new ModelNode();
|
||||||
|
json.get(RealmDefinition.TAG_NAME).set(realmName);
|
||||||
|
json.get("resource").set(resourceName);
|
||||||
|
|
||||||
|
// Realm values set first. Some can be overridden by deployment values.
|
||||||
|
setJSONValues(json, realm);
|
||||||
|
setJSONValues(json, deployment);
|
||||||
|
|
||||||
|
// TODO: change this to true to compact the string
|
||||||
|
return json.toJSONString(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setJSONValues(ModelNode json, ModelNode values) {
|
||||||
|
for (Property prop : values.asPropertyList()) {
|
||||||
|
String name = prop.getName();
|
||||||
|
ModelNode value = prop.getValue();
|
||||||
|
if (value.isDefined()) {
|
||||||
|
json.get(name).set(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKeycloakDeployment(String deploymentName) {
|
||||||
|
return this.deployments.containsKey(deploymentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static KeycloakAdapterConfigService find(ServiceRegistry registry) {
|
||||||
|
ServiceController<?> container = registry.getService(KeycloakAdapterConfigService.SERVICE_NAME);
|
||||||
|
if (container != null) {
|
||||||
|
KeycloakAdapterConfigService service = (KeycloakAdapterConfigService)container.getValue();
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static KeycloakAdapterConfigService find(OperationContext context) {
|
||||||
|
return find(context.getServiceRegistry(true));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.server.deployment.Attachments;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentPhaseContext;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnit;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
|
||||||
|
import org.jboss.as.server.deployment.module.ModuleDependency;
|
||||||
|
import org.jboss.as.server.deployment.module.ModuleSpecification;
|
||||||
|
import org.jboss.modules.Module;
|
||||||
|
import org.jboss.modules.ModuleIdentifier;
|
||||||
|
import org.jboss.modules.ModuleLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
|
||||||
|
|
||||||
|
private static final ModuleIdentifier KEYCLOAK_UNDERTOW_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-undertow-adapter");
|
||||||
|
private static final ModuleIdentifier KEYCLOAK_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-adapter-core");
|
||||||
|
private static final ModuleIdentifier APACHE_HTTPCOMPONENTS = ModuleIdentifier.create("org.apache.httpcomponents");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
|
||||||
|
final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||||
|
|
||||||
|
KeycloakAdapterConfigService service = KeycloakAdapterConfigService.find(phaseContext.getServiceRegistry());
|
||||||
|
if (service.isKeycloakDeployment(deploymentUnit.getName())) {
|
||||||
|
addModules(deploymentUnit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addModules(DeploymentUnit deploymentUnit) {
|
||||||
|
final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
|
||||||
|
final ModuleLoader moduleLoader = Module.getBootModuleLoader();
|
||||||
|
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_UNDERTOW_ADAPTER, false, false, true, false));
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE_ADAPTER, false, false, false, false));
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, APACHE_HTTPCOMPONENTS, false, false, true, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undeploy(DeploymentUnit du) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.Extension;
|
||||||
|
import org.jboss.as.controller.ExtensionContext;
|
||||||
|
import org.jboss.as.controller.PathElement;
|
||||||
|
import org.jboss.as.controller.SubsystemRegistration;
|
||||||
|
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
|
||||||
|
import org.jboss.as.controller.parsing.ExtensionParsingContext;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
import org.jboss.as.controller.ResourceDefinition;
|
||||||
|
import org.keycloak.subsystem.logging.KeycloakLogger;
|
||||||
|
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main Extension class for the subsystem.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakExtension implements Extension {
|
||||||
|
|
||||||
|
public static final String SUBSYSTEM_NAME = "keycloak";
|
||||||
|
public static final String NAMESPACE = "urn:jboss:domain:keycloak:1.0";
|
||||||
|
private static final KeycloakSubsystemParser PARSER = new KeycloakSubsystemParser();
|
||||||
|
static final PathElement PATH_SUBSYSTEM = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
|
||||||
|
private static final String RESOURCE_NAME = KeycloakExtension.class.getPackage().getName() + ".LocalDescriptions";
|
||||||
|
private static final int MANAGEMENT_API_MAJOR_VERSION = 1;
|
||||||
|
private static final int MANAGEMENT_API_MINOR_VERSION = 0;
|
||||||
|
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 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) {
|
||||||
|
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
|
||||||
|
for (String kp : keyPrefix) {
|
||||||
|
prefix.append('.').append(kp);
|
||||||
|
}
|
||||||
|
return new StandardResourceDescriptionResolver(prefix.toString(), RESOURCE_NAME, KeycloakExtension.class.getClassLoader(), true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeParsers(final ExtensionParsingContext context) {
|
||||||
|
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, KeycloakExtension.NAMESPACE, PARSER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initialize(final ExtensionContext context) {
|
||||||
|
KeycloakLogger.ROOT_LOGGER.debug("Activating Keycloak Extension");
|
||||||
|
final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, MANAGEMENT_API_MAJOR_VERSION,
|
||||||
|
MANAGEMENT_API_MINOR_VERSION, MANAGEMENT_API_MICRO_VERSION);
|
||||||
|
|
||||||
|
ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
|
||||||
|
ManagementResourceRegistration realmRegistration = registration.registerSubModel(REALM_DEFINITION);
|
||||||
|
ManagementResourceRegistration secureDeploymentRegistration = realmRegistration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION);
|
||||||
|
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
|
||||||
|
|
||||||
|
subsystem.registerXMLElementWriter(PARSER);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.as.controller.ServiceVerificationHandler;
|
||||||
|
import org.jboss.as.server.AbstractDeploymentChainStep;
|
||||||
|
import org.jboss.as.server.DeploymentProcessorTarget;
|
||||||
|
import org.jboss.as.server.deployment.Phase;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Keycloak subsystem add update handler.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
|
||||||
|
|
||||||
|
static final KeycloakSubsystemAdd INSTANCE = new KeycloakSubsystemAdd();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
model.setEmptyObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performBoottime(final OperationContext context, ModelNode operation, final ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) {
|
||||||
|
context.addStep(new AbstractDeploymentChainStep() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DeploymentProcessorTarget processorTarget) {
|
||||||
|
processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, 0, new KeycloakDependencyProcessor());
|
||||||
|
processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME,
|
||||||
|
KeycloakAdapterConfigDeploymentProcessor.PHASE,
|
||||||
|
KeycloakAdapterConfigDeploymentProcessor.PRIORITY,
|
||||||
|
new KeycloakAdapterConfigDeploymentProcessor());
|
||||||
|
}
|
||||||
|
}, OperationContext.Stage.RUNTIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||||
|
super.performRuntime(context, operation, model, verificationHandler, newControllers);
|
||||||
|
|
||||||
|
ServiceController<KeycloakAdapterConfigService> controller = context.getServiceTarget()
|
||||||
|
.addService(KeycloakAdapterConfigService.SERVICE_NAME, KeycloakAdapterConfigService.INSTANCE)
|
||||||
|
.addListener(verificationHandler)
|
||||||
|
.setInitialMode(ServiceController.Mode.ACTIVE)
|
||||||
|
.install();
|
||||||
|
newControllers.add(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean requiresRuntimeVerification() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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 org.jboss.as.controller.PathElement;
|
||||||
|
import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
|
||||||
|
import org.jboss.as.controller.SimpleResourceDefinition;
|
||||||
|
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
|
||||||
|
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definition of subsystem=keycloak.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
|
||||||
|
protected KeycloakSubsystemDefinition() {
|
||||||
|
super(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver("subsystem"),
|
||||||
|
KeycloakSubsystemAdd.INSTANCE,
|
||||||
|
ReloadRequiredRemoveStepHandler.INSTANCE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerOperations(resourceRegistration);
|
||||||
|
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
* 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.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.xml.stream.XMLStreamConstants;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.PathAddress;
|
||||||
|
import org.jboss.as.controller.PathElement;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||||
|
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
|
||||||
|
import org.jboss.as.controller.operations.common.Util;
|
||||||
|
import org.jboss.as.controller.parsing.ParseUtils;
|
||||||
|
import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.Property;
|
||||||
|
import org.jboss.staxmapper.XMLElementReader;
|
||||||
|
import org.jboss.staxmapper.XMLElementWriter;
|
||||||
|
import org.jboss.staxmapper.XMLExtendedStreamReader;
|
||||||
|
import org.jboss.staxmapper.XMLExtendedStreamWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The subsystem parser, which uses stax to read and write to and from xml
|
||||||
|
*/
|
||||||
|
class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>, XMLElementWriter<SubsystemMarshallingContext> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> list) throws XMLStreamException {
|
||||||
|
// Require no attributes
|
||||||
|
ParseUtils.requireNoAttributes(reader);
|
||||||
|
ModelNode addKeycloakSub = Util.createAddOperation(PathAddress.pathAddress(KeycloakExtension.PATH_SUBSYSTEM));
|
||||||
|
list.add(addKeycloakSub);
|
||||||
|
|
||||||
|
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
|
||||||
|
if (!reader.getLocalName().equals("realm")) {
|
||||||
|
throw ParseUtils.unexpectedElement(reader);
|
||||||
|
}
|
||||||
|
readRealm(reader, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for debugging
|
||||||
|
private int nextTag(XMLExtendedStreamReader reader) throws XMLStreamException {
|
||||||
|
return reader.nextTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
|
||||||
|
String realmName = readNameAttribute(reader);
|
||||||
|
ModelNode composite = new ModelNode();
|
||||||
|
composite.get(ModelDescriptionConstants.OP_ADDR).setEmptyList();
|
||||||
|
composite.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.COMPOSITE);
|
||||||
|
ModelNode addRealm = new ModelNode();
|
||||||
|
addRealm.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
|
||||||
|
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
|
||||||
|
PathElement.pathElement(RealmDefinition.TAG_NAME, realmName));
|
||||||
|
addRealm.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
|
||||||
|
|
||||||
|
List<ModelNode> resourcesToAdd = new ArrayList<ModelNode>();
|
||||||
|
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
|
||||||
|
String tagName = reader.getLocalName();
|
||||||
|
if (tagName.equals(SecureDeploymentDefinition.TAG_NAME)) {
|
||||||
|
readDeployment(reader, addr, resourcesToAdd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleAttributeDefinition def = RealmDefinition.lookup(tagName);
|
||||||
|
if (def == null) throw new XMLStreamException("Unknown realm tag " + tagName);
|
||||||
|
def.parseAndSetParameter(reader.getElementText(), addRealm, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RealmDefinition.validateTruststoreSetIfRequired(addRealm)) {
|
||||||
|
//TODO: externalize the message
|
||||||
|
throw new XMLStreamException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode steps = new ModelNode();
|
||||||
|
steps.add(addRealm);
|
||||||
|
for (ModelNode resource : resourcesToAdd) {
|
||||||
|
steps.add(resource);
|
||||||
|
}
|
||||||
|
composite.get(ModelDescriptionConstants.STEPS).set(steps);
|
||||||
|
|
||||||
|
list.add(composite);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readDeployment(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> resourcesToAdd) throws XMLStreamException {
|
||||||
|
String name = readNameAttribute(reader);
|
||||||
|
ModelNode addSecureDeployment = new ModelNode();
|
||||||
|
addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
|
||||||
|
PathAddress addr = PathAddress.pathAddress(parent, PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
|
||||||
|
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
|
||||||
|
List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>();
|
||||||
|
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
|
||||||
|
String tagName = reader.getLocalName();
|
||||||
|
if (tagName.equals(CredentialDefinition.TAG_NAME)) {
|
||||||
|
readCredential(reader, addr, credentialsToAdd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleAttributeDefinition def = SecureDeploymentDefinition.lookup(tagName);
|
||||||
|
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
|
||||||
|
def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader);
|
||||||
|
}
|
||||||
|
// Must add credentials after the deployment is added.
|
||||||
|
resourcesToAdd.add(addSecureDeployment);
|
||||||
|
resourcesToAdd.addAll(credentialsToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readCredential(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> credentialsToAdd) throws XMLStreamException {
|
||||||
|
String name = readNameAttribute(reader);
|
||||||
|
ModelNode addCredential = new ModelNode();
|
||||||
|
addCredential.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
|
||||||
|
PathAddress addr = PathAddress.pathAddress(parent, PathElement.pathElement(CredentialDefinition.TAG_NAME, name));
|
||||||
|
addCredential.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
|
||||||
|
addCredential.get(CredentialDefinition.VALUE.getName()).set(reader.getElementText());
|
||||||
|
credentialsToAdd.add(addCredential);
|
||||||
|
}
|
||||||
|
|
||||||
|
// expects that the current tag will have one single attribute called "name"
|
||||||
|
private String readNameAttribute(XMLExtendedStreamReader reader) throws XMLStreamException {
|
||||||
|
String name = null;
|
||||||
|
for (int i = 0; i < reader.getAttributeCount(); i++) {
|
||||||
|
String attr = reader.getAttributeLocalName(i);
|
||||||
|
if (attr.equals("name")) {
|
||||||
|
name = reader.getAttributeValue(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw ParseUtils.unexpectedAttribute(reader, i);
|
||||||
|
}
|
||||||
|
if (name == null) {
|
||||||
|
throw ParseUtils.missingRequired(reader, Collections.singleton("name"));
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
|
||||||
|
context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
|
||||||
|
writeRealms(writer, context);
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeRealms(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
|
||||||
|
if (!context.getModelNode().get(RealmDefinition.TAG_NAME).isDefined()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Property realm : context.getModelNode().get(RealmDefinition.TAG_NAME).asPropertyList()) {
|
||||||
|
writer.writeStartElement(RealmDefinition.TAG_NAME);
|
||||||
|
writer.writeAttribute("name", realm.getName());
|
||||||
|
ModelNode realmElements = realm.getValue();
|
||||||
|
for (AttributeDefinition element : RealmDefinition.ALL_ATTRIBUTES) {
|
||||||
|
element.marshallAsElement(realmElements, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode deployments = realmElements.get(SecureDeploymentDefinition.TAG_NAME);
|
||||||
|
if (deployments.isDefined()) {
|
||||||
|
writeSecureDeployments(writer, deployments);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeSecureDeployments(XMLExtendedStreamWriter writer, ModelNode deployments) throws XMLStreamException {
|
||||||
|
for (Property deployment : deployments.asPropertyList()) {
|
||||||
|
writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME);
|
||||||
|
writer.writeAttribute("name", deployment.getName());
|
||||||
|
ModelNode deploymentElements = deployment.getValue();
|
||||||
|
for (AttributeDefinition element : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
|
||||||
|
element.marshallAsElement(deploymentElements, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode credentials = deploymentElements.get(CredentialDefinition.TAG_NAME);
|
||||||
|
if (credentials.isDefined()) {
|
||||||
|
writeCredentials(writer, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeCredentials(XMLExtendedStreamWriter writer, ModelNode credentials) throws XMLStreamException {
|
||||||
|
for (Property credential : credentials.asPropertyList()) {
|
||||||
|
writer.writeStartElement(CredentialDefinition.TAG_NAME);
|
||||||
|
writer.writeAttribute("name", credential.getName());
|
||||||
|
String credentialValue = credential.getValue().get(CredentialDefinition.VALUE.getName()).asString();
|
||||||
|
writeCharacters(writer, credentialValue);
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// code taken from org.jboss.as.controller.AttributeMarshaller
|
||||||
|
private void writeCharacters(XMLExtendedStreamWriter writer, String content) throws XMLStreamException {
|
||||||
|
if (content.indexOf('\n') > -1) {
|
||||||
|
// Multiline content. Use the overloaded variant that staxmapper will format
|
||||||
|
writer.writeCharacters(content);
|
||||||
|
} else {
|
||||||
|
// Staxmapper will just output the chars without adding newlines if this is used
|
||||||
|
char[] chars = content.toCharArray();
|
||||||
|
writer.writeCharacters(chars, 0, chars.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
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 static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmAddHandler extends AbstractAddStepHandler {
|
||||||
|
|
||||||
|
public static RealmAddHandler INSTANCE = new RealmAddHandler();
|
||||||
|
|
||||||
|
private RealmAddHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
// TODO: localize exception. get id number
|
||||||
|
if (!operation.get(OP).asString().equals(ADD)) {
|
||||||
|
throw new OperationFailedException("Unexpected operation for add realm. operation=" + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AttributeDefinition attrib : RealmDefinition.ALL_ATTRIBUTES) {
|
||||||
|
attrib.validateAndSet(operation, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RealmDefinition.validateTruststoreSetIfRequired(model.clone())) {
|
||||||
|
//TODO: externalize message
|
||||||
|
throw new OperationFailedException("truststore and truststore-password must be set if both ssl-not-required and disable-trust-maanger are false.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.addRealm(operation, model);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
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.operations.validation.IntRangeValidator;
|
||||||
|
import org.jboss.as.controller.operations.validation.StringLengthValidator;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.ModelType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes and operations for the Realm
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmDefinition extends SimpleResourceDefinition {
|
||||||
|
|
||||||
|
public static final String TAG_NAME = "realm";
|
||||||
|
|
||||||
|
protected static final SimpleAttributeDefinition REALM_PUBLIC_KEY =
|
||||||
|
new SimpleAttributeDefinitionBuilder("realm-public-key", ModelType.STRING, false)
|
||||||
|
.setXmlName("realm-public-key")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition AUTH_SERVER_URL =
|
||||||
|
new SimpleAttributeDefinitionBuilder("auth-server-url", ModelType.STRING, false)
|
||||||
|
.setXmlName("auth-server-url")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition SSL_NOT_REQUIRED =
|
||||||
|
new SimpleAttributeDefinitionBuilder("ssl-not-required", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("ssl-not-required")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition ALLOW_ANY_HOSTNAME =
|
||||||
|
new SimpleAttributeDefinitionBuilder("allow-any-hostname", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("allow-any-hostname")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition DISABLE_TRUST_MANAGER =
|
||||||
|
new SimpleAttributeDefinitionBuilder("disable-trust-manager", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("disable-trust-manager")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition TRUSTSTORE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("truststore", ModelType.STRING, true)
|
||||||
|
.setXmlName("truststore")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition TRUSTSTORE_PASSWORD =
|
||||||
|
new SimpleAttributeDefinitionBuilder("truststore-password", ModelType.STRING, true)
|
||||||
|
.setXmlName("truststore-password")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CONNECTION_POOL_SIZE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("connection-pool-size", ModelType.INT, true)
|
||||||
|
.setXmlName("connection-pool-size")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new IntRangeValidator(0))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> REALM_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(REALM_PUBLIC_KEY);
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(AUTH_SERVER_URL);
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(TRUSTSTORE);
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(SSL_NOT_REQUIRED);
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
|
||||||
|
REALM_ONLY_ATTRIBUTES.add(CONNECTION_POOL_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
ALL_ATTRIBUTES.addAll(REALM_ONLY_ATTRIBUTES);
|
||||||
|
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 final RealmWriteAttributeHandler realmAttrHandler = new RealmWriteAttributeHandler(ALL_ATTRIBUTES.toArray(new SimpleAttributeDefinition[0]));
|
||||||
|
|
||||||
|
public RealmDefinition() {
|
||||||
|
super(PathElement.pathElement("realm"),
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver("realm"),
|
||||||
|
RealmAddHandler.INSTANCE,
|
||||||
|
RealmRemoveHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
//TODO: use subclass of realmAttrHandler that can call RealmDefinition.validateTruststoreSetIfRequired
|
||||||
|
resourceRegistration.registerReadWriteAttribute(attrDef, null, realmAttrHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* truststore and truststore-password must be set if ssl-not-required and disable-trust-manager are both false.
|
||||||
|
*
|
||||||
|
* @param attributes The full set of attributes.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the attributes are valid, <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean validateTruststoreSetIfRequired(ModelNode attributes) {
|
||||||
|
if (!isSet(attributes, SSL_NOT_REQUIRED) && !isSet(attributes, DISABLE_TRUST_MANAGER)) {
|
||||||
|
if (!(isSet(attributes, TRUSTSTORE) && isSet(attributes, TRUSTSTORE_PASSWORD))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
|
||||||
|
ModelNode attribute = attributes.get(def.getName());
|
||||||
|
|
||||||
|
if (def.getType() == ModelType.BOOLEAN) {
|
||||||
|
return attribute.isDefined() && attribute.asBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
return attribute.isDefined() && !attribute.asString().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimpleAttributeDefinition lookup(String name) {
|
||||||
|
return DEFINITION_LOOKUP.get(name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractRemoveStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmRemoveHandler extends AbstractRemoveStepHandler {
|
||||||
|
|
||||||
|
public static RealmRemoveHandler INSTANCE = new RealmRemoveHandler();
|
||||||
|
|
||||||
|
private RealmRemoveHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.removeRealm(operation);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.jboss.as.controller.AbstractWriteAttributeHandler;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an attribute on a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
|
||||||
|
|
||||||
|
public RealmWriteAttributeHandler(List<AttributeDefinition> definitions) {
|
||||||
|
this(definitions.toArray(new AttributeDefinition[definitions.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealmWriteAttributeHandler(AttributeDefinition... definitions) {
|
||||||
|
super(definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode resolvedValue, ModelNode currentValue, HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.updateRealm(operation, attributeName, resolvedValue);
|
||||||
|
|
||||||
|
hh.setHandback(ckService);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
|
||||||
|
ckService.updateRealm(operation, attributeName, valueToRestore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
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 static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a deployment to a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SecureDeploymentAddHandler extends AbstractAddStepHandler {
|
||||||
|
|
||||||
|
public static SecureDeploymentAddHandler INSTANCE = new SecureDeploymentAddHandler();
|
||||||
|
|
||||||
|
private SecureDeploymentAddHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
// TODO: localize exception. get id number
|
||||||
|
if (!operation.get(OP).asString().equals(ADD)) {
|
||||||
|
throw new OperationFailedException("Unexpected operation for add secure deployment. operation=" + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AttributeDefinition attr : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
|
||||||
|
attr.validateAndSet(operation, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.addSecureDeployment(operation, model);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
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.operations.validation.StringLengthValidator;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.ModelType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes and operations for a secure-deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||||
|
|
||||||
|
public static final String TAG_NAME = "secure-deployment";
|
||||||
|
|
||||||
|
protected static final SimpleAttributeDefinition RESOURCE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
|
||||||
|
.setXmlName("resource")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition USE_RESOURCE_ROLE_MAPPINGS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("use-resource-role-mappings", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("use-resource-role-mappings")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition BEARER_ONLY =
|
||||||
|
new SimpleAttributeDefinitionBuilder("bearer-only", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("bearer-only")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
ALL_ATTRIBUTES.addAll(DEPLOYMENT_ONLY_ATTRIBUTES);
|
||||||
|
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 SecureDeploymentWriteAttributeHandler attrHandler = new SecureDeploymentWriteAttributeHandler(ALL_ATTRIBUTES);
|
||||||
|
|
||||||
|
public SecureDeploymentDefinition() {
|
||||||
|
super(PathElement.pathElement(TAG_NAME),
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
|
||||||
|
SecureDeploymentAddHandler.INSTANCE,
|
||||||
|
SecureDeploymentRemoveHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractRemoveStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a secure-deployment from a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SecureDeploymentRemoveHandler extends AbstractRemoveStepHandler {
|
||||||
|
|
||||||
|
public static SecureDeploymentRemoveHandler INSTANCE = new SecureDeploymentRemoveHandler();
|
||||||
|
|
||||||
|
private SecureDeploymentRemoveHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
ckService.removeSecureDeployment(operation);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.jboss.as.controller.AbstractWriteAttributeHandler;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an attribute on a secure-deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SecureDeploymentWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
|
||||||
|
|
||||||
|
public SecureDeploymentWriteAttributeHandler(List<SimpleAttributeDefinition> definitions) {
|
||||||
|
this(definitions.toArray(new AttributeDefinition[definitions.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecureDeploymentWriteAttributeHandler(AttributeDefinition... definitions) {
|
||||||
|
super(definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode resolvedValue, ModelNode currentValue, HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||||
|
hh.setHandback(ckService);
|
||||||
|
ckService.updateSecureDeployment(operation, attributeName, resolvedValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
|
||||||
|
ckService.updateSecureDeployment(operation, attributeName, valueToRestore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
|
||||||
|
import org.jboss.as.controller.operations.validation.IntRangeValidator;
|
||||||
|
import org.jboss.as.controller.operations.validation.StringLengthValidator;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.ModelType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes that can be present in both a realm and an application (secure-deployment).
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SharedAttributeDefinitons {
|
||||||
|
|
||||||
|
protected static final SimpleAttributeDefinition ENABLE_CORS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("enable-cors", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("enable-cors")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CLIENT_KEYSTORE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("client-keystore", ModelType.STRING, true)
|
||||||
|
.setXmlName("client-keystore")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CLIENT_KEYSTORE_PASSWORD =
|
||||||
|
new SimpleAttributeDefinitionBuilder("client-keystore-password", ModelType.STRING, true)
|
||||||
|
.setXmlName("client-keystore-password")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CLIENT_KEY_PASSWORD =
|
||||||
|
new SimpleAttributeDefinitionBuilder("client-key-password", ModelType.STRING, true)
|
||||||
|
.setXmlName("client-key-password")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CORS_MAX_AGE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("cors-max-age", ModelType.INT, true)
|
||||||
|
.setXmlName("cors-max-age")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new IntRangeValidator(-1))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CORS_ALLOWED_HEADERS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("cors-allowed-headers", ModelType.STRING, true)
|
||||||
|
.setXmlName("cors-allowed-headers")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CORS_ALLOWED_METHODS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("cors-allowed-methods", ModelType.STRING, true)
|
||||||
|
.setXmlName("cors-allowed-methods")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition EXPOSE_TOKEN =
|
||||||
|
new SimpleAttributeDefinitionBuilder("expose-token", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("expose-token")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
ATTRIBUTES.add(ENABLE_CORS);
|
||||||
|
ATTRIBUTES.add(CLIENT_KEYSTORE);
|
||||||
|
ATTRIBUTES.add(CLIENT_KEYSTORE_PASSWORD);
|
||||||
|
ATTRIBUTES.add(CLIENT_KEY_PASSWORD);
|
||||||
|
ATTRIBUTES.add(CORS_MAX_AGE);
|
||||||
|
ATTRIBUTES.add(CORS_ALLOWED_HEADERS);
|
||||||
|
ATTRIBUTES.add(CORS_ALLOWED_METHODS);
|
||||||
|
ATTRIBUTES.add(EXPOSE_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.logging;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.jboss.logging.BasicLogger;
|
||||||
|
import org.jboss.logging.annotations.LogMessage;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.jboss.logging.annotations.Message;
|
||||||
|
import org.jboss.logging.annotations.MessageLogger;
|
||||||
|
import org.jboss.vfs.VirtualFile;
|
||||||
|
|
||||||
|
import static org.jboss.logging.Logger.Level.ERROR;
|
||||||
|
import static org.jboss.logging.Logger.Level.INFO;
|
||||||
|
import static org.jboss.logging.Logger.Level.WARN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface to be fleshed out later when error messages are fully externalized.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
@MessageLogger(projectCode = "KEYCLOAK")
|
||||||
|
public interface KeycloakLogger extends BasicLogger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A logger with a category of the package name.
|
||||||
|
*/
|
||||||
|
KeycloakLogger ROOT_LOGGER = Logger.getMessageLogger(KeycloakLogger.class, "org.jboss.keycloak");
|
||||||
|
|
||||||
|
/* @LogMessage(level = ERROR)
|
||||||
|
@Message(id = 12600, value = "Could not load JSF managed bean class: %s")
|
||||||
|
void managedBeanLoadFail(String managedBean);
|
||||||
|
|
||||||
|
@LogMessage(level = ERROR)
|
||||||
|
@Message(id = 12601, value = "JSF managed bean class %s has no default constructor")
|
||||||
|
void managedBeanNoDefaultConstructor(String managedBean);
|
||||||
|
|
||||||
|
@LogMessage(level = ERROR)
|
||||||
|
@Message(id = 12602, value = "Failed to parse %s, managed beans defined in this file will not be available")
|
||||||
|
void managedBeansConfigParseFailed(VirtualFile facesConfig);
|
||||||
|
|
||||||
|
@LogMessage(level = WARN)
|
||||||
|
@Message(id = 12603, value = "Unknown JSF version '%s'. Default version '%s' will be used instead.")
|
||||||
|
void unknownJSFVersion(String version, String defaultVersion);
|
||||||
|
|
||||||
|
@LogMessage(level = WARN)
|
||||||
|
@Message(id = 12604, value = "JSF version slot '%s' is missing from module %s")
|
||||||
|
void missingJSFModule(String version, String module);
|
||||||
|
|
||||||
|
@LogMessage(level = INFO)
|
||||||
|
@Message(id = 12605, value = "Activated the following JSF Implementations: %s")
|
||||||
|
void activatedJSFImplementations(List target); */
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.logging;
|
||||||
|
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
|
||||||
|
import org.jboss.jandex.AnnotationTarget;
|
||||||
|
import org.jboss.jandex.DotName;
|
||||||
|
import org.jboss.logging.annotations.Cause;
|
||||||
|
import org.jboss.logging.annotations.Message;
|
||||||
|
import org.jboss.logging.annotations.MessageBundle;
|
||||||
|
import org.jboss.logging.Messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface to be fleshed out later when error messages are fully externalized.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2012 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
@MessageBundle(projectCode = "TLIP")
|
||||||
|
public interface KeycloakMessages {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The messages
|
||||||
|
*/
|
||||||
|
KeycloakMessages MESSAGES = Messages.getBundle(KeycloakMessages.class);
|
||||||
|
/*
|
||||||
|
@Message(id = 12650, value = "Failed to load annotated class: %s")
|
||||||
|
String classLoadingFailed(DotName clazz);
|
||||||
|
|
||||||
|
@Message(id = 12651, value = "Annotation %s in class %s is only allowed on classes")
|
||||||
|
String invalidAnnotationLocation(Object annotation, AnnotationTarget classInfo);
|
||||||
|
|
||||||
|
@Message(id = 12652, value = "Instance creation failed")
|
||||||
|
RuntimeException instanceCreationFailed(@Cause Throwable t);
|
||||||
|
|
||||||
|
@Message(id = 12653, value = "Instance destruction failed")
|
||||||
|
RuntimeException instanceDestructionFailed(@Cause Throwable t);
|
||||||
|
|
||||||
|
@Message(id = 12654, value = "Thread local injection container not set")
|
||||||
|
IllegalStateException noThreadLocalInjectionContainer();
|
||||||
|
|
||||||
|
@Message(id = 12655, value = "@ManagedBean is only allowed at class level %s")
|
||||||
|
String invalidManagedBeanAnnotation(AnnotationTarget target);
|
||||||
|
|
||||||
|
@Message(id = 12656, value = "Default JSF implementation slot '%s' is invalid")
|
||||||
|
DeploymentUnitProcessingException invalidDefaultJSFImpl(String defaultJsfVersion);
|
||||||
|
*/
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.subsystem.extension.KeycloakExtension
|
|
@ -0,0 +1,49 @@
|
||||||
|
keycloak.subsystem=Keycloak subsystem
|
||||||
|
keycloak.subsystem.add=Operation Adds Keycloak subsystem
|
||||||
|
keycloak.subsystem.remove=Operation removes Keycloak subsystem
|
||||||
|
keycloak.subsystem.realm=A Keycloak realm.
|
||||||
|
|
||||||
|
keycloak.realm=A Keycloak realm.
|
||||||
|
keycloak.realm.add=Add a realm definition to the subsystem.
|
||||||
|
keycloak.realm.remove=Remove a realm from the subsystem.
|
||||||
|
keycloak.realm.realm-public-key=TODO: fill in help text
|
||||||
|
keycloak.realm.auth-server-url=TODO: fill in help text
|
||||||
|
keycloak.realm.disable-trust-manager=TODO: fill in help text
|
||||||
|
keycloak.realm.ssl-not-required=TODO: fill in help text
|
||||||
|
keycloak.realm.allow-any-hostname=TODO: fill in help text
|
||||||
|
keycloak.realm.truststore=TODO: fill in help text
|
||||||
|
keycloak.realm.truststore-password=TODO: fill in help text
|
||||||
|
keycloak.realm.connection-pool-size=TODO: fill in help text
|
||||||
|
keycloak.realm.enable-cors=TODO: fill in help text
|
||||||
|
keycloak.realm.client-keystore=TODO: fill in help text
|
||||||
|
keycloak.realm.client-keystore-password=TODO: fill in help text
|
||||||
|
keycloak.realm.client-key-password=TODO: fill in help text
|
||||||
|
keycloak.realm.cors-max-age=TODO: fill in help text
|
||||||
|
keycloak.realm.cors-allowed-headers=TODO: fill in help text
|
||||||
|
keycloak.realm.cors-allowed-methods=TODO: fill in help text
|
||||||
|
keycloak.realm.expose-token=TODO: fill in help text
|
||||||
|
|
||||||
|
keycloak.realm.secure-deployment=A deployment secured by Keycloak
|
||||||
|
|
||||||
|
keycloak.secure-deployment=A deployment secured by Keycloak
|
||||||
|
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
|
||||||
|
keycloak.secure-deployment.remove=Remove a deployment to be secured by Keycloak
|
||||||
|
keycloak.secure-deployment.resource=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.use-resource-role-mappings=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.credentials=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.bearer-only=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.enable-cors=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.client-keystore=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.client-keystore-password=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.client-key-password=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.cors-max-age=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.cors-allowed-headers=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.cors-allowed-methods=TODO: fill in help text
|
||||||
|
keycloak.secure-deployment.expose-token=TODO: fill in help text
|
||||||
|
|
||||||
|
keycloak.secure-deployment.credential=TODO: fill in help text
|
||||||
|
|
||||||
|
keycloak.credential=TODO: fill in help text
|
||||||
|
keycloak.credential.value=TODO: fill in help text
|
||||||
|
keycloak.credential.add=TODO: fill in help text
|
||||||
|
keycloak.credential.remove=TODO: fill in help text
|
89
subsystem/src/main/resources/schema/keycloak_1_0.xsd
Normal file
89
subsystem/src/main/resources/schema/keycloak_1_0.xsd
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="urn:jboss:domain:keycloak:1.0"
|
||||||
|
xmlns="urn:jboss:domain:keycloak:1.0"
|
||||||
|
elementFormDefault="qualified"
|
||||||
|
attributeFormDefault="unqualified"
|
||||||
|
version="1.1">
|
||||||
|
|
||||||
|
<!-- The subsystem root element -->
|
||||||
|
<xs:element name="subsystem" type="subsystemType"/>
|
||||||
|
|
||||||
|
<xs:complexType name="subsystemType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<![CDATA[
|
||||||
|
The Keycloak subsystem, used to register deployments managed by Keycloak
|
||||||
|
]]>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="realm-type"/>
|
||||||
|
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="realm-type">
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>The name of the realm.</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="override-element-type">
|
||||||
|
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
|
||||||
|
<xs:element name="auth-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
|
||||||
|
<xs:element name="code-url" type="xs:string" minOccurs="1" maxOccurs="1" use="required"/>
|
||||||
|
<xs:element name="ssl-not-required" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:choice maxOccurs="unbounded" minOccurs="0">
|
||||||
|
<xs:element name="secure-deployment" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
|
||||||
|
</xs:choice>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="secure-deployment-type">
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>The name of the deployment.</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="override-element-type">
|
||||||
|
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" use="required"/>
|
||||||
|
<xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="credential" maxOccurs="unbounded" minOccurs="0" type="xs:credential-type"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="credential-type">
|
||||||
|
<xs:attribute name="name" type="xs:string" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>The name of the credential.</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="override-element-type">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
<![CDATA[
|
||||||
|
These elements can be declared at the realm level and overridden at the secure-deployment level.
|
||||||
|
]]>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:element name="enable-cors" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="client-keystore" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="client-keystore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="client-key-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="cors-max-age" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="cors-allowed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="expose-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
</xs:schema>
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmDefinitionTestCase {
|
||||||
|
|
||||||
|
private ModelNode model;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
model = new ModelNode();
|
||||||
|
model.get("realm").set("demo");
|
||||||
|
model.get("resource").set("customer-portal");
|
||||||
|
model.get("realm-public-key").set("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB");
|
||||||
|
model.get("auth-url").set("http://localhost:8080/auth-server/rest/realms/demo/tokens/login");
|
||||||
|
model.get("code-url").set("http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes");
|
||||||
|
model.get("expose-token").set(true);
|
||||||
|
ModelNode credential = new ModelNode();
|
||||||
|
credential.get("password").set("password");
|
||||||
|
model.get("credentials").set(credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsTruststoreSetIfRequired() throws Exception {
|
||||||
|
model.get("ssl-not-required").set(true);
|
||||||
|
model.get("disable-trust-manager").set(true);
|
||||||
|
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-not-required").set(true);
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-not-required").set(false);
|
||||||
|
model.get("disable-trust-manager").set(true);
|
||||||
|
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-not-required").set(false);
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
Assert.assertFalse(RealmDefinition.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-not-required").set(false);
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
model.get("truststore").set("foo");
|
||||||
|
Assert.assertFalse(RealmDefinition.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-not-required").set(false);
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
model.get("truststore").set("foo");
|
||||||
|
model.get("truststore-password").set("password");
|
||||||
|
Assert.assertTrue(RealmDefinition.validateTruststoreSetIfRequired(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.extension;
|
||||||
|
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import org.jboss.as.controller.PathAddress;
|
||||||
|
import org.jboss.as.controller.PathElement;
|
||||||
|
import org.jboss.as.subsystem.test.AbstractSubsystemTest;
|
||||||
|
import org.jboss.as.subsystem.test.KernelServices;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIBE;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests all management expects for subsystem, parsing, marshaling, model definition and other
|
||||||
|
* Here is an example that allows you a fine grained controller over what is tested and how. So it can give you ideas what can be done and tested.
|
||||||
|
* If you have no need for advanced testing of subsystem you look at {@link SubsystemBaseParsingTestCase} that testes same stuff but most of the code
|
||||||
|
* is hidden inside of test harness
|
||||||
|
*
|
||||||
|
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
|
||||||
|
*/
|
||||||
|
public class SubsystemParsingTestCase extends AbstractSubsystemTest {
|
||||||
|
|
||||||
|
public SubsystemParsingTestCase() {
|
||||||
|
super(KeycloakExtension.SUBSYSTEM_NAME, new KeycloakExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJson() throws Exception {
|
||||||
|
ModelNode node = new ModelNode();
|
||||||
|
node.get("realm").set("demo");
|
||||||
|
node.get("resource").set("customer-portal");
|
||||||
|
node.get("realm-public-key").set("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB");
|
||||||
|
node.get("auth-url").set("http://localhost:8080/auth-server/rest/realms/demo/tokens/login");
|
||||||
|
node.get("code-url").set("http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes");
|
||||||
|
node.get("ssl-not-required").set(true);
|
||||||
|
node.get("expose-token").set(true);
|
||||||
|
ModelNode credential = new ModelNode();
|
||||||
|
credential.get("password").set("password");
|
||||||
|
node.get("credentials").set(credential);
|
||||||
|
|
||||||
|
System.out.println("json=" + node.toJSONString(false));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Tests that the xml is parsed into the correct operations
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParseSubsystem() throws Exception {
|
||||||
|
//Parse the subsystem xml into operations
|
||||||
|
String subsystemXml =
|
||||||
|
"<subsystem xmlns=\"" + KeycloakExtension.NAMESPACE + "\">" +
|
||||||
|
"</subsystem>";
|
||||||
|
List<ModelNode> operations = super.parse(subsystemXml);
|
||||||
|
|
||||||
|
///Check that we have the expected number of operations
|
||||||
|
Assert.assertEquals(1, operations.size());
|
||||||
|
|
||||||
|
//Check that each operation has the correct content
|
||||||
|
ModelNode addSubsystem = operations.get(0);
|
||||||
|
Assert.assertEquals(ADD, addSubsystem.get(OP).asString());
|
||||||
|
PathAddress addr = PathAddress.pathAddress(addSubsystem.get(OP_ADDR));
|
||||||
|
Assert.assertEquals(1, addr.size());
|
||||||
|
PathElement element = addr.getElement(0);
|
||||||
|
Assert.assertEquals(SUBSYSTEM, element.getKey());
|
||||||
|
Assert.assertEquals(KeycloakExtension.SUBSYSTEM_NAME, element.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the model created from the xml looks as expected
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInstallIntoController() throws Exception {
|
||||||
|
//Parse the subsystem xml and install into the controller
|
||||||
|
String subsystemXml =
|
||||||
|
"<subsystem xmlns=\"" + KeycloakExtension.NAMESPACE + "\">" +
|
||||||
|
"</subsystem>";
|
||||||
|
KernelServices services = super.installInController(subsystemXml);
|
||||||
|
|
||||||
|
//Read the whole model and make sure it looks as expected
|
||||||
|
ModelNode model = services.readWholeModel();
|
||||||
|
Assert.assertTrue(model.get(SUBSYSTEM).hasDefined(KeycloakExtension.SUBSYSTEM_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a controller with a given subsystem xml and then checks that a second
|
||||||
|
* controller started with the xml marshalled from the first one results in the same model
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParseAndMarshalModel() throws Exception {
|
||||||
|
//Parse the subsystem xml and install into the first controller
|
||||||
|
//TODO: Figure out why this fails
|
||||||
|
String subsystemXml =
|
||||||
|
"<subsystem xmlns=\"" + KeycloakExtension.NAMESPACE + "\">" +
|
||||||
|
"</subsystem>";
|
||||||
|
KernelServices servicesA = super.installInController(subsystemXml);
|
||||||
|
//Get the model and the persisted xml from the first controller
|
||||||
|
ModelNode modelA = servicesA.readWholeModel();
|
||||||
|
String marshalled = servicesA.getPersistedSubsystemXml();
|
||||||
|
|
||||||
|
//Install the persisted xml from the first controller into a second controller
|
||||||
|
KernelServices servicesB = super.installInController(marshalled);
|
||||||
|
ModelNode modelB = servicesB.readWholeModel();
|
||||||
|
|
||||||
|
//Make sure the models from the two controllers are identical
|
||||||
|
super.compare(modelA, modelB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a controller with the given subsystem xml and then checks that a second
|
||||||
|
* controller started with the operations from its describe action results in the same model
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDescribeHandler() throws Exception {
|
||||||
|
//Parse the subsystem xml and install into the first controller
|
||||||
|
String subsystemXml =
|
||||||
|
"<subsystem xmlns=\"" + KeycloakExtension.NAMESPACE + "\">" +
|
||||||
|
"</subsystem>";
|
||||||
|
KernelServices servicesA = super.installInController(subsystemXml);
|
||||||
|
//Get the model and the describe operations from the first controller
|
||||||
|
ModelNode modelA = servicesA.readWholeModel();
|
||||||
|
ModelNode describeOp = new ModelNode();
|
||||||
|
describeOp.get(OP).set(DESCRIBE);
|
||||||
|
describeOp.get(OP_ADDR).set(
|
||||||
|
PathAddress.pathAddress(
|
||||||
|
PathElement.pathElement(SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME)).toModelNode());
|
||||||
|
List<ModelNode> operations = super.checkResultAndGetContents(servicesA.executeOperation(describeOp)).asList();
|
||||||
|
|
||||||
|
|
||||||
|
//Install the describe options from the first controller into a second controller
|
||||||
|
KernelServices servicesB = super.installInController(operations);
|
||||||
|
ModelNode modelB = servicesB.readWholeModel();
|
||||||
|
|
||||||
|
//Make sure the models from the two controllers are identical
|
||||||
|
super.compare(modelA, modelB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the subsystem can be removed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSubsystemRemoval() throws Exception {
|
||||||
|
//Parse the subsystem xml and install into the first controller
|
||||||
|
String subsystemXml =
|
||||||
|
"<subsystem xmlns=\"" + KeycloakExtension.NAMESPACE + "\">" +
|
||||||
|
"</subsystem>";
|
||||||
|
KernelServices services = super.installInController(subsystemXml);
|
||||||
|
//Checks that the subsystem was removed from the model
|
||||||
|
super.assertRemoveSubsystemResources(services);
|
||||||
|
|
||||||
|
//TODO Chek that any services that were installed were removed here
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue