keycloak-uncached
Changes
distribution/demo-dist/assembly.xml 2(+1 -1)
distribution/demo-dist/pom.xml 6(+3 -3)
distribution/downloads/pom.xml 4(+2 -2)
distribution/saml-adapters/pom.xml 2(+1 -1)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-spi/main/module.xml 0(+0 -0)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml 0(+0 -0)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml 0(+0 -0)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-adapter-core/main/module.xml 0(+0 -0)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-adapter-subsystem/main/module.xml 2(+1 -1)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-core/main/module.xml 0(+0 -0)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-undertow-adapter/main/module.xml 0(+0 -0)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-wildfly-adapter/main/module.xml 0(+0 -0)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-wildfly-subsystem/main/module.xml 2(+1 -1)
pom.xml 6(+3 -3)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java 60(+60 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java 120(+120 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderAddHandler.java 41(+41 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderDefinition.java 106(+106 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyAddHandler.java 41(+41 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java 80(+68 -12)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSamlExtension.java 19(+11 -8)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java 18(+10 -8)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemDefinition.java 13(+6 -7)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemParser.java 506(+504 -2)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyDefinition.java 122(+122 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreCertificateDefinition.java 36(+36 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreDefinition.java 73(+73 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStorePrivateKeyDefinition.java 52(+52 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakLogger.java 49(+49 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakMessages.java 34(+34 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentAddHandler.java 42(+42 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentDefinition.java 44(+44 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderAddHandler.java 43(+43 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderDefinition.java 125(+125 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleLogoutDefinition.java 84(+84 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java 68(+68 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/FormattingXMLStreamWriter.java 534(+534 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/Spliterator.java 66(+66 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties 63(+63 -0)
saml/client-adapter/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd 268(+268 -0)
saml/client-adapter/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml 49(+49 -0)
saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java 12(+11 -1)
saml/client-adapter/wildfly/pom.xml 2(+1 -1)
saml/client-adapter/wildfly/wildfly9-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemParser.java 91(+0 -91)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java 56(+56 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java 120(+120 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderAddHandler.java 37(+37 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderDefinition.java 106(+106 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyAddHandler.java 37(+37 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakAdapterConfigDeploymentProcessor.java 81(+78 -3)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakDependencyProcessor.java 1(+0 -1)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakDependencyProcessorWildFly.java 0(+0 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSamlExtension.java 12(+8 -4)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemAdd.java 1(+0 -1)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemDefinition.java 9(+5 -4)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemParser.java 569(+569 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyDefinition.java 122(+122 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreCertificateDefinition.java 36(+36 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreDefinition.java 73(+73 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStorePrivateKeyDefinition.java 52(+52 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakLogger.java 45(+45 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakMessages.java 34(+34 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentAddHandler.java 38(+38 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentDefinition.java 47(+47 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderAddHandler.java 39(+39 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java 125(+125 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleLogoutDefinition.java 84(+84 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java 68(+68 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension 0(+0 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties 63(+63 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd 268(+268 -0)
saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/subsystem-templates/keycloak-saml-adapter.xml 4(+2 -2)
saml/client-adapter/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/saml/extension/SubsystemParsingTestCase.java 56(+56 -0)
Details
distribution/demo-dist/assembly.xml 2(+1 -1)
diff --git a/distribution/demo-dist/assembly.xml b/distribution/demo-dist/assembly.xml
index f1c39c2..a06ed13 100755
--- a/distribution/demo-dist/assembly.xml
+++ b/distribution/demo-dist/assembly.xml
@@ -40,7 +40,7 @@
</excludes>
</fileSet>
<fileSet>
- <directory>${project.build.directory}/unpacked/keycloak-saml-wf9-adapter-${project.version}</directory>
+ <directory>${project.build.directory}/unpacked/keycloak-saml-wildfly-adapter-${project.version}</directory>
<outputDirectory>keycloak</outputDirectory>
<excludes>
<exclude>standalone/configuration/standalone-keycloak.xml</exclude>
distribution/demo-dist/pom.xml 6(+3 -3)
diff --git a/distribution/demo-dist/pom.xml b/distribution/demo-dist/pom.xml
index 9443478..baebb36 100755
--- a/distribution/demo-dist/pom.xml
+++ b/distribution/demo-dist/pom.xml
@@ -26,7 +26,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-wf9-adapter-dist</artifactId>
+ <artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
<type>zip</type>
</dependency>
<dependency>
@@ -116,9 +116,9 @@
<artifactItems>
<artifactItem>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-wf9-adapter-dist</artifactId>
+ <artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
<type>zip</type>
- <outputDirectory>${project.build.directory}/unpacked/keycloak-saml-wf9-adapter-${project.version}</outputDirectory>
+ <outputDirectory>${project.build.directory}/unpacked/keycloak-saml-wildfly-adapter-${project.version}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
diff --git a/distribution/demo-dist/src/main/xslt/standalone.xsl b/distribution/demo-dist/src/main/xslt/standalone.xsl
index 106c08f..9f52547 100755
--- a/distribution/demo-dist/src/main/xslt/standalone.xsl
+++ b/distribution/demo-dist/src/main/xslt/standalone.xsl
@@ -44,7 +44,7 @@
<web-context>auth</web-context>
</subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
- <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.6"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1"/>
</xsl:copy>
</xsl:template>
distribution/downloads/pom.xml 4(+2 -2)
diff --git a/distribution/downloads/pom.xml b/distribution/downloads/pom.xml
index b9daadf..9e91285 100755
--- a/distribution/downloads/pom.xml
+++ b/distribution/downloads/pom.xml
@@ -338,12 +338,12 @@
<artifactItem>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-wf9-adapter-dist</artifactId>
+ <artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-wf9-adapter-dist</artifactId>
+ <artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
</artifactItems>
distribution/saml-adapters/pom.xml 2(+1 -1)
diff --git a/distribution/saml-adapters/pom.xml b/distribution/saml-adapters/pom.xml
index 456f292..ea95663 100755
--- a/distribution/saml-adapters/pom.xml
+++ b/distribution/saml-adapters/pom.xml
@@ -15,7 +15,7 @@
<packaging>pom</packaging>
<modules>
- <module>wf9-adapter</module>
+ <module>wildfly-adapter</module>
<module>tomcat6-adapter-zip</module>
<module>tomcat7-adapter-zip</module>
<module>tomcat8-adapter-zip</module>
diff --git a/docbook/saml-adapter-docs/reference/en/en-US/modules/jboss-adapter.xml b/docbook/saml-adapter-docs/reference/en/en-US/modules/jboss-adapter.xml
index fc29402..df07d8d 100755
--- a/docbook/saml-adapter-docs/reference/en/en-US/modules/jboss-adapter.xml
+++ b/docbook/saml-adapter-docs/reference/en/en-US/modules/jboss-adapter.xml
@@ -3,7 +3,7 @@
<para>
To be able to secure WAR apps deployed on JBoss EAP 6.x or Wildfly, you must install and
configure the Keycloak SAML Adapter Subsystem. You then provide a keycloak
- config, <literal>/WEB-INF/keycloak-saml</literal> file in your WAR and change the auth-method to KEYCLOAK-SAML within web.xml.
+ config, <literal>/WEB-INF/keycloak-saml.xml</literal> file in your WAR and change the auth-method to KEYCLOAK-SAML within web.xml.
Both methods are described in this section.
</para>
<section id="jboss-adapter-installation">
@@ -13,10 +13,10 @@
the Keycloak download site. They are also available as a maven artifact.
</para>
<para>
- Install on Wildfly 9:
+ Install on Wildfly 9 or 10:
<programlisting>
$ cd $WILDFLY_HOME
-$ unzip keycloak-saml-wf9-adapter-dist.zip
+$ unzip keycloak-saml-wildfly-adapter-dist.zip
</programlisting>
</para>
<para>
@@ -52,7 +52,7 @@ $ jboss-cli.sh -c --file=adapter-install.cli
</extensions>
<profile>
- <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.6"/>
+ <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1"/>
...
</profile>
]]>
@@ -185,4 +185,92 @@ public class CustomerService {
</programlisting>
</para>
</section>
+ <section>
+ <title>Securing WARs via Keycloak SAML Subsystem</title>
+ <para>
+ You do not have to crack open a WAR to secure it with Keycloak. Alternatively, you can externally secure
+ it via the Keycloak SAML Adapter Subsystem. While you don't have to specify KEYCLOAK-SAML as an <literal>auth-method</literal>,
+ you still have to define the <literal>security-constraints</literal> in <literal>web.xml</literal>. You do
+ not, however, have to create a <literal>WEB-INF/keycloak-saml.xml</literal> file. This metadata is instead defined
+ within XML in your server's <literal>domain.xml</literal> or <literal>standalone.xml</literal> subsystem
+ configuration section.
+ </para>
+ <para>
+ <programlisting><![CDATA[
+<extensions>
+ <extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
+</extensions>
+
+<profile>
+ <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
+ <secure-deployment name="WAR MODULE NAME.war">
+ <SP entityID="APPLICATION URL">
+ ...
+ </SP>
+ </secure-deployment>
+ </subsystem>
+</profile>
+]]>
+ </programlisting>
+ </para>
+ <para>
+ The <literal>secure-deployment</literal> <literal>name</literal> attribute identifies the WAR you want
+ to secure. Its value is the <literal>module-name</literal> defined in <literal>web.xml</literal> with
+ <literal>.war</literal> appended. The rest of the configuration uses the same XML syntax as
+ <literal>keycloak-saml.xml</literal> configuration defined in <link linkend='adapter-config'>general adapter configuration</link>.
+ </para>
+ <para>
+ An example configuration:
+ </para>
+ <para>
+ <programlisting><![CDATA[
+<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
+ <secure-deployment name="saml-post-encryption.war">
+ <SP entityID="http://localhost:8080/sales-post-enc/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+ <Keys>
+ <Key signing="true" encryption="true">
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
+ <Certificate alias="http://localhost:8080/sales-post-enc/"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp">
+ <SingleSignOnService signRequest="true"
+ validateResponseSignature="true"
+ requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+
+ <SingleLogoutService
+ validateRequestSignature="true"
+ validateResponseSignature="true"
+ signRequest="true"
+ signResponse="true"
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+ <Keys>
+ <Key signing="true" >
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <Certificate alias="saml-demo"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ </IDP>
+ </SP>
+ </secure-deployment>
+</subsystem>
+]]>
+ </programlisting>
+ </para>
+ </section>
</chapter>
\ No newline at end of file
pom.xml 6(+3 -3)
diff --git a/pom.xml b/pom.xml
index 62ae25c..b81ec57 100755
--- a/pom.xml
+++ b/pom.xml
@@ -1048,7 +1048,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-wf9-subsystem</artifactId>
+ <artifactId>keycloak-saml-wildfly-subsystem</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@@ -1143,7 +1143,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-wf9-modules</artifactId>
+ <artifactId>keycloak-saml-wildfly-modules</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
@@ -1155,7 +1155,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-wf9-adapter-dist</artifactId>
+ <artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
diff --git a/saml/client-adapter/as7-eap6/adapter/pom.xml b/saml/client-adapter/as7-eap6/adapter/pom.xml
index 6d1ace8..da632c7 100755
--- a/saml/client-adapter/as7-eap6/adapter/pom.xml
+++ b/saml/client-adapter/as7-eap6/adapter/pom.xml
@@ -31,10 +31,6 @@
<artifactId>keycloak-saml-adapter-core</artifactId>
</dependency>
<dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-saml-adapter-core</artifactId>
- </dependency>
- <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
diff --git a/saml/client-adapter/as7-eap6/subsystem/pom.xml b/saml/client-adapter/as7-eap6/subsystem/pom.xml
index fa87dcf..872e5d1 100755
--- a/saml/client-adapter/as7-eap6/subsystem/pom.xml
+++ b/saml/client-adapter/as7-eap6/subsystem/pom.xml
@@ -101,9 +101,9 @@ projects that depend on this project.-->
</dependency>
<dependency>
- <groupId>org.jboss.msc</groupId>
- <artifactId>jboss-msc</artifactId>
- <version>1.0.2.GA</version>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-controller</artifactId>
+ <version>${jboss.version}</version>
</dependency>
<dependency>
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java
new file mode 100644
index 0000000..966cd67
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.Property;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class Configuration {
+
+ static final Configuration INSTANCE = new Configuration();
+
+ private ModelNode config = new ModelNode();
+
+ private Configuration() {
+ }
+
+ void updateModel(ModelNode operation, ModelNode model) {
+ ModelNode node = config;
+ ModelNode addr = operation.get("address");
+ for (Property item : addr.asPropertyList()) {
+ node = getNodeForAddressElement(node, item);
+ }
+ node.set(model);
+ }
+
+ private ModelNode getNodeForAddressElement(ModelNode node, Property item) {
+ String key = item.getValue().asString();
+ ModelNode keymodel = node.get(item.getName());
+ return keymodel.get(key);
+ }
+
+ public ModelNode getSecureDeployment(String name) {
+ ModelNode secureDeployment = config.get("subsystem").get("keycloak-saml").get(Constants.Model.SECURE_DEPLOYMENT);
+ if (secureDeployment.hasDefined(name)) {
+ return secureDeployment.get(name);
+ }
+ return null;
+ }
+
+ public boolean isSecureDeployment(String name) {
+ return getSecureDeployment(name) != null;
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java
new file mode 100644
index 0000000..07af4f7
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class Constants {
+
+ static class Model {
+ static final String SECURE_DEPLOYMENT = "secure-deployment";
+ static final String SERVICE_PROVIDER = "service-provider";
+
+ static final String SSL_POLICY = "ssl-policy";
+ static final String NAME_ID_POLICY_FORMAT = "name-id-policy-format";
+ static final String LOGOUT_PAGE = "logout-page";
+ static final String FORCE_AUTHENTICATION = "force-authentication";
+ static final String ROLE_ATTRIBUTES = "role-attributes";
+ static final String SIGNING = "signing";
+ static final String ENCRYPTION = "encryption";
+ static final String KEY = "key";
+ static final String RESOURCE = "resource";
+ static final String PASSWORD = "password";
+
+ static final String PRIVATE_KEY_ALIAS = "private-key-alias";
+ static final String PRIVATE_KEY_PASSWORD = "private-key-password";
+ static final String CERTIFICATE_ALIAS = "certificate-alias";
+ static final String KEY_STORE = "key-store";
+ static final String SIGN_REQUEST = "sign-request";
+ static final String VALIDATE_RESPONSE_SIGNATURE = "validate-response-signature";
+ static final String REQUEST_BINDING = "request-binding";
+ static final String BINDING_URL = "binding-url";
+ static final String VALIDATE_REQUEST_SIGNATURE = "validate-request-signature";
+ static final String SIGN_RESPONSE = "sign-response";
+ static final String RESPONSE_BINDING = "response-binding";
+ static final String POST_BINDING_URL = "post-binding-url";
+ static final String REDIRECT_BINDING_URL = "redirect-binding-url";
+ static final String SINGLE_SIGN_ON = "single-sign-on";
+ static final String SINGLE_LOGOUT = "single-logout";
+ static final String IDENTITY_PROVIDER = "identity-provider";
+ static final String PRINCIPAL_NAME_MAPPING_POLICY = "principal-name-mapping-policy";
+ static final String PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME = "principal-name-mapping-attribute-name";
+ static final String SIGNATURE_ALGORITHM = "signature-algorithm";
+ static final String SIGNATURE_CANONICALIZATION_METHOD = "signature-canonicalization-method";
+ static final String PRIVATE_KEY_PEM = "private-key-pem";
+ static final String PUBLIC_KEY_PEM = "public-key-pem";
+ static final String CERTIFICATE_PEM = "certificate-pem";
+ static final String TYPE = "type";
+ static final String ALIAS = "alias";
+ static final String FILE = "file";
+ static final String SIGNATURES_REQUIRED = "signatures-required";
+ }
+
+
+ static class XML {
+ static final String SECURE_DEPLOYMENT = "secure-deployment";
+ static final String SERVICE_PROVIDER = "SP";
+
+ static final String NAME = "name";
+ static final String ENTITY_ID = "entityID";
+ static final String SSL_POLICY = "sslPolicy";
+ static final String NAME_ID_POLICY_FORMAT = "nameIDPolicyFormat";
+ static final String LOGOUT_PAGE = "logoutPage";
+ static final String FORCE_AUTHENTICATION = "forceAuthentication";
+ static final String ROLE_IDENTIFIERS = "RoleIdentifiers";
+ static final String SIGNING = "signing";
+ static final String ENCRYPTION = "encryption";
+ static final String KEYS = "Keys";
+ static final String KEY = "Key";
+ static final String RESOURCE = "resource";
+ static final String PASSWORD = "password";
+ static final String KEY_STORE = "KeyStore";
+ static final String PRIVATE_KEY = "PrivateKey";
+ static final String CERTIFICATE = "Certificate";
+
+ static final String PRIVATE_KEY_ALIAS = "alias";
+ static final String PRIVATE_KEY_PASSWORD = "password";
+ static final String CERTIFICATE_ALIAS = "alias";
+ static final String SIGN_REQUEST = "signRequest";
+ static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
+ static final String REQUEST_BINDING = "requestBinding";
+ static final String BINDING_URL = "bindingUrl";
+ static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
+ static final String SIGN_RESPONSE = "signResponse";
+ static final String RESPONSE_BINDING = "responseBinding";
+ static final String POST_BINDING_URL = "postBindingUrl";
+ static final String REDIRECT_BINDING_URL = "redirectBindingUrl";
+ static final String SINGLE_SIGN_ON = "SingleSignOnService";
+ static final String SINGLE_LOGOUT = "SingleLogoutService";
+ static final String IDENTITY_PROVIDER = "IDP";
+ static final String PRINCIPAL_NAME_MAPPING = "PrincipalNameMapping";
+ static final String PRINCIPAL_NAME_MAPPING_POLICY = "policy";
+ static final String PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME = "attribute";
+ static final String ATTRIBUTE = "Attribute";
+ static final String SIGNATURE_ALGORITHM = "signatureAlgorithm";
+ static final String SIGNATURE_CANONICALIZATION_METHOD = "signatureCanonicalizationMethod";
+ static final String PRIVATE_KEY_PEM = "PrivateKeyPem";
+ static final String PUBLIC_KEY_PEM = "PublicKeyPem";
+ static final String CERTIFICATE_PEM = "CertificatePem";
+ static final String TYPE = "type";
+ static final String ALIAS = "alias";
+ static final String FILE = "file";
+ static final String SIGNATURES_REQUIRED = "signaturesRequired";
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderAddHandler.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderAddHandler.java
new file mode 100644
index 0000000..679658b
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderAddHandler.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.ServiceVerificationHandler;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceController;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class IdentityProviderAddHandler extends AbstractAddStepHandler {
+
+ IdentityProviderAddHandler() {
+ super(IdentityProviderDefinition.ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderDefinition.java
new file mode 100644
index 0000000..09262f9
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/IdentityProviderDefinition.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.ObjectTypeAttributeDefinition;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class IdentityProviderDefinition extends SimpleResourceDefinition {
+
+ static final SimpleAttributeDefinition SIGNATURES_REQUIRED =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNATURES_REQUIRED, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGNATURES_REQUIRED)
+ .build();
+
+ static final SimpleAttributeDefinition SIGNATURE_ALGORITHM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNATURE_ALGORITHM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.SIGNATURE_ALGORITHM)
+ .build();
+
+ static final SimpleAttributeDefinition SIGNATURE_CANONICALIZATION_METHOD =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNATURE_CANONICALIZATION_METHOD, ModelType.STRING, true)
+ .setXmlName(Constants.XML.SIGNATURE_CANONICALIZATION_METHOD)
+ .build();
+
+ static final ObjectTypeAttributeDefinition SINGLE_SIGN_ON =
+ ObjectTypeAttributeDefinition.Builder.of(Constants.Model.SINGLE_SIGN_ON,
+ SingleSignOnDefinition.ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final ObjectTypeAttributeDefinition SINGLE_LOGOUT =
+ ObjectTypeAttributeDefinition.Builder.of(Constants.Model.SINGLE_LOGOUT,
+ SingleLogoutDefinition.ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGNATURES_REQUIRED, SIGNATURE_ALGORITHM, SIGNATURE_CANONICALIZATION_METHOD};
+
+ static final SimpleAttributeDefinition[] ALL_ATTRIBUTES = {SIGNATURES_REQUIRED, SIGNATURE_ALGORITHM, SIGNATURE_CANONICALIZATION_METHOD, SINGLE_SIGN_ON, SINGLE_LOGOUT};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static final IdentityProviderDefinition INSTANCE = new IdentityProviderDefinition();
+
+ private IdentityProviderDefinition() {
+ super(PathElement.pathElement(Constants.Model.IDENTITY_PROVIDER),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.IDENTITY_PROVIDER),
+ new IdentityProviderAddHandler(),
+ ReloadRequiredRemoveStepHandler.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);
+
+ final OperationStepHandler writeHandler = new ReloadRequiredWriteAttributeHandler(ALL_ATTRIBUTES);
+ for (AttributeDefinition attribute : ALL_ATTRIBUTES) {
+ resourceRegistration.registerReadWriteAttribute(attribute, null, writeHandler);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
\ No newline at end of file
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyAddHandler.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyAddHandler.java
new file mode 100644
index 0000000..b362d4f
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyAddHandler.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.ServiceVerificationHandler;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceController;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class KeyAddHandler extends AbstractAddStepHandler {
+
+ KeyAddHandler() {
+ super(KeyDefinition.ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java
index 31008d4..68e4679 100755
--- a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java
@@ -21,13 +21,22 @@ 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.web.deployment.WarMetaData;
+import org.jboss.dmr.ModelNode;
import org.jboss.logging.Logger;
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.jboss.ValveMetaData;
import org.jboss.metadata.web.spec.LoginConfigMetaData;
+import org.jboss.staxmapper.XMLExtendedStreamWriter;
+import org.keycloak.adapters.saml.AdapterConstants;
import org.keycloak.adapters.saml.jbossweb.SamlAuthenticatorValve;
+import org.keycloak.subsystem.saml.as7.logging.KeycloakLogger;
+import org.keycloak.subsystem.saml.as7.xml.FormattingXMLStreamWriter;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@@ -39,22 +48,16 @@ import java.util.List;
public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitProcessor {
protected Logger log = Logger.getLogger(KeycloakAdapterConfigDeploymentProcessor.class);
- // 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.saml.adapterConfig";
-
-
@Override
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
String deploymentName = deploymentUnit.getName();
- // if it's not a web-app there's nothing to secure
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
if (warMetaData == null) {
return;
}
+
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
if (webMetaData == null) {
webMetaData = new JBossWebMetaData();
@@ -64,12 +67,66 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
// otherwise
LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
- boolean webRequiresKC = loginConfig != null && "KEYCLOAK-SAML".equalsIgnoreCase(loginConfig.getAuthMethod());
+ try {
+ boolean webRequiresKC = loginConfig != null && "KEYCLOAK-SAML".equalsIgnoreCase(loginConfig.getAuthMethod());
+ boolean hasSubsystemConfig = Configuration.INSTANCE.isSecureDeployment(deploymentName);
+ if (hasSubsystemConfig || webRequiresKC) {
+ log.debug("Setting up KEYCLOAK-SAML auth method for WAR: " + deploymentName);
+
+ // if secure-deployment configuration exists for web app, we force KEYCLOAK-SAML auth method on it
+ if (hasSubsystemConfig) {
+ addXMLData(getXML(deploymentName), warMetaData);
+ if (loginConfig != null) {
+ loginConfig.setAuthMethod("KEYCLOAK-SAML");
+ //loginConfig.setRealmName(service.getRealmName(deploymentName));
+ } else {
+ log.warn("Failed to set up KEYCLOAK-SAML auth method for WAR: " + deploymentName + " (loginConfig == null)");
+ }
+ }
+ addValve(webMetaData);
+ KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
+ }
+ } catch (Exception e) {
+ throw new DeploymentUnitProcessingException("Failed to configure KeycloakSamlExtension from subsystem model", e);
+ }
+ }
+
+ private String getXML(String deploymentName) throws XMLStreamException {
+ ModelNode node = Configuration.INSTANCE.getSecureDeployment(deploymentName);
+ if (node != null) {
+ KeycloakSubsystemParser writer = new KeycloakSubsystemParser();
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ XMLExtendedStreamWriter streamWriter = new FormattingXMLStreamWriter(XMLOutputFactory.newInstance().createXMLStreamWriter(output));
+ try {
+ streamWriter.writeStartElement("keycloak-saml-adapter");
+ writer.writeSps(streamWriter, node);
+ streamWriter.writeEndElement();
+ } finally {
+ streamWriter.close();
+ }
+ return new String(output.toByteArray(), Charset.forName("utf-8"));
+ }
+ return null;
+ }
+
+ private void addXMLData(String xml, WarMetaData warMetaData) {
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ webMetaData = new JBossWebMetaData();
+ warMetaData.setMergedJBossWebMetaData(webMetaData);
+ }
- if (webRequiresKC) {
- log.debug("Setting up KEYCLOAK-SAML auth method for WAR: " + deploymentName);
- addValve(webMetaData);
+ List<ParamValueMetaData> contextParams = webMetaData.getContextParams();
+ if (contextParams == null) {
+ contextParams = new ArrayList<>();
}
+
+ ParamValueMetaData param = new ParamValueMetaData();
+ param.setParamName(AdapterConstants.AUTH_DATA_PARAM_NAME);
+ param.setParamValue(xml);
+ contextParams.add(param);
+
+ webMetaData.setContextParams(contextParams);
}
private void addValve(JBossWebMetaData webMetaData) {
@@ -89,5 +146,4 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
public void undeploy(DeploymentUnit du) {
}
-
}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSamlExtension.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSamlExtension.java
index c52f2b5..d936982 100755
--- a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSamlExtension.java
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSamlExtension.java
@@ -18,6 +18,7 @@ package org.keycloak.subsystem.saml.as7;
import org.jboss.as.controller.Extension;
import org.jboss.as.controller.ExtensionContext;
+import org.jboss.as.controller.ModelVersion;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.ResourceDefinition;
import org.jboss.as.controller.SubsystemRegistration;
@@ -36,15 +37,12 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUB
public class KeycloakSamlExtension implements Extension {
public static final String SUBSYSTEM_NAME = "keycloak-saml";
- public static final String NAMESPACE = "urn:jboss:domain:keycloak-saml:1.6";
+ public static final String NAMESPACE = "urn:jboss:domain:keycloak-saml:1.1";
private static final KeycloakSubsystemParser PARSER = new KeycloakSubsystemParser();
static final PathElement PATH_SUBSYSTEM = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
private static final String RESOURCE_NAME = KeycloakSamlExtension.class.getPackage().getName() + ".LocalDescriptions";
- private static final int MGMT_API_VERSION_MAJOR = 1;
- private static final int MGMT_API_VERSION_MINOR = 1;
-
+ private static final ModelVersion MGMT_API_VERSION = ModelVersion.create(1, 1, 0);
static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
- private static final ResourceDefinition KEYCLOAK_SUBSYSTEM_RESOURCE = new KeycloakSubsystemDefinition();
public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
@@ -67,10 +65,15 @@ public class KeycloakSamlExtension implements Extension {
*/
@Override
public void initialize(final ExtensionContext context) {
- final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, MGMT_API_VERSION_MAJOR, MGMT_API_VERSION_MINOR);
-
- ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
+ final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME,
+ MGMT_API_VERSION.getMajor(), MGMT_API_VERSION.getMinor(), MGMT_API_VERSION.getMicro());
+ ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KeycloakSubsystemDefinition.INSTANCE);
+ ManagementResourceRegistration secureDeploymentRegistration = registration.registerSubModel(SecureDeploymentDefinition.INSTANCE);
+ ManagementResourceRegistration serviceProviderRegistration = secureDeploymentRegistration.registerSubModel(ServiceProviderDefinition.INSTANCE);
+ serviceProviderRegistration.registerSubModel(KeyDefinition.INSTANCE);
+ ManagementResourceRegistration idpRegistration = serviceProviderRegistration.registerSubModel(IdentityProviderDefinition.INSTANCE);
+ idpRegistration.registerSubModel(KeyDefinition.INSTANCE);
subsystem.registerXMLElementWriter(PARSER);
}
}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java
index 2a7fd55..eda678f 100755
--- a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java
@@ -16,13 +16,12 @@
*/
package org.keycloak.subsystem.saml.as7;
-
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.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.Phase;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
@@ -43,17 +42,20 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
context.addStep(new AbstractDeploymentChainStep() {
@Override
protected void execute(DeploymentProcessorTarget processorTarget) {
- processorTarget.addDeploymentProcessor(Phase.DEPENDENCIES, 0, new KeycloakDependencyProcessorAS7());
- processorTarget.addDeploymentProcessor(
+ processorTarget.addDeploymentProcessor(KeycloakSamlExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, 0, chooseDependencyProcessor());
+ processorTarget.addDeploymentProcessor(KeycloakSamlExtension.SUBSYSTEM_NAME,
Phase.POST_MODULE, // PHASE
Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
- new KeycloakAdapterConfigDeploymentProcessor());
+ chooseConfigDeploymentProcessor());
}
}, OperationContext.Stage.RUNTIME);
}
- @Override
- protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
- model.setEmptyObject();
+ private DeploymentUnitProcessor chooseDependencyProcessor() {
+ return new KeycloakDependencyProcessorAS7();
+ }
+
+ private DeploymentUnitProcessor chooseConfigDeploymentProcessor() {
+ return new KeycloakAdapterConfigDeploymentProcessor();
}
}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemDefinition.java
index 400822e..4b7ef3f 100755
--- a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemDefinition.java
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemDefinition.java
@@ -14,23 +14,23 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-
package org.keycloak.subsystem.saml.as7;
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;
-import org.jboss.as.controller.registry.OperationEntry;
/**
- * Definition of subsystem=keycloak.
+ * Definition of subsystem=keycloak-saml.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
- protected KeycloakSubsystemDefinition() {
+
+ static final KeycloakSubsystemDefinition INSTANCE = new KeycloakSubsystemDefinition();
+
+ private KeycloakSubsystemDefinition() {
super(KeycloakSamlExtension.SUBSYSTEM_PATH,
KeycloakSamlExtension.getResourceDescriptionResolver("subsystem"),
KeycloakSubsystemAdd.INSTANCE,
@@ -41,7 +41,6 @@ public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
- resourceRegistration.registerOperationHandler(ModelDescriptionConstants.DESCRIBE, GenericSubsystemDescribeHandler.INSTANCE, GenericSubsystemDescribeHandler.INSTANCE, false, OperationEntry.EntryType.PRIVATE);
+ resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
}
-
}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemParser.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemParser.java
index 14899e1..0b2cef9 100755
--- a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemParser.java
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * Copyright 2015 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
@@ -17,9 +17,14 @@
package org.keycloak.subsystem.saml.as7;
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;
@@ -27,6 +32,10 @@ import org.jboss.staxmapper.XMLExtendedStreamWriter;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -41,10 +50,15 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> list) throws XMLStreamException {
// Require no attributes
ParseUtils.requireNoAttributes(reader);
- ModelNode addKeycloakSub = org.jboss.as.controller.operations.common.Util.createAddOperation(PathAddress.pathAddress(KeycloakSamlExtension.PATH_SUBSYSTEM));
+ ModelNode addKeycloakSub = Util.createAddOperation(PathAddress.pathAddress(KeycloakSamlExtension.PATH_SUBSYSTEM));
list.add(addKeycloakSub);
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ if (reader.getLocalName().equals(Constants.XML.SECURE_DEPLOYMENT)) {
+ readSecureDeployment(reader, list);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
}
}
@@ -53,6 +67,319 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
return reader.nextTag();
}
+ void readSecureDeployment(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
+ String name = readRequiredAttribute(reader, Constants.XML.NAME);
+
+ PathAddress addr = PathAddress.pathAddress(
+ PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakSamlExtension.SUBSYSTEM_NAME),
+ PathElement.pathElement(Constants.Model.SECURE_DEPLOYMENT, name));
+ ModelNode addSecureDeployment = Util.createAddOperation(addr);
+ list.add(addSecureDeployment);
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ if (tagName.equals(Constants.XML.SERVICE_PROVIDER)) {
+ readServiceProvider(reader, list, addr);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readServiceProvider(XMLExtendedStreamReader reader, List<ModelNode> list, PathAddress parentAddr) throws XMLStreamException {
+ String entityId = readRequiredAttribute(reader, Constants.XML.ENTITY_ID);
+
+ PathAddress addr = PathAddress.pathAddress(parentAddr,
+ PathElement.pathElement(Constants.Model.SERVICE_PROVIDER, entityId));
+ ModelNode addServiceProvider = Util.createAddOperation(addr);
+ list.add(addServiceProvider);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ if (Constants.XML.ENTITY_ID.equals(name)) {
+ continue;
+ }
+
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = ServiceProviderDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addServiceProvider, reader);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (Constants.XML.KEYS.equals(tagName)) {
+ readKeys(list, reader, addr);
+ } else if (Constants.XML.PRINCIPAL_NAME_MAPPING.equals(tagName)) {
+ readPrincipalNameMapping(addServiceProvider, reader);
+ } else if (Constants.XML.ROLE_IDENTIFIERS.equals(tagName)) {
+ readRoleIdentifiers(addServiceProvider, reader);
+ } else if (Constants.XML.IDENTITY_PROVIDER.equals(tagName)) {
+ readIdentityProvider(list, reader, addr);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readIdentityProvider(List<ModelNode> list, XMLExtendedStreamReader reader, PathAddress parentAddr) throws XMLStreamException {
+ String entityId = readRequiredAttribute(reader, Constants.XML.ENTITY_ID);
+
+ PathAddress addr = PathAddress.pathAddress(parentAddr,
+ PathElement.pathElement(Constants.Model.IDENTITY_PROVIDER, entityId));
+ ModelNode addIdentityProvider = Util.createAddOperation(addr);
+ list.add(addIdentityProvider);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ if (Constants.XML.ENTITY_ID.equals(name)
+ // don't break if encountering this noop attr from client-adapter/core keycloak_saml_adapter_1_6.xsd
+ || "encryption".equals(name)) {
+ continue;
+ }
+ SimpleAttributeDefinition attr = IdentityProviderDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addIdentityProvider, reader);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (Constants.XML.SINGLE_SIGN_ON.equals(tagName)) {
+ readSingleSignOn(addIdentityProvider, reader);
+ } else if (Constants.XML.SINGLE_LOGOUT.equals(tagName)) {
+ readSingleLogout(addIdentityProvider, reader);
+ } else if (Constants.XML.KEYS.equals(tagName)) {
+ readKeys(list, reader, addr);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readSingleSignOn(ModelNode addIdentityProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ModelNode sso = addIdentityProvider.get(Constants.Model.SINGLE_SIGN_ON);
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = SingleSignOnDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, sso, reader);
+ }
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readSingleLogout(ModelNode addIdentityProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ModelNode slo = addIdentityProvider.get(Constants.Model.SINGLE_LOGOUT);
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = SingleLogoutDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, slo, reader);
+ }
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readKeys(List<ModelNode> list, XMLExtendedStreamReader reader, PathAddress parentAddr) throws XMLStreamException {
+ ParseUtils.requireNoAttributes(reader);
+ List<ModelNode> keyList = new LinkedList<>();
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ if (!Constants.XML.KEY.equals(tagName)) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ readKey(keyList, reader, parentAddr);
+ }
+ list.addAll(keyList);
+ }
+
+ void readKey(List<ModelNode> list, XMLExtendedStreamReader reader, PathAddress parentAddr) throws XMLStreamException {
+ PathAddress addr = PathAddress.pathAddress(parentAddr,
+ PathElement.pathElement(Constants.Model.KEY, "key-" + list.size()));
+ ModelNode addKey = Util.createAddOperation(addr);
+ list.add(addKey);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKey, reader);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (Constants.XML.KEY_STORE.equals(tagName)) {
+ readKeyStore(addKey, reader);
+ } else if (Constants.XML.PRIVATE_KEY_PEM.equals(tagName)
+ || Constants.XML.PUBLIC_KEY_PEM.equals(tagName)
+ || Constants.XML.CERTIFICATE_PEM.equals(tagName)) {
+
+ readNoAttrElementContent(KeyDefinition.lookupElement(tagName), addKey, reader);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readNoAttrElementContent(SimpleAttributeDefinition attr, ModelNode model, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ParseUtils.requireNoAttributes(reader);
+ String value = reader.getElementText();
+ attr.parseAndSetParameter(value, model, reader);
+ }
+
+ void readKeyStore(ModelNode addKey, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ModelNode addKeyStore = addKey.get(Constants.Model.KEY_STORE);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyStoreDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKeyStore, reader);
+ }
+
+ if (!addKeyStore.hasDefined(Constants.Model.FILE) && !addKeyStore.hasDefined(Constants.Model.RESOURCE)) {
+ throw new XMLStreamException("KeyStore element must have 'file' or 'resource' attribute set", reader.getLocation());
+ }
+ if (!addKeyStore.hasDefined(Constants.Model.PASSWORD)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PASSWORD);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ if (Constants.XML.PRIVATE_KEY.equals(tagName)) {
+ readPrivateKey(reader, addKeyStore);
+ } else if (Constants.XML.CERTIFICATE.equals(tagName)) {
+ readCertificate(reader, addKeyStore);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+
+ void readPrivateKey(XMLExtendedStreamReader reader, ModelNode addKeyStore) throws XMLStreamException {
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyStorePrivateKeyDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKeyStore, reader);
+ }
+
+ if (!addKeyStore.hasDefined(Constants.Model.PRIVATE_KEY_ALIAS)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PRIVATE_KEY_ALIAS);
+ }
+ if (!addKeyStore.hasDefined(Constants.Model.PRIVATE_KEY_PASSWORD)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PRIVATE_KEY_PASSWORD);
+ }
+
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readCertificate(XMLExtendedStreamReader reader, ModelNode addKeyStore) throws XMLStreamException {
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyStoreCertificateDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKeyStore, reader);
+ }
+
+ if (!addKeyStore.hasDefined(Constants.Model.CERTIFICATE_ALIAS)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.CERTIFICATE_ALIAS);
+ }
+
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readRoleIdentifiers(ModelNode addServiceProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ParseUtils.requireNoAttributes(reader);
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (!Constants.XML.ATTRIBUTE.equals(tagName)) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+
+ ParseUtils.requireSingleAttribute(reader, Constants.XML.NAME);
+ String name = ParseUtils.readStringAttributeElement(reader, Constants.XML.NAME);
+
+ ServiceProviderDefinition.ROLE_ATTRIBUTES.parseAndAddParameterElement(name, addServiceProvider, reader);
+ }
+ }
+
+ void readPrincipalNameMapping(ModelNode addServiceProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+
+ boolean policySet = false;
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ if (Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY.equals(name)) {
+ policySet = true;
+ ServiceProviderDefinition.PRINCIPAL_NAME_MAPPING_POLICY.parseAndSetParameter(value, addServiceProvider, reader);
+ } else if (Constants.XML.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME.equals(name)) {
+ ServiceProviderDefinition.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME.parseAndSetParameter(value, addServiceProvider, reader);
+ } else {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ }
+
+ if (!policySet) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY);
+ }
+ ParseUtils.requireNoContent(reader);
+ }
+
+ /**
+ * Read an attribute, and throw exception if attribute is not present
+ */
+ String readRequiredAttribute(XMLExtendedStreamReader reader, String attrName) throws XMLStreamException {
+ String value = null;
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String attr = reader.getAttributeLocalName(i);
+ if (attr.equals(attrName)) {
+ value = reader.getAttributeValue(i);
+ break;
+ }
+ }
+ if (value == null) {
+ throw ParseUtils.missingRequired(reader, Collections.singleton(attrName));
+ }
+ return value;
+ }
/**
* {@inheritDoc}
@@ -60,8 +387,183 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
@Override
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
context.startSubsystemElement(KeycloakSamlExtension.NAMESPACE, false);
+ writeSecureDeployment(writer, context.getModelNode());
+ writer.writeEndElement();
+ }
+
+ public void writeSecureDeployment(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.get(Constants.Model.SECURE_DEPLOYMENT).isDefined()) {
+ return;
+ }
+
+ for (Property sp : model.get(Constants.Model.SECURE_DEPLOYMENT).asPropertyList()) {
+ writer.writeStartElement(Constants.XML.SECURE_DEPLOYMENT);
+ writer.writeAttribute(Constants.XML.NAME, sp.getName());
+
+ writeSps(writer, sp.getValue());
+ writer.writeEndElement();
+ }
+ }
+
+ void writeSps(final XMLExtendedStreamWriter writer, final ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ for (Property sp : model.get(Constants.Model.SERVICE_PROVIDER).asPropertyList()) {
+ writer.writeStartElement(Constants.XML.SERVICE_PROVIDER);
+ writer.writeAttribute(Constants.XML.ENTITY_ID, sp.getName());
+ ModelNode spAttributes = sp.getValue();
+ for (SimpleAttributeDefinition attr : ServiceProviderDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, spAttributes, false, writer);
+ }
+ writeKeys(writer, spAttributes.get(Constants.Model.KEY));
+ writePrincipalNameMapping(writer, spAttributes);
+ writeRoleIdentifiers(writer, spAttributes);
+ writeIdentityProvider(writer, spAttributes.get(Constants.Model.IDENTITY_PROVIDER));
+
+ writer.writeEndElement();
+ }
+ }
+
+ void writeIdentityProvider(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+
+ for (Property idp : model.asPropertyList()) {
+ writer.writeStartElement(Constants.XML.IDENTITY_PROVIDER);
+ writer.writeAttribute(Constants.XML.ENTITY_ID, idp.getName());
+
+ ModelNode idpAttributes = idp.getValue();
+ for (SimpleAttributeDefinition attr : IdentityProviderDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, idpAttributes, false, writer);
+ }
+
+ writeSingleSignOn(writer, idpAttributes.get(Constants.Model.SINGLE_SIGN_ON));
+ writeSingleLogout(writer, idpAttributes.get(Constants.Model.SINGLE_LOGOUT));
+ writeKeys(writer, idpAttributes.get(Constants.Model.KEY));
+ }
+ writer.writeEndElement();
+ }
+
+ void writeSingleSignOn(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.SINGLE_SIGN_ON);
+ for (SimpleAttributeDefinition attr : SingleSignOnDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
writer.writeEndElement();
}
+ void writeSingleLogout(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.SINGLE_LOGOUT);
+ for (SimpleAttributeDefinition attr : SingleLogoutDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ void writeKeys(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ boolean contains = false;
+ for (Property key : model.asPropertyList()) {
+ if (!contains) {
+ writer.writeStartElement(Constants.XML.KEYS);
+ contains = true;
+ }
+ writer.writeStartElement(Constants.XML.KEY);
+ ModelNode keyAttributes = key.getValue();
+ for (SimpleAttributeDefinition attr : KeyDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, keyAttributes, false, writer);
+ }
+ for (SimpleAttributeDefinition attr : KeyDefinition.ELEMENTS) {
+ attr.getAttributeMarshaller().marshallAsElement(attr, keyAttributes, false, writer);
+ }
+ writeKeyStore(writer, keyAttributes.get(Constants.Model.KEY_STORE));
+
+ writer.writeEndElement();
+ }
+ if (contains) {
+ writer.writeEndElement();
+ }
+ }
+
+ void writeKeyStore(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.KEY_STORE);
+ for (SimpleAttributeDefinition attr : KeyStoreDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
+ writePrivateKey(writer, model);
+ writeCertificate(writer, model);
+ writer.writeEndElement();
+ }
+
+ void writeCertificate(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ ModelNode value = model.get(Constants.Model.CERTIFICATE_ALIAS);
+ if (!value.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.CERTIFICATE);
+ SimpleAttributeDefinition attr = KeyStoreCertificateDefinition.CERTIFICATE_ALIAS;
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ writer.writeEndElement();
+ }
+
+ void writePrivateKey(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ ModelNode pk_alias = model.get(Constants.Model.PRIVATE_KEY_ALIAS);
+ ModelNode pk_password = model.get(Constants.Model.PRIVATE_KEY_PASSWORD);
+
+ if (!pk_alias.isDefined() && !pk_password.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.PRIVATE_KEY);
+ for (SimpleAttributeDefinition attr : KeyStorePrivateKeyDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ void writeRoleIdentifiers(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ ModelNode value = model.get(Constants.Model.ROLE_ATTRIBUTES);
+ if (!value.isDefined()) {
+ return;
+ }
+
+ List<ModelNode> items = value.asList();
+ if (items.size() == 0) {
+ return;
+ }
+
+ writer.writeStartElement(Constants.XML.ROLE_IDENTIFIERS);
+ for (ModelNode item : items) {
+ writer.writeStartElement(Constants.XML.ATTRIBUTE);
+ writer.writeAttribute("name", item.asString());
+ writer.writeEndElement();
+ }
+ writer.writeEndElement();
+ }
+
+ void writePrincipalNameMapping(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ writer.writeStartElement(Constants.XML.PRINCIPAL_NAME_MAPPING);
+ ModelNode value = model.get(Constants.Model.PRINCIPAL_NAME_MAPPING_POLICY);
+ if (value.isDefined()) {
+ writer.writeAttribute(Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY, value.asString());
+ }
+ value = model.get(Constants.Model.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME);
+ if (value.isDefined()) {
+ writer.writeAttribute(Constants.XML.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME, value.asString());
+ }
+ writer.writeEndElement();
+ }
}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyDefinition.java
new file mode 100644
index 0000000..0f76399
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyDefinition.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.ObjectTypeAttributeDefinition;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class KeyDefinition extends SimpleResourceDefinition {
+
+ static final SimpleAttributeDefinition SIGNING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNING, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGNING)
+ .build();
+
+ static final SimpleAttributeDefinition ENCRYPTION =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.ENCRYPTION, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.ENCRYPTION)
+ .build();
+
+ static final SimpleAttributeDefinition PRIVATE_KEY_PEM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRIVATE_KEY_PEM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRIVATE_KEY_PEM)
+ .build();
+
+ static final SimpleAttributeDefinition PUBLIC_KEY_PEM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PUBLIC_KEY_PEM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PUBLIC_KEY_PEM)
+ .build();
+
+ static final SimpleAttributeDefinition CERTIFICATE_PEM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.CERTIFICATE_PEM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.CERTIFICATE_PEM)
+ .build();
+
+ static final ObjectTypeAttributeDefinition KEY_STORE =
+ ObjectTypeAttributeDefinition.Builder.of(Constants.Model.KEY_STORE,
+ KeyStoreDefinition.ALL_ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGNING, ENCRYPTION};
+ static final SimpleAttributeDefinition[] ELEMENTS = {PRIVATE_KEY_PEM, PUBLIC_KEY_PEM, CERTIFICATE_PEM};
+ static final AttributeDefinition[] ALL_ATTRIBUTES = {SIGNING, ENCRYPTION, PRIVATE_KEY_PEM, PUBLIC_KEY_PEM, CERTIFICATE_PEM, KEY_STORE};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static final HashMap<String, SimpleAttributeDefinition> ELEMENT_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ELEMENTS) {
+ ELEMENT_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static final KeyDefinition INSTANCE = new KeyDefinition();
+
+ private KeyDefinition() {
+ super(PathElement.pathElement(Constants.Model.KEY),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.KEY),
+ new KeyAddHandler(),
+ ReloadRequiredRemoveStepHandler.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);
+
+ final OperationStepHandler writeHandler = new ReloadRequiredWriteAttributeHandler(ALL_ATTRIBUTES);
+ for (AttributeDefinition attribute : ALL_ATTRIBUTES) {
+ resourceRegistration.registerReadWriteAttribute(attribute, null, writeHandler);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+
+ static SimpleAttributeDefinition lookupElement(String xmlName) {
+ return ELEMENT_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreCertificateDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreCertificateDefinition.java
new file mode 100644
index 0000000..7ae2ff1
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreCertificateDefinition.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class KeyStoreCertificateDefinition {
+
+ static final SimpleAttributeDefinition CERTIFICATE_ALIAS =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.CERTIFICATE_ALIAS, ModelType.STRING, true)
+ .setXmlName(Constants.XML.CERTIFICATE_ALIAS)
+ .build();
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return Constants.XML.CERTIFICATE_ALIAS.equals(xmlName) ? CERTIFICATE_ALIAS : null;
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreDefinition.java
new file mode 100644
index 0000000..2fb14f5
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStoreDefinition.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+abstract class KeyStoreDefinition {
+
+ static final SimpleAttributeDefinition RESOURCE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.RESOURCE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.RESOURCE)
+ .build();
+
+ static final SimpleAttributeDefinition PASSWORD =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PASSWORD, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PASSWORD)
+ .build();
+
+ static final SimpleAttributeDefinition FILE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.FILE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.FILE)
+ .build();
+
+ static final SimpleAttributeDefinition TYPE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.TYPE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.TYPE)
+ .build();
+
+ static final SimpleAttributeDefinition ALIAS =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.ALIAS, ModelType.STRING, true)
+ .setXmlName(Constants.XML.ALIAS)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {RESOURCE, PASSWORD, FILE, TYPE, ALIAS};
+ static final SimpleAttributeDefinition[] ALL_ATTRIBUTES = {RESOURCE, PASSWORD, FILE, TYPE, ALIAS,
+ KeyStorePrivateKeyDefinition.PRIVATE_KEY_ALIAS,
+ KeyStorePrivateKeyDefinition.PRIVATE_KEY_PASSWORD,
+ KeyStoreCertificateDefinition.CERTIFICATE_ALIAS
+ };
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStorePrivateKeyDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStorePrivateKeyDefinition.java
new file mode 100644
index 0000000..1947ca9
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeyStorePrivateKeyDefinition.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class KeyStorePrivateKeyDefinition {
+ static final SimpleAttributeDefinition PRIVATE_KEY_ALIAS =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRIVATE_KEY_ALIAS, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRIVATE_KEY_ALIAS)
+ .build();
+
+ static final SimpleAttributeDefinition PRIVATE_KEY_PASSWORD =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRIVATE_KEY_PASSWORD, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRIVATE_KEY_PASSWORD)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {PRIVATE_KEY_ALIAS, PRIVATE_KEY_PASSWORD};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakLogger.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakLogger.java
new file mode 100755
index 0000000..8bd7ac1
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakLogger.java
@@ -0,0 +1,49 @@
+/*
+ * 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.saml.as7.logging;
+
+import org.jboss.logging.BasicLogger;
+import org.jboss.logging.LogMessage;
+import org.jboss.logging.Logger;
+import org.jboss.logging.Message;
+import org.jboss.logging.MessageLogger;
+
+import static org.jboss.logging.Logger.Level.DEBUG;
+import static org.jboss.logging.Logger.Level.INFO;
+
+/**
+ * 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 = INFO)
+ @Message(value = "Keycloak SAML subsystem override for deployment %s")
+ void deploymentSecured(String deployment);
+
+ @LogMessage(level = DEBUG)
+ @Message(value = "Keycloak SAML has overriden and secured deployment %s")
+ void warSecured(String deployment);
+
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakMessages.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakMessages.java
new file mode 100755
index 0000000..f4917b1
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/logging/KeycloakMessages.java
@@ -0,0 +1,34 @@
+/*
+ * 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.saml.as7.logging;
+
+import org.jboss.logging.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);
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentAddHandler.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentAddHandler.java
new file mode 100644
index 0000000..c5325f6
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentAddHandler.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.ServiceVerificationHandler;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceController;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class SecureDeploymentAddHandler extends AbstractAddStepHandler {
+
+ static SecureDeploymentAddHandler INSTANCE = new SecureDeploymentAddHandler();
+
+ private SecureDeploymentAddHandler() {
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentDefinition.java
new file mode 100644
index 0000000..75f4dca
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SecureDeploymentDefinition.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+
+/**
+ * Defines attributes and operations for a secure-deployment.
+ */
+public class SecureDeploymentDefinition extends SimpleResourceDefinition {
+
+ static final SecureDeploymentDefinition INSTANCE = new SecureDeploymentDefinition();
+
+ private SecureDeploymentDefinition() {
+ super(PathElement.pathElement(Constants.Model.SECURE_DEPLOYMENT),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.SECURE_DEPLOYMENT),
+ SecureDeploymentAddHandler.INSTANCE,
+ ReloadRequiredRemoveStepHandler.INSTANCE);
+ }
+
+ @Override
+ public void registerOperations(ManagementResourceRegistration resourceRegistration) {
+ super.registerOperations(resourceRegistration);
+ resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderAddHandler.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderAddHandler.java
new file mode 100644
index 0000000..33d6015
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderAddHandler.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.ServiceVerificationHandler;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceController;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class ServiceProviderAddHandler extends AbstractAddStepHandler {
+
+ static final ServiceProviderAddHandler INSTANCE = new ServiceProviderAddHandler();
+
+ ServiceProviderAddHandler() {
+ super(ServiceProviderDefinition.ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderDefinition.java
new file mode 100644
index 0000000..02ecc8f
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/ServiceProviderDefinition.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.ListAttributeDefinition;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.StringListAttributeDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelType;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class ServiceProviderDefinition extends SimpleResourceDefinition {
+
+ static final SimpleAttributeDefinition SSL_POLICY =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SSL_POLICY, ModelType.STRING, true)
+ .setXmlName(Constants.XML.SSL_POLICY)
+ .build();
+
+ static final SimpleAttributeDefinition NAME_ID_POLICY_FORMAT =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.NAME_ID_POLICY_FORMAT, ModelType.STRING, true)
+ .setXmlName(Constants.XML.NAME_ID_POLICY_FORMAT)
+ .build();
+
+ static final SimpleAttributeDefinition LOGOUT_PAGE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.LOGOUT_PAGE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.LOGOUT_PAGE)
+ .build();
+
+ static final SimpleAttributeDefinition FORCE_AUTHENTICATION =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.FORCE_AUTHENTICATION, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.FORCE_AUTHENTICATION)
+ .build();
+
+ static final SimpleAttributeDefinition PRINCIPAL_NAME_MAPPING_POLICY =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRINCIPAL_NAME_MAPPING_POLICY, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY)
+ .build();
+
+ static final SimpleAttributeDefinition PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME)
+ .build();
+
+ static final ListAttributeDefinition ROLE_ATTRIBUTES =
+ new StringListAttributeDefinition.Builder(Constants.Model.ROLE_ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SSL_POLICY, NAME_ID_POLICY_FORMAT, LOGOUT_PAGE, FORCE_AUTHENTICATION};
+ static final AttributeDefinition[] ELEMENTS = {PRINCIPAL_NAME_MAPPING_POLICY, PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME, ROLE_ATTRIBUTES};
+
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+ static final HashMap<String, AttributeDefinition> ALL_MAP = new HashMap<>();
+ static final Collection<AttributeDefinition> ALL_ATTRIBUTES;
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+
+ ALL_MAP.putAll(ATTRIBUTE_MAP);
+ for (AttributeDefinition def : ELEMENTS) {
+ ALL_MAP.put(def.getXmlName(), def);
+ }
+ ALL_ATTRIBUTES = Collections.unmodifiableCollection(ALL_MAP.values());
+ }
+
+ static final ServiceProviderDefinition INSTANCE = new ServiceProviderDefinition();
+
+ private ServiceProviderDefinition() {
+ super(PathElement.pathElement(Constants.Model.SERVICE_PROVIDER),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.SERVICE_PROVIDER),
+ ServiceProviderAddHandler.INSTANCE,
+ ReloadRequiredRemoveStepHandler.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);
+
+ final OperationStepHandler writeHandler = new ReloadRequiredWriteAttributeHandler(ALL_ATTRIBUTES);
+ for (AttributeDefinition attribute : ALL_ATTRIBUTES) {
+ resourceRegistration.registerReadWriteAttribute(attribute, null, writeHandler);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleLogoutDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleLogoutDefinition.java
new file mode 100644
index 0000000..beb884c
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleLogoutDefinition.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+abstract class SingleLogoutDefinition {
+
+ static final SimpleAttributeDefinition VALIDATE_REQUEST_SIGNATURE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_REQUEST_SIGNATURE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.VALIDATE_REQUEST_SIGNATURE)
+ .build();
+
+ static final SimpleAttributeDefinition VALIDATE_RESPONSE_SIGNATURE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_RESPONSE_SIGNATURE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
+ .build();
+
+ static final SimpleAttributeDefinition SIGN_REQUEST =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGN_REQUEST, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGN_REQUEST)
+ .build();
+
+ static final SimpleAttributeDefinition SIGN_RESPONSE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGN_RESPONSE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGN_RESPONSE)
+ .build();
+
+ static final SimpleAttributeDefinition REQUEST_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.REQUEST_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition RESPONSE_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.RESPONSE_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.RESPONSE_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition POST_BINDING_URL =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.POST_BINDING_URL, ModelType.STRING, true)
+ .setXmlName(Constants.XML.POST_BINDING_URL)
+ .build();
+
+ static final SimpleAttributeDefinition REDIRECT_BINDING_URL =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.REDIRECT_BINDING_URL, ModelType.STRING, true)
+ .setXmlName(Constants.XML.REDIRECT_BINDING_URL)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {VALIDATE_REQUEST_SIGNATURE, VALIDATE_RESPONSE_SIGNATURE,
+ SIGN_REQUEST, SIGN_RESPONSE, REQUEST_BINDING, RESPONSE_BINDING, POST_BINDING_URL, REDIRECT_BINDING_URL};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java
new file mode 100644
index 0000000..827be9b
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 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.saml.as7;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+abstract class SingleSignOnDefinition {
+
+ static final SimpleAttributeDefinition SIGN_REQUEST =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGN_REQUEST, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGN_REQUEST)
+ .build();
+
+ static final SimpleAttributeDefinition VALIDATE_RESPONSE_SIGNATURE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_RESPONSE_SIGNATURE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
+ .build();
+
+ static final SimpleAttributeDefinition REQUEST_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.REQUEST_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition RESPONSE_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.RESPONSE_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.RESPONSE_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition BINDING_URL =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.BINDING_URL, ModelType.STRING, true)
+ .setXmlName(Constants.XML.BINDING_URL)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/FormattingXMLStreamWriter.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/FormattingXMLStreamWriter.java
new file mode 100644
index 0000000..dda3ed3
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/FormattingXMLStreamWriter.java
@@ -0,0 +1,534 @@
+/*
+ * 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.
+ */
+
+package org.keycloak.subsystem.saml.as7.xml;
+
+import org.jboss.staxmapper.XMLExtendedStreamWriter;
+
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.ArrayDeque;
+import java.util.Iterator;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ * An XML stream writer which nicely formats the XML for configuration files.
+ *
+ * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
+ */
+public final class FormattingXMLStreamWriter implements XMLExtendedStreamWriter, XMLStreamConstants {
+ private static final String NO_NAMESPACE = new String();
+ private final XMLStreamWriter delegate;
+ private final ArrayDeque<ArgRunnable> attrQueue = new ArrayDeque<ArgRunnable>();
+ private int level;
+ private int state = START_DOCUMENT;
+ private boolean indentEndElement = false;
+ private ArrayDeque<String> unspecifiedNamespaces = new ArrayDeque<String>();
+
+
+ public FormattingXMLStreamWriter(final XMLStreamWriter delegate) {
+ this.delegate = delegate;
+ unspecifiedNamespaces.push(NO_NAMESPACE);
+ }
+
+ private void nl() throws XMLStreamException {
+ delegate.writeCharacters("\n");
+ }
+
+ private void indent() throws XMLStreamException {
+ int level = this.level;
+ final XMLStreamWriter delegate = this.delegate;
+ for (int i = 0; i < level; i ++) {
+ delegate.writeCharacters(" ");
+ }
+ }
+
+ private interface ArgRunnable {
+ public void run(int arg) throws XMLStreamException;
+ }
+
+ @Override
+ public void setUnspecifiedElementNamespace(final String namespace) {
+ ArrayDeque<String> namespaces = this.unspecifiedNamespaces;
+ namespaces.pop();
+ namespaces.push(namespace == null ? NO_NAMESPACE : namespace);
+ }
+
+ private String nestUnspecifiedNamespace() {
+ ArrayDeque<String> namespaces = unspecifiedNamespaces;
+ String clone = namespaces.getFirst();
+ namespaces.push(clone);
+ return clone;
+ }
+
+ @Override
+ public void writeStartElement(final String localName) throws XMLStreamException {
+ ArrayDeque<String> namespaces = unspecifiedNamespaces;
+ String namespace = namespaces.getFirst();
+ if (namespace != NO_NAMESPACE) {
+ writeStartElement(namespace, localName);
+ return;
+ }
+
+ unspecifiedNamespaces.push(namespace);
+
+ // If this is a nested element flush the outer
+ runAttrQueue();
+ nl();
+ indent();
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ if (arg == 0) {
+ delegate.writeStartElement(localName);
+ } else {
+ delegate.writeEmptyElement(localName);
+ }
+ }
+ });
+
+ level++;
+ state = START_ELEMENT;
+ indentEndElement = false;
+ }
+
+ @Override
+ public void writeStartElement(final String namespaceURI, final String localName) throws XMLStreamException {
+ nestUnspecifiedNamespace();
+
+ // If this is a nested element flush the outer
+ runAttrQueue();
+ nl();
+ indent();
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ if (arg == 0) {
+ delegate.writeStartElement(namespaceURI, localName);
+ } else {
+ delegate.writeEmptyElement(namespaceURI, localName);
+ }
+ }
+ });
+ level++;
+ state = START_ELEMENT;
+ indentEndElement = false;
+ }
+
+ @Override
+ public void writeStartElement(final String prefix, final String localName, final String namespaceURI) throws XMLStreamException {
+ nestUnspecifiedNamespace();
+
+ // If this is a nested element flush the outer
+ runAttrQueue();
+ nl();
+ indent();
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ if (arg == 0) {
+ delegate.writeStartElement(prefix, namespaceURI, localName);
+ } else {
+ delegate.writeEmptyElement(prefix, namespaceURI, localName);
+ }
+ }
+ });
+ level++;
+ state = START_ELEMENT;
+ indentEndElement = false;
+ }
+
+ @Override
+ public void writeEmptyElement(final String namespaceURI, final String localName) throws XMLStreamException {
+ runAttrQueue();
+ nl();
+ indent();
+ delegate.writeEmptyElement(namespaceURI, localName);
+ state = END_ELEMENT;
+ }
+
+ @Override
+ public void writeEmptyElement(final String prefix, final String localName, final String namespaceURI) throws XMLStreamException {
+ runAttrQueue();
+ nl();
+ indent();
+ delegate.writeEmptyElement(prefix, namespaceURI, localName);
+ state = END_ELEMENT;
+ }
+
+ @Override
+ public void writeEmptyElement(final String localName) throws XMLStreamException {
+ String namespace = unspecifiedNamespaces.getFirst();
+ if (namespace != NO_NAMESPACE) {
+ writeEmptyElement(namespace, localName);
+ return;
+ }
+
+ runAttrQueue();
+ nl();
+ indent();
+ delegate.writeEmptyElement(localName);
+ state = END_ELEMENT;
+ }
+
+ @Override
+ public void writeEndElement() throws XMLStreamException {
+ level--;
+ if (state != START_ELEMENT) {
+ runAttrQueue();
+ if (state != CHARACTERS || indentEndElement) {
+ nl();
+ indent();
+ indentEndElement = false;
+ }
+ delegate.writeEndElement();
+ } else {
+ // Change the start element to an empty element
+ ArgRunnable start = attrQueue.poll();
+ if (start == null) {
+ delegate.writeEndElement();
+ } else {
+ start.run(1);
+ // Write everything else
+ runAttrQueue();
+ }
+ }
+
+ unspecifiedNamespaces.pop();
+ state = END_ELEMENT;
+ }
+
+ private void runAttrQueue() throws XMLStreamException {
+ ArgRunnable attr;
+ while ((attr = attrQueue.poll()) != null) {
+ attr.run(0);
+ }
+ }
+
+ @Override
+ public void writeEndDocument() throws XMLStreamException {
+ delegate.writeEndDocument();
+ state = END_DOCUMENT;
+ }
+
+ @Override
+ public void close() throws XMLStreamException {
+ delegate.close();
+ state = END_DOCUMENT;
+ }
+
+ @Override
+ public void flush() throws XMLStreamException {
+ delegate.flush();
+ }
+
+ @Override
+ public void writeAttribute(final String localName, final String value) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ try {
+ delegate.writeAttribute(localName, value);
+ } catch (XMLStreamException e) {
+ throw new UndeclaredThrowableException(e);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String prefix, final String namespaceURI, final String localName, final String value) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(prefix, namespaceURI, localName, value);
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String namespaceURI, final String localName, final String value) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(namespaceURI, localName, value);
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String localName, final String[] values) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(localName, join(values));
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String prefix, final String namespaceURI, final String localName, final String[] values) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(prefix, namespaceURI, localName, join(values));
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String namespaceURI, final String localName, final String[] values) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(namespaceURI, localName, join(values));
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String localName, final Iterable<String> values) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(localName, join(values));
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String prefix, final String namespaceURI, final String localName, final Iterable<String> values) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(prefix, namespaceURI, localName, join(values));
+ }
+ });
+ }
+
+ @Override
+ public void writeAttribute(final String namespaceURI, final String localName, final Iterable<String> values) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeAttribute(namespaceURI, localName, join(values));
+ }
+ });
+ }
+
+ @Override
+ public void writeNamespace(final String prefix, final String namespaceURI) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeNamespace(prefix, namespaceURI);
+ }
+ });
+ }
+
+ @Override
+ public void writeDefaultNamespace(final String namespaceURI) throws XMLStreamException {
+ attrQueue.add(new ArgRunnable() {
+ public void run(int arg) throws XMLStreamException {
+ delegate.writeDefaultNamespace(namespaceURI);
+ }
+ });
+ }
+
+ @Override
+ public void writeComment(final String data) throws XMLStreamException {
+ runAttrQueue();
+ nl();
+ nl();
+ indent();
+ final StringBuilder b = new StringBuilder(data.length());
+ final Iterator<String> i = Spliterator.over(data, '\n');
+ if (! i.hasNext()) {
+ return;
+ } else {
+ final String first = i.next();
+ if (! i.hasNext()) {
+ delegate.writeComment(" " + first + " ");
+ state = COMMENT;
+ return;
+ } else {
+ b.append('\n');
+ for (int q = 0; q < level; q++) {
+ b.append(" ");
+ }
+ b.append(" ~ ");
+ b.append(first);
+ do {
+ b.append('\n');
+ for (int q = 0; q < level; q++) {
+ b.append(" ");
+ }
+ b.append(" ~ ");
+ b.append(i.next());
+ } while (i.hasNext());
+ }
+ b.append('\n');
+ for (int q = 0; q < level; q ++) {
+ b.append(" ");
+ }
+ b.append(" ");
+ delegate.writeComment(b.toString());
+ state = COMMENT;
+ }
+ }
+
+ @Override
+ public void writeProcessingInstruction(final String target) throws XMLStreamException {
+ runAttrQueue();
+ nl();
+ indent();
+ delegate.writeProcessingInstruction(target);
+ state = PROCESSING_INSTRUCTION;
+ }
+
+ @Override
+ public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException {
+ runAttrQueue();
+ nl();
+ indent();
+ delegate.writeProcessingInstruction(target, data);
+ state = PROCESSING_INSTRUCTION;
+ }
+
+ @Override
+ public void writeCData(final String data) throws XMLStreamException {
+ runAttrQueue();
+ delegate.writeCData(data);
+ state = CDATA;
+ }
+
+ @Override
+ public void writeDTD(final String dtd) throws XMLStreamException {
+ nl();
+ indent();
+ delegate.writeDTD(dtd);
+ state = DTD;
+ }
+
+ @Override
+ public void writeEntityRef(final String name) throws XMLStreamException {
+ runAttrQueue();
+ delegate.writeEntityRef(name);
+ state = ENTITY_REFERENCE;
+ }
+
+ @Override
+ public void writeStartDocument() throws XMLStreamException {
+ delegate.writeStartDocument();
+ nl();
+ state = START_DOCUMENT;
+ }
+
+ @Override
+ public void writeStartDocument(final String version) throws XMLStreamException {
+ delegate.writeStartDocument(version);
+ nl();
+ state = START_DOCUMENT;
+ }
+
+ @Override
+ public void writeStartDocument(final String encoding, final String version) throws XMLStreamException {
+ delegate.writeStartDocument(encoding, version);
+ nl();
+ state = START_DOCUMENT;
+ }
+
+ @Override
+ public void writeCharacters(final String text) throws XMLStreamException {
+ runAttrQueue();
+ if (state != CHARACTERS) {
+ nl();
+ indent();
+ }
+ final Iterator<String> iterator = Spliterator.over(text, '\n');
+ while (iterator.hasNext()) {
+ final String t = iterator.next();
+ delegate.writeCharacters(t);
+ if (iterator.hasNext()) {
+ nl();
+ indent();
+ }
+ }
+ state = CHARACTERS;
+ indentEndElement = true;
+ }
+
+ @Override
+ public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException {
+ runAttrQueue();
+ delegate.writeCharacters(text, start, len);
+ state = CHARACTERS;
+ }
+
+ @Override
+ public String getPrefix(final String uri) throws XMLStreamException {
+ return delegate.getPrefix(uri);
+ }
+
+ @Override
+ public void setPrefix(final String prefix, final String uri) throws XMLStreamException {
+ delegate.setPrefix(prefix, uri);
+ }
+
+ @Override
+ public void setDefaultNamespace(final String uri) throws XMLStreamException {
+ runAttrQueue();
+ delegate.setDefaultNamespace(uri);
+ }
+
+ @Override
+ public void setNamespaceContext(final NamespaceContext context) throws XMLStreamException {
+ delegate.setNamespaceContext(context);
+ }
+
+ @Override
+ public NamespaceContext getNamespaceContext() {
+ return delegate.getNamespaceContext();
+ }
+
+ @Override
+ public Object getProperty(final String name) throws IllegalArgumentException {
+ return delegate.getProperty(name);
+ }
+
+ private static String join(final String[] values) {
+ final StringBuilder b = new StringBuilder();
+ for (int i = 0, valuesLength = values.length; i < valuesLength; i++) {
+ final String s = values[i];
+ if (s != null) {
+ if (i > 0) {
+ b.append(' ');
+ }
+ b.append(s);
+ }
+ }
+ return b.toString();
+ }
+
+ private static String join(final Iterable<String> values) {
+ final StringBuilder b = new StringBuilder();
+ Iterator<String> iterator = values.iterator();
+ while (iterator.hasNext()) {
+ final String s = iterator.next();
+ if (s != null) {
+ b.append(s);
+ if (iterator.hasNext()) b.append(' ');
+ }
+ }
+ return b.toString();
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/Spliterator.java b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/Spliterator.java
new file mode 100644
index 0000000..e9cb5c6
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/xml/Spliterator.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package org.keycloak.subsystem.saml.as7.xml;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
+ */
+final class Spliterator implements Iterator<String> {
+ private final String subject;
+ private final char delimiter;
+ private int i;
+
+ Spliterator(final String subject, final char delimiter) {
+ this.subject = subject;
+ this.delimiter = delimiter;
+ i = 0;
+ }
+
+ static Spliterator over(String subject, char delimiter) {
+ return new Spliterator(subject, delimiter);
+ }
+
+ public boolean hasNext() {
+ return i != -1;
+ }
+
+ public String next() {
+ final int i = this.i;
+ if (i == -1) {
+ throw new NoSuchElementException();
+ }
+ int n = subject.indexOf(delimiter, i);
+ try {
+ return n == -1 ? subject.substring(i) : subject.substring(i, n);
+ } finally {
+ this.i = n == -1 ? -1 : n + 1;
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties b/saml/client-adapter/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties
new file mode 100755
index 0000000..f8a4a11
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties
@@ -0,0 +1,63 @@
+keycloak-saml.subsystem=Keycloak adapter subsystem
+keycloak-saml.subsystem.add=Operation Adds Keycloak adapter subsystem
+keycloak-saml.subsystem.remove=Operation removes Keycloak adapter subsystem
+keycloak-saml.subsystem.secure-deployment=A deployment secured by Keycloak.
+
+keycloak-saml.secure-deployment=A deployment secured by Keycloak
+keycloak-saml.secure-deployment.add=Add a deployment to be secured by Keycloak
+keycloak-saml.secure-deployment.remove=Remove a deployment to be secured by Keycloak
+keycloak-saml.secure-deployment.service-provider=A security provider configuration for secure deployment
+
+keycloak-saml.service-provider=A security provider configuration for secure deployment
+keycloak-saml.service-provider.add=Add a security provider configuration to deployment secured by Keycloak SAML
+keycloak-saml.service-provider.remove=Remove a security provider definition from deployment secured by Keycloak SAML
+keycloak-saml.service-provider.ssl-policy=SSL Policy to use
+keycloak-saml.service-provider.name-id-policy-format=Name ID policy format URN
+keycloak-saml.service-provider.logout-page=URI to a logout page
+keycloak-saml.service-provider.force-authentication=Redirected unauthenticated request to a login page
+keycloak-saml.service-provider.role-attributes=Role identifiers
+keycloak-saml.service-provider.principal-name-mapping-policy=Principal name mapping policy
+keycloak-saml.service-provider.principal-name-mapping-attribute-name=Principal name mapping attribute name
+keycloak-saml.service-provider.key=A key definition
+keycloak-saml.service-provider.identity-provider=Identity provider definition
+
+keycloak-saml.key=A key configuration for service provider or identity provider
+keycloak-saml.key.add=Add a key definition
+keycloak-saml.key.remove=Remove a key definition
+keycloak-saml.key.signing=Key can be used for signing
+keycloak-saml.key.encryption=Key can be used for encryption
+keycloak-saml.key.private-key-pem=Private key string in pem format
+keycloak-saml.key.public-key-pem=Public key string in pem format
+keycloak-saml.key.certificate-pem=Certificate key string in pem format
+keycloak-saml.key.key-store=Key store definition
+keycloak-saml.key.key-store.file=Key store filesystem path
+keycloak-saml.key.key-store.resource=Key store resource URI
+keycloak-saml.key.key-store.password=Key store password
+keycloak-saml.key.key-store.type=Key store format
+keycloak-saml.key.key-store.alias=Key alias
+keycloak-saml.key.key-store.private-key-alias=Private key alias
+keycloak-saml.key.key-store.private-key-password=Private key password
+keycloak-saml.key.key-store.certificate-alias=Certificate alias
+
+keycloak-saml.identity-provider=An identity provider configuration
+keycloak-saml.identity-provider.add=Add an identity provider
+keycloak-saml.identity-provider.remove=Remove an identity provider
+keycloak-saml.identity-provider.signatures-required=Require signatures for single-sign-on and single-logout
+keycloak-saml.identity-provider.signature-algorithm=Signature algorithm
+keycloak-saml.identity-provider.signature-canonicalization-method=Signature canonicalization method
+keycloak-saml.identity-provider.single-sign-on=Single sign-on configuration
+keycloak-saml.identity-provider.single-sign-on.sign-request=Sign SSO requests
+keycloak-saml.identity-provider.single-sign-on.validate-response-signature=Validate an SSO response signature
+keycloak-saml.identity-provider.single-sign-on.request-binding=HTTP method to use for requests
+keycloak-saml.identity-provider.single-sign-on.response-binding=HTTP method to use for responses
+keycloak-saml.identity-provider.single-sign-on.binding-url=SSO endpoint URL
+keycloak-saml.identity-provider.single-logout=Single logout configuration
+keycloak-saml.identity-provider.single-logout.validate-request-signature=Validate a single-logout request signature
+keycloak-saml.identity-provider.single-logout.validate-response-signature=Validate a single-logout response signature
+keycloak-saml.identity-provider.single-logout.sign-request=Sign single-logout requests
+keycloak-saml.identity-provider.single-logout.sign-response=Sign single-logout responses
+keycloak-saml.identity-provider.single-logout.request-binding=HTTP method to use for request
+keycloak-saml.identity-provider.single-logout.response-binding=HTTP method to use for response
+keycloak-saml.identity-provider.single-logout.post-binding-url=Endpoint URL for posting
+keycloak-saml.identity-provider.single-logout.redirect-binding-url=Endpoint URL for redirects
+keycloak-saml.identity-provider.key=Key definition for identity provider
\ No newline at end of file
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd b/saml/client-adapter/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
new file mode 100644
index 0000000..725104b
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="urn:jboss:domain:keycloak-saml:1.1"
+ xmlns="urn:jboss:domain:keycloak-saml:1.1"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ version="1.0">
+
+ <!-- The subsystem root element -->
+ <xs:element name="subsystem" type="subsystem-type"/>
+
+ <xs:complexType name="subsystem-type">
+ <xs:annotation>
+ <xs:documentation>
+ <![CDATA[
+ The Keycloak SAML adapter subsystem, used to register deployments managed by Keycloak SAML adapter
+ ]]>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:all>
+ <xs:element name="secure-deployment" minOccurs="0" type="secure-deployment-type"/>
+ </xs:all>
+ </xs:complexType>
+
+ <xs:complexType name="secure-deployment-type">
+ <xs:all>
+ <xs:element name="SP" minOccurs="1" maxOccurs="1" type="sp-type"/>
+ </xs:all>
+ <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:complexType>
+
+ <xs:complexType name="sp-type">
+ <xs:all>
+ <xs:element name="Keys" minOccurs="0" maxOccurs="1" type="keys-type"/>
+ <xs:element name="PrincipalNameMapping" minOccurs="0" maxOccurs="1" type="principal-name-mapping-type"/>
+ <xs:element name="RoleIdentifiers" minOccurs="0" maxOccurs="1" type="role-identifiers-type"/>
+ <xs:element name="IDP" minOccurs="1" maxOccurs="1" type="identity-provider-type"/>
+ </xs:all>
+ <xs:attribute name="entityID" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The entity ID for SAML service provider</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="sslPolicy" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The ssl policy</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="nameIDPolicyFormat" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Name ID policy format URN</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="logoutPage" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>URI to a logout page</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="forceAuthentication" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>Redirected unauthenticated request to a login page</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="identity-provider-type">
+ <xs:all minOccurs="1" maxOccurs="1">
+ <xs:element name="SingleSignOnService" minOccurs="1" maxOccurs="1" type="single-signon-type"/>
+ <xs:element name="SingleLogoutService" minOccurs="0" maxOccurs="1" type="single-logout-type"/>
+ <xs:element name="Keys" minOccurs="0" maxOccurs="1" type="keys-type"/>
+ </xs:all>
+ <xs:attribute name="entityID" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The entity ID for SAML service provider</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signaturesRequired" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>Require signatures for single-sign-on and single-logout</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signatureAlgorithm" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Algorithm used for signatures</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signatureCanonicalizationMethod" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Canonicalization method used for signatures</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="single-signon-type">
+ <xs:attribute name="signRequest" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sign the SSO requests</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Validate the SSO response signature</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requestBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for requests</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="responseBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for response</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="bindingUrl" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>SSO endpoint URL</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="single-logout-type">
+ <xs:attribute name="validateRequestSignature" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Validate a single-logout request signature</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Validate a single-logout response signature</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signRequest" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sign single-logout requests</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signResponse" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sign single-logout responses</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requestBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for request</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="responseBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for response</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="postBindingUrl" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Endpoint URL for posting</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="redirectBindingUrl" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Endpoint URL for redirects</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="keys-type">
+ <xs:sequence>
+ <xs:element name="Key" minOccurs="1" maxOccurs="2" type="key-type"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="key-type">
+ <xs:all>
+ <xs:element name="KeyStore" minOccurs="0" maxOccurs="1" type="keystore-type"/>
+ <xs:element name="PrivateKeyPem" minOccurs="0" maxOccurs="1" type="xs:string"/>
+ <xs:element name="PublicKeyPem" minOccurs="0" maxOccurs="1" type="xs:string"/>
+ <xs:element name="CertificatePem" minOccurs="0" maxOccurs="1" type="xs:string"/>
+ </xs:all>
+ <xs:attribute name="signing" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key can be used for signing</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="encryption" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key can be used for encryption</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="keystore-type">
+ <xs:sequence minOccurs="0" maxOccurs="1">
+ <xs:element name="PrivateKey" minOccurs="0" maxOccurs="1" type="privatekey-type"/>
+ <xs:element name="Certificate" minOccurs="0" maxOccurs="1" type="certificate-type"/>
+ </xs:sequence>
+ <xs:attribute name="file" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key store filesystem path</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="resource" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key store resource URI</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="password" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Key store password</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key store format</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="alias" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key alias</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="privatekey-type">
+ <xs:attribute name="alias" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Private key alias</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="password" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Private key password</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="certificate-type">
+ <xs:attribute name="alias" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Certificate alias</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="principal-name-mapping-type">
+ <xs:attribute name="policy" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Principal name mapping policy. Possible values: FROM_NAME_ID</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="attribute" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the attribute to use for principal name mapping</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="role-identifiers-type">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="Attribute" minOccurs="0" maxOccurs="unbounded" type="attribute-type"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="attribute-type">
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Role attribute</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
diff --git a/saml/client-adapter/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml b/saml/client-adapter/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml
new file mode 100644
index 0000000..19d7528
--- /dev/null
+++ b/saml/client-adapter/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml
@@ -0,0 +1,49 @@
+<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
+ <secure-deployment name="my-app.war">
+ <SP entityID="http://localhost:8080/sales-post-enc/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+
+ <Keys>
+ <Key encryption="true" signing="true">
+ <PrivateKeyPem>my_key.pem</PrivateKeyPem>
+ <PublicKeyPem>my_key.pub</PublicKeyPem>
+ <CertificatePem>cert.cer</CertificatePem>
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
+ <Certificate alias="http://localhost:8080/sales-post-enc/"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ <PrincipalNameMapping policy="FROM_NAME_ID"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ <Attribute name="Role2"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp">
+ <SingleSignOnService signRequest="true"
+ validateResponseSignature="true"
+ requestBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+ <SingleLogoutService
+ validateRequestSignature="true"
+ validateResponseSignature="true"
+ signRequest="true"
+ signResponse="true"
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+ <Keys>
+ <Key signing="true">
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <Certificate alias="saml-demo"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ </IDP>
+ </SP>
+ </secure-deployment>
+</subsystem>
\ No newline at end of file
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java
index 280b5f8..e921d15 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java
@@ -5,5 +5,5 @@ package org.keycloak.adapters.saml;
* @version $Revision: 1 $
*/
public class AdapterConstants {
- public static final String AUTH_DATA_PARAM_NAME="org.keycloak.auth.deployment.data";
+ public static final String AUTH_DATA_PARAM_NAME="org.keycloak.saml.xml.adapterConfig";
}
diff --git a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java
index 615e4a6..ad22718 100755
--- a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java
+++ b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java
@@ -28,6 +28,7 @@ import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.ServletSessionConfig;
import org.jboss.logging.Logger;
+import org.keycloak.adapters.saml.AdapterConstants;
import org.keycloak.adapters.saml.DefaultSamlDeployment;
import org.keycloak.adapters.saml.SamlConfigResolver;
import org.keycloak.adapters.saml.SamlDeployment;
@@ -38,6 +39,7 @@ import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
import org.keycloak.saml.common.exceptions.ParsingException;
import javax.servlet.ServletContext;
+import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
@@ -64,8 +66,16 @@ public class SamlServletExtension implements ServletExtension {
return false;
}
+ private static InputStream getXMLFromServletContext(ServletContext servletContext) {
+ String json = servletContext.getInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME);
+ if (json == null) {
+ return null;
+ }
+ return new ByteArrayInputStream(json.getBytes());
+ }
+
private static InputStream getConfigInputStream(ServletContext context) {
- InputStream is = null;
+ InputStream is = getXMLFromServletContext(context);
if (is == null) {
String path = context.getInitParameter("keycloak.config.file");
if (path == null) {
saml/client-adapter/wildfly/pom.xml 2(+1 -1)
diff --git a/saml/client-adapter/wildfly/pom.xml b/saml/client-adapter/wildfly/pom.xml
index 2b5eb25..d9014b6 100755
--- a/saml/client-adapter/wildfly/pom.xml
+++ b/saml/client-adapter/wildfly/pom.xml
@@ -15,6 +15,6 @@
<modules>
<module>wildfly-adapter</module>
- <module>wildfly9-subsystem</module>
+ <module>wildfly-subsystem</module>
</modules>
</project>
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java
new file mode 100644
index 0000000..e364e2d
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.Property;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class Configuration {
+
+ static Configuration INSTANCE = new Configuration();
+
+ private ModelNode config = new ModelNode();
+
+ private Configuration() {
+ }
+
+ void updateModel(ModelNode operation, ModelNode model) {
+ ModelNode node = config;
+ ModelNode addr = operation.get("address");
+ for (Property item : addr.asPropertyList()) {
+ node = getNodeForAddressElement(node, item);
+ }
+ node.set(model);
+ }
+
+ private ModelNode getNodeForAddressElement(ModelNode node, Property item) {
+ String key = item.getValue().asString();
+ ModelNode keymodel = node.get(item.getName());
+ return keymodel.get(key);
+ }
+
+ public ModelNode getSecureDeployment(String name) {
+ ModelNode secureDeployment = config.get("subsystem").get("keycloak-saml").get(Constants.Model.SECURE_DEPLOYMENT);
+ if (secureDeployment.hasDefined(name)) {
+ return secureDeployment.get(name);
+ }
+ return null;
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java
new file mode 100644
index 0000000..9b89fb2
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class Constants {
+
+ static class Model {
+ static final String SECURE_DEPLOYMENT = "secure-deployment";
+ static final String SERVICE_PROVIDER = "service-provider";
+
+ static final String SSL_POLICY = "ssl-policy";
+ static final String NAME_ID_POLICY_FORMAT = "name-id-policy-format";
+ static final String LOGOUT_PAGE = "logout-page";
+ static final String FORCE_AUTHENTICATION = "force-authentication";
+ static final String ROLE_ATTRIBUTES = "role-attributes";
+ static final String SIGNING = "signing";
+ static final String ENCRYPTION = "encryption";
+ static final String KEY = "key";
+ static final String RESOURCE = "resource";
+ static final String PASSWORD = "password";
+
+ static final String PRIVATE_KEY_ALIAS = "private-key-alias";
+ static final String PRIVATE_KEY_PASSWORD = "private-key-password";
+ static final String CERTIFICATE_ALIAS = "certificate-alias";
+ static final String KEY_STORE = "key-store";
+ static final String SIGN_REQUEST = "sign-request";
+ static final String VALIDATE_RESPONSE_SIGNATURE = "validate-response-signature";
+ static final String REQUEST_BINDING = "request-binding";
+ static final String BINDING_URL = "binding-url";
+ static final String VALIDATE_REQUEST_SIGNATURE = "validate-request-signature";
+ static final String SIGN_RESPONSE = "sign-response";
+ static final String RESPONSE_BINDING = "response-binding";
+ static final String POST_BINDING_URL = "post-binding-url";
+ static final String REDIRECT_BINDING_URL = "redirect-binding-url";
+ static final String SINGLE_SIGN_ON = "single-sign-on";
+ static final String SINGLE_LOGOUT = "single-logout";
+ static final String IDENTITY_PROVIDER = "identity-provider";
+ static final String PRINCIPAL_NAME_MAPPING_POLICY = "principal-name-mapping-policy";
+ static final String PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME = "principal-name-mapping-attribute-name";
+ static final String SIGNATURE_ALGORITHM = "signature-algorithm";
+ static final String SIGNATURE_CANONICALIZATION_METHOD = "signature-canonicalization-method";
+ static final String PRIVATE_KEY_PEM = "private-key-pem";
+ static final String PUBLIC_KEY_PEM = "public-key-pem";
+ static final String CERTIFICATE_PEM = "certificate-pem";
+ static final String TYPE = "type";
+ static final String ALIAS = "alias";
+ static final String FILE = "file";
+ static final String SIGNATURES_REQUIRED = "signatures-required";
+ }
+
+
+ static class XML {
+ static final String SECURE_DEPLOYMENT = "secure-deployment";
+ static final String SERVICE_PROVIDER = "SP";
+
+ static final String NAME = "name";
+ static final String ENTITY_ID = "entityID";
+ static final String SSL_POLICY = "sslPolicy";
+ static final String NAME_ID_POLICY_FORMAT = "nameIDPolicyFormat";
+ static final String LOGOUT_PAGE = "logoutPage";
+ static final String FORCE_AUTHENTICATION = "forceAuthentication";
+ static final String ROLE_IDENTIFIERS = "RoleIdentifiers";
+ static final String SIGNING = "signing";
+ static final String ENCRYPTION = "encryption";
+ static final String KEYS = "Keys";
+ static final String KEY = "Key";
+ static final String RESOURCE = "resource";
+ static final String PASSWORD = "password";
+ static final String KEY_STORE = "KeyStore";
+ static final String PRIVATE_KEY = "PrivateKey";
+ static final String CERTIFICATE = "Certificate";
+
+ static final String PRIVATE_KEY_ALIAS = "alias";
+ static final String PRIVATE_KEY_PASSWORD = "password";
+ static final String CERTIFICATE_ALIAS = "alias";
+ static final String SIGN_REQUEST = "signRequest";
+ static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
+ static final String REQUEST_BINDING = "requestBinding";
+ static final String BINDING_URL = "bindingUrl";
+ static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
+ static final String SIGN_RESPONSE = "signResponse";
+ static final String RESPONSE_BINDING = "responseBinding";
+ static final String POST_BINDING_URL = "postBindingUrl";
+ static final String REDIRECT_BINDING_URL = "redirectBindingUrl";
+ static final String SINGLE_SIGN_ON = "SingleSignOnService";
+ static final String SINGLE_LOGOUT = "SingleLogoutService";
+ static final String IDENTITY_PROVIDER = "IDP";
+ static final String PRINCIPAL_NAME_MAPPING = "PrincipalNameMapping";
+ static final String PRINCIPAL_NAME_MAPPING_POLICY = "policy";
+ static final String PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME = "attribute";
+ static final String ATTRIBUTE = "Attribute";
+ static final String SIGNATURE_ALGORITHM = "signatureAlgorithm";
+ static final String SIGNATURE_CANONICALIZATION_METHOD = "signatureCanonicalizationMethod";
+ static final String PRIVATE_KEY_PEM = "PrivateKeyPem";
+ static final String PUBLIC_KEY_PEM = "PublicKeyPem";
+ static final String CERTIFICATE_PEM = "CertificatePem";
+ static final String TYPE = "type";
+ static final String ALIAS = "alias";
+ static final String FILE = "file";
+ static final String SIGNATURES_REQUIRED = "signaturesRequired";
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderAddHandler.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderAddHandler.java
new file mode 100644
index 0000000..7648ba3
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderAddHandler.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.dmr.ModelNode;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class IdentityProviderAddHandler extends AbstractAddStepHandler {
+
+ IdentityProviderAddHandler() {
+ super(IdentityProviderDefinition.ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderDefinition.java
new file mode 100644
index 0000000..1459f15
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/IdentityProviderDefinition.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.ObjectTypeAttributeDefinition;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class IdentityProviderDefinition extends SimpleResourceDefinition {
+
+ static final SimpleAttributeDefinition SIGNATURES_REQUIRED =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNATURES_REQUIRED, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGNATURES_REQUIRED)
+ .build();
+
+ static final SimpleAttributeDefinition SIGNATURE_ALGORITHM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNATURE_ALGORITHM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.SIGNATURE_ALGORITHM)
+ .build();
+
+ static final SimpleAttributeDefinition SIGNATURE_CANONICALIZATION_METHOD =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNATURE_CANONICALIZATION_METHOD, ModelType.STRING, true)
+ .setXmlName(Constants.XML.SIGNATURE_CANONICALIZATION_METHOD)
+ .build();
+
+ static final ObjectTypeAttributeDefinition SINGLE_SIGN_ON =
+ ObjectTypeAttributeDefinition.Builder.of(Constants.Model.SINGLE_SIGN_ON,
+ SingleSignOnDefinition.ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final ObjectTypeAttributeDefinition SINGLE_LOGOUT =
+ ObjectTypeAttributeDefinition.Builder.of(Constants.Model.SINGLE_LOGOUT,
+ SingleLogoutDefinition.ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGNATURES_REQUIRED, SIGNATURE_ALGORITHM, SIGNATURE_CANONICALIZATION_METHOD};
+
+ static final SimpleAttributeDefinition[] ALL_ATTRIBUTES = {SIGNATURES_REQUIRED, SIGNATURE_ALGORITHM, SIGNATURE_CANONICALIZATION_METHOD, SINGLE_SIGN_ON, SINGLE_LOGOUT};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static final IdentityProviderDefinition INSTANCE = new IdentityProviderDefinition();
+
+ private IdentityProviderDefinition() {
+ super(PathElement.pathElement(Constants.Model.IDENTITY_PROVIDER),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.IDENTITY_PROVIDER),
+ new IdentityProviderAddHandler(),
+ ReloadRequiredRemoveStepHandler.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);
+
+ final OperationStepHandler writeHandler = new ReloadRequiredWriteAttributeHandler(ALL_ATTRIBUTES);
+ for (AttributeDefinition attribute : ALL_ATTRIBUTES) {
+ resourceRegistration.registerReadWriteAttribute(attribute, null, writeHandler);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
\ No newline at end of file
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyAddHandler.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyAddHandler.java
new file mode 100644
index 0000000..1799290
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyAddHandler.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.dmr.ModelNode;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class KeyAddHandler extends AbstractAddStepHandler {
+
+ KeyAddHandler() {
+ super(KeyDefinition.ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemParser.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemParser.java
new file mode 100755
index 0000000..8b20565
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemParser.java
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+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;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 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(KeycloakSamlExtension.PATH_SUBSYSTEM));
+ list.add(addKeycloakSub);
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ if (reader.getLocalName().equals(Constants.XML.SECURE_DEPLOYMENT)) {
+ readSecureDeployment(reader, list);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ // used for debugging
+ private int nextTag(XMLExtendedStreamReader reader) throws XMLStreamException {
+ return reader.nextTag();
+ }
+
+ void readSecureDeployment(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
+ String name = readRequiredAttribute(reader, Constants.XML.NAME);
+
+ PathAddress addr = PathAddress.pathAddress(
+ PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakSamlExtension.SUBSYSTEM_NAME),
+ PathElement.pathElement(Constants.Model.SECURE_DEPLOYMENT, name));
+ ModelNode addSecureDeployment = Util.createAddOperation(addr);
+ list.add(addSecureDeployment);
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ if (tagName.equals(Constants.XML.SERVICE_PROVIDER)) {
+ readServiceProvider(reader, list, addr);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readServiceProvider(XMLExtendedStreamReader reader, List<ModelNode> list, PathAddress parentAddr) throws XMLStreamException {
+ String entityId = readRequiredAttribute(reader, Constants.XML.ENTITY_ID);
+
+ PathAddress addr = PathAddress.pathAddress(parentAddr,
+ PathElement.pathElement(Constants.Model.SERVICE_PROVIDER, entityId));
+ ModelNode addServiceProvider = Util.createAddOperation(addr);
+ list.add(addServiceProvider);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ if (Constants.XML.ENTITY_ID.equals(name)) {
+ continue;
+ }
+
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = ServiceProviderDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addServiceProvider, reader);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (Constants.XML.KEYS.equals(tagName)) {
+ readKeys(list, reader, addr);
+ } else if (Constants.XML.PRINCIPAL_NAME_MAPPING.equals(tagName)) {
+ readPrincipalNameMapping(addServiceProvider, reader);
+ } else if (Constants.XML.ROLE_IDENTIFIERS.equals(tagName)) {
+ readRoleIdentifiers(addServiceProvider, reader);
+ } else if (Constants.XML.IDENTITY_PROVIDER.equals(tagName)) {
+ readIdentityProvider(list, reader, addr);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readIdentityProvider(List<ModelNode> list, XMLExtendedStreamReader reader, PathAddress parentAddr) throws XMLStreamException {
+ String entityId = readRequiredAttribute(reader, Constants.XML.ENTITY_ID);
+
+ PathAddress addr = PathAddress.pathAddress(parentAddr,
+ PathElement.pathElement(Constants.Model.IDENTITY_PROVIDER, entityId));
+ ModelNode addIdentityProvider = Util.createAddOperation(addr);
+ list.add(addIdentityProvider);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ if (Constants.XML.ENTITY_ID.equals(name)
+ // don't break if encountering this noop attr from client-adapter/core keycloak_saml_adapter_1_6.xsd
+ || "encryption".equals(name)) {
+ continue;
+ }
+ SimpleAttributeDefinition attr = IdentityProviderDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addIdentityProvider, reader);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (Constants.XML.SINGLE_SIGN_ON.equals(tagName)) {
+ readSingleSignOn(addIdentityProvider, reader);
+ } else if (Constants.XML.SINGLE_LOGOUT.equals(tagName)) {
+ readSingleLogout(addIdentityProvider, reader);
+ } else if (Constants.XML.KEYS.equals(tagName)) {
+ readKeys(list, reader, addr);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readSingleSignOn(ModelNode addIdentityProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ModelNode sso = addIdentityProvider.get(Constants.Model.SINGLE_SIGN_ON);
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = SingleSignOnDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, sso, reader);
+ }
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readSingleLogout(ModelNode addIdentityProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ModelNode slo = addIdentityProvider.get(Constants.Model.SINGLE_LOGOUT);
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = SingleLogoutDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, slo, reader);
+ }
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readKeys(List<ModelNode> list, XMLExtendedStreamReader reader, PathAddress parentAddr) throws XMLStreamException {
+ ParseUtils.requireNoAttributes(reader);
+ List<ModelNode> keyList = new LinkedList<>();
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ if (!Constants.XML.KEY.equals(tagName)) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ readKey(keyList, reader, parentAddr);
+ }
+ list.addAll(keyList);
+ }
+
+ void readKey(List<ModelNode> list, XMLExtendedStreamReader reader, PathAddress parentAddr) throws XMLStreamException {
+ PathAddress addr = PathAddress.pathAddress(parentAddr,
+ PathElement.pathElement(Constants.Model.KEY, "key-" + list.size()));
+ ModelNode addKey = Util.createAddOperation(addr);
+ list.add(addKey);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKey, reader);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (Constants.XML.KEY_STORE.equals(tagName)) {
+ readKeyStore(addKey, reader);
+ } else if (Constants.XML.PRIVATE_KEY_PEM.equals(tagName)
+ || Constants.XML.PUBLIC_KEY_PEM.equals(tagName)
+ || Constants.XML.CERTIFICATE_PEM.equals(tagName)) {
+
+ readNoAttrElementContent(KeyDefinition.lookupElement(tagName), addKey, reader);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+ void readNoAttrElementContent(SimpleAttributeDefinition attr, ModelNode model, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ParseUtils.requireNoAttributes(reader);
+ String value = reader.getElementText();
+ attr.parseAndSetParameter(value, model, reader);
+ }
+
+ void readKeyStore(ModelNode addKey, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ModelNode addKeyStore = addKey.get(Constants.Model.KEY_STORE);
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyStoreDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKeyStore, reader);
+ }
+
+ if (!addKeyStore.hasDefined(Constants.Model.FILE) && !addKeyStore.hasDefined(Constants.Model.RESOURCE)) {
+ throw new XMLStreamException("KeyStore element must have 'file' or 'resource' attribute set", reader.getLocation());
+ }
+ if (!addKeyStore.hasDefined(Constants.Model.PASSWORD)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PASSWORD);
+ }
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+ if (Constants.XML.PRIVATE_KEY.equals(tagName)) {
+ readPrivateKey(reader, addKeyStore);
+ } else if (Constants.XML.CERTIFICATE.equals(tagName)) {
+ readCertificate(reader, addKeyStore);
+ } else {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+ }
+ }
+
+
+ void readPrivateKey(XMLExtendedStreamReader reader, ModelNode addKeyStore) throws XMLStreamException {
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyStorePrivateKeyDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKeyStore, reader);
+ }
+
+ if (!addKeyStore.hasDefined(Constants.Model.PRIVATE_KEY_ALIAS)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PRIVATE_KEY_ALIAS);
+ }
+ if (!addKeyStore.hasDefined(Constants.Model.PRIVATE_KEY_PASSWORD)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PRIVATE_KEY_PASSWORD);
+ }
+
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readCertificate(XMLExtendedStreamReader reader, ModelNode addKeyStore) throws XMLStreamException {
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ SimpleAttributeDefinition attr = KeyStoreCertificateDefinition.lookup(name);
+ if (attr == null) {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ attr.parseAndSetParameter(value, addKeyStore, reader);
+ }
+
+ if (!addKeyStore.hasDefined(Constants.Model.CERTIFICATE_ALIAS)) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.CERTIFICATE_ALIAS);
+ }
+
+ ParseUtils.requireNoContent(reader);
+ }
+
+ void readRoleIdentifiers(ModelNode addServiceProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+ ParseUtils.requireNoAttributes(reader);
+
+ while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
+ String tagName = reader.getLocalName();
+
+ if (!Constants.XML.ATTRIBUTE.equals(tagName)) {
+ throw ParseUtils.unexpectedElement(reader);
+ }
+
+ ParseUtils.requireSingleAttribute(reader, Constants.XML.NAME);
+ String name = ParseUtils.readStringAttributeElement(reader, Constants.XML.NAME);
+
+ ServiceProviderDefinition.ROLE_ATTRIBUTES.parseAndAddParameterElement(name, addServiceProvider, reader);
+ }
+ }
+
+ void readPrincipalNameMapping(ModelNode addServiceProvider, XMLExtendedStreamReader reader) throws XMLStreamException {
+
+ boolean policySet = false;
+
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String name = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+
+ if (Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY.equals(name)) {
+ policySet = true;
+ ServiceProviderDefinition.PRINCIPAL_NAME_MAPPING_POLICY.parseAndSetParameter(value, addServiceProvider, reader);
+ } else if (Constants.XML.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME.equals(name)) {
+ ServiceProviderDefinition.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME.parseAndSetParameter(value, addServiceProvider, reader);
+ } else {
+ throw ParseUtils.unexpectedAttribute(reader, i);
+ }
+ }
+
+ if (!policySet) {
+ throw ParseUtils.missingRequired(reader, Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY);
+ }
+ ParseUtils.requireNoContent(reader);
+ }
+
+ /**
+ * Read an attribute, and throw exception if attribute is not present
+ */
+ String readRequiredAttribute(XMLExtendedStreamReader reader, String attrName) throws XMLStreamException {
+ String value = null;
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String attr = reader.getAttributeLocalName(i);
+ if (attr.equals(attrName)) {
+ value = reader.getAttributeValue(i);
+ break;
+ }
+ }
+ if (value == null) {
+ throw ParseUtils.missingRequired(reader, Collections.singleton(attrName));
+ }
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
+ context.startSubsystemElement(KeycloakSamlExtension.NAMESPACE, false);
+ writeSecureDeployment(writer, context.getModelNode());
+ writer.writeEndElement();
+ }
+
+ public void writeSecureDeployment(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.get(Constants.Model.SECURE_DEPLOYMENT).isDefined()) {
+ return;
+ }
+
+ for (Property sp : model.get(Constants.Model.SECURE_DEPLOYMENT).asPropertyList()) {
+ writer.writeStartElement(Constants.XML.SECURE_DEPLOYMENT);
+ writer.writeAttribute(Constants.XML.NAME, sp.getName());
+
+ writeSps(writer, sp.getValue());
+ writer.writeEndElement();
+ }
+ }
+
+ void writeSps(final XMLExtendedStreamWriter writer, final ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ for (Property sp : model.get(Constants.Model.SERVICE_PROVIDER).asPropertyList()) {
+ writer.writeStartElement(Constants.XML.SERVICE_PROVIDER);
+ writer.writeAttribute(Constants.XML.ENTITY_ID, sp.getName());
+ ModelNode spAttributes = sp.getValue();
+ for (SimpleAttributeDefinition attr : ServiceProviderDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, spAttributes, false, writer);
+ }
+ writeKeys(writer, spAttributes.get(Constants.Model.KEY));
+ writePrincipalNameMapping(writer, spAttributes);
+ writeRoleIdentifiers(writer, spAttributes);
+ writeIdentityProvider(writer, spAttributes.get(Constants.Model.IDENTITY_PROVIDER));
+
+ writer.writeEndElement();
+ }
+ }
+
+ void writeIdentityProvider(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+
+ for (Property idp : model.asPropertyList()) {
+ writer.writeStartElement(Constants.XML.IDENTITY_PROVIDER);
+ writer.writeAttribute(Constants.XML.ENTITY_ID, idp.getName());
+
+ ModelNode idpAttributes = idp.getValue();
+ for (SimpleAttributeDefinition attr : IdentityProviderDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, idpAttributes, false, writer);
+ }
+
+ writeSingleSignOn(writer, idpAttributes.get(Constants.Model.SINGLE_SIGN_ON));
+ writeSingleLogout(writer, idpAttributes.get(Constants.Model.SINGLE_LOGOUT));
+ writeKeys(writer, idpAttributes.get(Constants.Model.KEY));
+ }
+ writer.writeEndElement();
+ }
+
+ void writeSingleSignOn(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.SINGLE_SIGN_ON);
+ for (SimpleAttributeDefinition attr : SingleSignOnDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ void writeSingleLogout(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.SINGLE_LOGOUT);
+ for (SimpleAttributeDefinition attr : SingleLogoutDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ void writeKeys(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ boolean contains = false;
+ for (Property key : model.asPropertyList()) {
+ if (!contains) {
+ writer.writeStartElement(Constants.XML.KEYS);
+ contains = true;
+ }
+ writer.writeStartElement(Constants.XML.KEY);
+
+ ModelNode keyAttributes = key.getValue();
+ for (SimpleAttributeDefinition attr : KeyDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, keyAttributes, false, writer);
+ }
+ for (SimpleAttributeDefinition attr : KeyDefinition.ELEMENTS) {
+ attr.getAttributeMarshaller().marshallAsElement(attr, keyAttributes, false, writer);
+ }
+ writeKeyStore(writer, keyAttributes.get(Constants.Model.KEY_STORE));
+
+ writer.writeEndElement();
+ }
+ if (contains) {
+ writer.writeEndElement();
+ }
+ }
+
+ void writeKeyStore(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ if (!model.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.KEY_STORE);
+ for (SimpleAttributeDefinition attr : KeyStoreDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
+ writePrivateKey(writer, model);
+ writeCertificate(writer, model);
+ writer.writeEndElement();
+ }
+
+ void writeCertificate(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ ModelNode value = model.get(Constants.Model.CERTIFICATE_ALIAS);
+ if (!value.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.CERTIFICATE);
+ SimpleAttributeDefinition attr = KeyStoreCertificateDefinition.CERTIFICATE_ALIAS;
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ writer.writeEndElement();
+ }
+
+ void writePrivateKey(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ ModelNode pk_alias = model.get(Constants.Model.PRIVATE_KEY_ALIAS);
+ ModelNode pk_password = model.get(Constants.Model.PRIVATE_KEY_PASSWORD);
+
+ if (!pk_alias.isDefined() && !pk_password.isDefined()) {
+ return;
+ }
+ writer.writeStartElement(Constants.XML.PRIVATE_KEY);
+ for (SimpleAttributeDefinition attr : KeyStorePrivateKeyDefinition.ATTRIBUTES) {
+ attr.getAttributeMarshaller().marshallAsAttribute(attr, model, false, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ void writeRoleIdentifiers(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ ModelNode value = model.get(Constants.Model.ROLE_ATTRIBUTES);
+ if (!value.isDefined()) {
+ return;
+ }
+
+ List<ModelNode> items = value.asList();
+ if (items.size() == 0) {
+ return;
+ }
+
+ writer.writeStartElement(Constants.XML.ROLE_IDENTIFIERS);
+ for (ModelNode item : items) {
+ writer.writeStartElement(Constants.XML.ATTRIBUTE);
+ writer.writeAttribute("name", item.asString());
+ writer.writeEndElement();
+ }
+ writer.writeEndElement();
+ }
+
+ void writePrincipalNameMapping(XMLExtendedStreamWriter writer, ModelNode model) throws XMLStreamException {
+ writer.writeStartElement(Constants.XML.PRINCIPAL_NAME_MAPPING);
+ ModelNode value = model.get(Constants.Model.PRINCIPAL_NAME_MAPPING_POLICY);
+ if (value.isDefined()) {
+ writer.writeAttribute(Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY, value.asString());
+ }
+ value = model.get(Constants.Model.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME);
+ if (value.isDefined()) {
+ writer.writeAttribute(Constants.XML.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME, value.asString());
+ }
+ writer.writeEndElement();
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyDefinition.java
new file mode 100644
index 0000000..7d19994
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyDefinition.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.ObjectTypeAttributeDefinition;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class KeyDefinition extends SimpleResourceDefinition {
+
+ static final SimpleAttributeDefinition SIGNING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGNING, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGNING)
+ .build();
+
+ static final SimpleAttributeDefinition ENCRYPTION =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.ENCRYPTION, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.ENCRYPTION)
+ .build();
+
+ static final SimpleAttributeDefinition PRIVATE_KEY_PEM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRIVATE_KEY_PEM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRIVATE_KEY_PEM)
+ .build();
+
+ static final SimpleAttributeDefinition PUBLIC_KEY_PEM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PUBLIC_KEY_PEM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PUBLIC_KEY_PEM)
+ .build();
+
+ static final SimpleAttributeDefinition CERTIFICATE_PEM =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.CERTIFICATE_PEM, ModelType.STRING, true)
+ .setXmlName(Constants.XML.CERTIFICATE_PEM)
+ .build();
+
+ static final ObjectTypeAttributeDefinition KEY_STORE =
+ ObjectTypeAttributeDefinition.Builder.of(Constants.Model.KEY_STORE,
+ KeyStoreDefinition.ALL_ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGNING, ENCRYPTION};
+ static final SimpleAttributeDefinition[] ELEMENTS = {PRIVATE_KEY_PEM, PUBLIC_KEY_PEM, CERTIFICATE_PEM};
+ static final AttributeDefinition[] ALL_ATTRIBUTES = {SIGNING, ENCRYPTION, PRIVATE_KEY_PEM, PUBLIC_KEY_PEM, CERTIFICATE_PEM, KEY_STORE};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static final HashMap<String, SimpleAttributeDefinition> ELEMENT_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ELEMENTS) {
+ ELEMENT_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static final KeyDefinition INSTANCE = new KeyDefinition();
+
+ private KeyDefinition() {
+ super(PathElement.pathElement(Constants.Model.KEY),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.KEY),
+ new KeyAddHandler(),
+ ReloadRequiredRemoveStepHandler.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);
+
+ final OperationStepHandler writeHandler = new ReloadRequiredWriteAttributeHandler(ALL_ATTRIBUTES);
+ for (AttributeDefinition attribute : ALL_ATTRIBUTES) {
+ resourceRegistration.registerReadWriteAttribute(attribute, null, writeHandler);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+
+ static SimpleAttributeDefinition lookupElement(String xmlName) {
+ return ELEMENT_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreCertificateDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreCertificateDefinition.java
new file mode 100644
index 0000000..83dc057
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreCertificateDefinition.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class KeyStoreCertificateDefinition {
+
+ static final SimpleAttributeDefinition CERTIFICATE_ALIAS =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.CERTIFICATE_ALIAS, ModelType.STRING, true)
+ .setXmlName(Constants.XML.CERTIFICATE_ALIAS)
+ .build();
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return Constants.XML.CERTIFICATE_ALIAS.equals(xmlName) ? CERTIFICATE_ALIAS : null;
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreDefinition.java
new file mode 100644
index 0000000..a71e89a
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStoreDefinition.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+abstract class KeyStoreDefinition {
+
+ static final SimpleAttributeDefinition RESOURCE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.RESOURCE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.RESOURCE)
+ .build();
+
+ static final SimpleAttributeDefinition PASSWORD =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PASSWORD, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PASSWORD)
+ .build();
+
+ static final SimpleAttributeDefinition FILE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.FILE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.FILE)
+ .build();
+
+ static final SimpleAttributeDefinition TYPE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.TYPE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.TYPE)
+ .build();
+
+ static final SimpleAttributeDefinition ALIAS =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.ALIAS, ModelType.STRING, true)
+ .setXmlName(Constants.XML.ALIAS)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {RESOURCE, PASSWORD, FILE, TYPE, ALIAS};
+ static final SimpleAttributeDefinition[] ALL_ATTRIBUTES = {RESOURCE, PASSWORD, FILE, TYPE, ALIAS,
+ KeyStorePrivateKeyDefinition.PRIVATE_KEY_ALIAS,
+ KeyStorePrivateKeyDefinition.PRIVATE_KEY_PASSWORD,
+ KeyStoreCertificateDefinition.CERTIFICATE_ALIAS
+ };
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStorePrivateKeyDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStorePrivateKeyDefinition.java
new file mode 100644
index 0000000..bbb398d
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeyStorePrivateKeyDefinition.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class KeyStorePrivateKeyDefinition {
+ static final SimpleAttributeDefinition PRIVATE_KEY_ALIAS =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRIVATE_KEY_ALIAS, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRIVATE_KEY_ALIAS)
+ .build();
+
+ static final SimpleAttributeDefinition PRIVATE_KEY_PASSWORD =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRIVATE_KEY_PASSWORD, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRIVATE_KEY_PASSWORD)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {PRIVATE_KEY_ALIAS, PRIVATE_KEY_PASSWORD};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakLogger.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakLogger.java
new file mode 100755
index 0000000..d068b64
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakLogger.java
@@ -0,0 +1,45 @@
+/*
+ * 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.adapter.saml.extension.logging;
+
+import org.jboss.logging.BasicLogger;
+import org.jboss.logging.Logger;
+import org.jboss.logging.annotations.LogMessage;
+import org.jboss.logging.annotations.Message;
+import org.jboss.logging.annotations.MessageLogger;
+
+import static org.jboss.logging.Logger.Level.INFO;
+
+/**
+ * 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 = INFO)
+ @Message(value = "Keycloak subsystem override for deployment %s")
+ void deploymentSecured(String deployment);
+
+
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakMessages.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakMessages.java
new file mode 100755
index 0000000..be44809
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/logging/KeycloakMessages.java
@@ -0,0 +1,34 @@
+/*
+ * 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.adapter.saml.extension.logging;
+
+import org.jboss.logging.Messages;
+import org.jboss.logging.annotations.MessageBundle;
+
+/**
+ * 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 = "KEYCLOAK")
+public interface KeycloakMessages {
+
+ /**
+ * The messages
+ */
+ KeycloakMessages MESSAGES = Messages.getBundle(KeycloakMessages.class);
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentAddHandler.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentAddHandler.java
new file mode 100644
index 0000000..22de93d
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentAddHandler.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.dmr.ModelNode;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class SecureDeploymentAddHandler extends AbstractAddStepHandler {
+
+ static SecureDeploymentAddHandler INSTANCE = new SecureDeploymentAddHandler();
+
+ private SecureDeploymentAddHandler() {
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentDefinition.java
new file mode 100644
index 0000000..bf6cab5
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SecureDeploymentDefinition.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.*;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Defines attributes and operations for a secure-deployment.
+ */
+public class SecureDeploymentDefinition extends SimpleResourceDefinition {
+
+ static final SecureDeploymentDefinition INSTANCE = new SecureDeploymentDefinition();
+
+ private SecureDeploymentDefinition() {
+ super(PathElement.pathElement(Constants.Model.SECURE_DEPLOYMENT),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.SECURE_DEPLOYMENT),
+ SecureDeploymentAddHandler.INSTANCE,
+ ReloadRequiredRemoveStepHandler.INSTANCE);
+ }
+
+ @Override
+ public void registerOperations(ManagementResourceRegistration resourceRegistration) {
+ super.registerOperations(resourceRegistration);
+ resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderAddHandler.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderAddHandler.java
new file mode 100644
index 0000000..f9f3070
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderAddHandler.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.AbstractAddStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.dmr.ModelNode;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+class ServiceProviderAddHandler extends AbstractAddStepHandler {
+
+ static final ServiceProviderAddHandler INSTANCE = new ServiceProviderAddHandler();
+
+ ServiceProviderAddHandler() {
+ super(ServiceProviderDefinition.ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ Configuration.INSTANCE.updateModel(operation, model);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java
new file mode 100644
index 0000000..cb84f12
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.ListAttributeDefinition;
+import org.jboss.as.controller.OperationStepHandler;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.StringListAttributeDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelType;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class ServiceProviderDefinition extends SimpleResourceDefinition {
+
+ static final SimpleAttributeDefinition SSL_POLICY =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SSL_POLICY, ModelType.STRING, true)
+ .setXmlName(Constants.XML.SSL_POLICY)
+ .build();
+
+ static final SimpleAttributeDefinition NAME_ID_POLICY_FORMAT =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.NAME_ID_POLICY_FORMAT, ModelType.STRING, true)
+ .setXmlName(Constants.XML.NAME_ID_POLICY_FORMAT)
+ .build();
+
+ static final SimpleAttributeDefinition LOGOUT_PAGE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.LOGOUT_PAGE, ModelType.STRING, true)
+ .setXmlName(Constants.XML.LOGOUT_PAGE)
+ .build();
+
+ static final SimpleAttributeDefinition FORCE_AUTHENTICATION =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.FORCE_AUTHENTICATION, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.FORCE_AUTHENTICATION)
+ .build();
+
+ static final SimpleAttributeDefinition PRINCIPAL_NAME_MAPPING_POLICY =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRINCIPAL_NAME_MAPPING_POLICY, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY)
+ .build();
+
+ static final SimpleAttributeDefinition PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME, ModelType.STRING, true)
+ .setXmlName(Constants.XML.PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME)
+ .build();
+
+ static final ListAttributeDefinition ROLE_ATTRIBUTES =
+ new StringListAttributeDefinition.Builder(Constants.Model.ROLE_ATTRIBUTES)
+ .setAllowNull(false)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SSL_POLICY, NAME_ID_POLICY_FORMAT, LOGOUT_PAGE, FORCE_AUTHENTICATION};
+ static final AttributeDefinition[] ELEMENTS = {PRINCIPAL_NAME_MAPPING_POLICY, PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME, ROLE_ATTRIBUTES};
+
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+ static final HashMap<String, AttributeDefinition> ALL_MAP = new HashMap<>();
+ static final Collection<AttributeDefinition> ALL_ATTRIBUTES;
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+
+ ALL_MAP.putAll(ATTRIBUTE_MAP);
+ for (AttributeDefinition def : ELEMENTS) {
+ ALL_MAP.put(def.getXmlName(), def);
+ }
+ ALL_ATTRIBUTES = Collections.unmodifiableCollection(ALL_MAP.values());
+ }
+
+ static final ServiceProviderDefinition INSTANCE = new ServiceProviderDefinition();
+
+ private ServiceProviderDefinition() {
+ super(PathElement.pathElement(Constants.Model.SERVICE_PROVIDER),
+ KeycloakSamlExtension.getResourceDescriptionResolver(Constants.Model.SERVICE_PROVIDER),
+ ServiceProviderAddHandler.INSTANCE,
+ ReloadRequiredRemoveStepHandler.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);
+
+ final OperationStepHandler writeHandler = new ReloadRequiredWriteAttributeHandler(ALL_ATTRIBUTES);
+ for (AttributeDefinition attribute : ALL_ATTRIBUTES) {
+ resourceRegistration.registerReadWriteAttribute(attribute, null, writeHandler);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleLogoutDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleLogoutDefinition.java
new file mode 100644
index 0000000..6ad99b1
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleLogoutDefinition.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+abstract class SingleLogoutDefinition {
+
+ static final SimpleAttributeDefinition VALIDATE_REQUEST_SIGNATURE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_REQUEST_SIGNATURE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.VALIDATE_REQUEST_SIGNATURE)
+ .build();
+
+ static final SimpleAttributeDefinition VALIDATE_RESPONSE_SIGNATURE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_RESPONSE_SIGNATURE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
+ .build();
+
+ static final SimpleAttributeDefinition SIGN_REQUEST =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGN_REQUEST, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGN_REQUEST)
+ .build();
+
+ static final SimpleAttributeDefinition SIGN_RESPONSE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGN_RESPONSE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGN_RESPONSE)
+ .build();
+
+ static final SimpleAttributeDefinition REQUEST_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.REQUEST_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition RESPONSE_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.RESPONSE_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.RESPONSE_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition POST_BINDING_URL =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.POST_BINDING_URL, ModelType.STRING, true)
+ .setXmlName(Constants.XML.POST_BINDING_URL)
+ .build();
+
+ static final SimpleAttributeDefinition REDIRECT_BINDING_URL =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.REDIRECT_BINDING_URL, ModelType.STRING, true)
+ .setXmlName(Constants.XML.REDIRECT_BINDING_URL)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {VALIDATE_REQUEST_SIGNATURE, VALIDATE_RESPONSE_SIGNATURE,
+ SIGN_REQUEST, SIGN_RESPONSE, REQUEST_BINDING, RESPONSE_BINDING, POST_BINDING_URL, REDIRECT_BINDING_URL};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java
new file mode 100644
index 0000000..fe78c02
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 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.adapter.saml.extension;
+
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.dmr.ModelType;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+abstract class SingleSignOnDefinition {
+
+ static final SimpleAttributeDefinition SIGN_REQUEST =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.SIGN_REQUEST, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.SIGN_REQUEST)
+ .build();
+
+ static final SimpleAttributeDefinition VALIDATE_RESPONSE_SIGNATURE =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_RESPONSE_SIGNATURE, ModelType.BOOLEAN, true)
+ .setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
+ .build();
+
+ static final SimpleAttributeDefinition REQUEST_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.REQUEST_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition RESPONSE_BINDING =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.RESPONSE_BINDING, ModelType.STRING, true)
+ .setXmlName(Constants.XML.RESPONSE_BINDING)
+ .build();
+
+ static final SimpleAttributeDefinition BINDING_URL =
+ new SimpleAttributeDefinitionBuilder(Constants.Model.BINDING_URL, ModelType.STRING, true)
+ .setXmlName(Constants.XML.BINDING_URL)
+ .build();
+
+ static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
+
+ static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
+
+ static {
+ for (SimpleAttributeDefinition def : ATTRIBUTES) {
+ ATTRIBUTE_MAP.put(def.getXmlName(), def);
+ }
+ }
+
+ static SimpleAttributeDefinition lookup(String xmlName) {
+ return ATTRIBUTE_MAP.get(xmlName);
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties
new file mode 100755
index 0000000..f8a4a11
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties
@@ -0,0 +1,63 @@
+keycloak-saml.subsystem=Keycloak adapter subsystem
+keycloak-saml.subsystem.add=Operation Adds Keycloak adapter subsystem
+keycloak-saml.subsystem.remove=Operation removes Keycloak adapter subsystem
+keycloak-saml.subsystem.secure-deployment=A deployment secured by Keycloak.
+
+keycloak-saml.secure-deployment=A deployment secured by Keycloak
+keycloak-saml.secure-deployment.add=Add a deployment to be secured by Keycloak
+keycloak-saml.secure-deployment.remove=Remove a deployment to be secured by Keycloak
+keycloak-saml.secure-deployment.service-provider=A security provider configuration for secure deployment
+
+keycloak-saml.service-provider=A security provider configuration for secure deployment
+keycloak-saml.service-provider.add=Add a security provider configuration to deployment secured by Keycloak SAML
+keycloak-saml.service-provider.remove=Remove a security provider definition from deployment secured by Keycloak SAML
+keycloak-saml.service-provider.ssl-policy=SSL Policy to use
+keycloak-saml.service-provider.name-id-policy-format=Name ID policy format URN
+keycloak-saml.service-provider.logout-page=URI to a logout page
+keycloak-saml.service-provider.force-authentication=Redirected unauthenticated request to a login page
+keycloak-saml.service-provider.role-attributes=Role identifiers
+keycloak-saml.service-provider.principal-name-mapping-policy=Principal name mapping policy
+keycloak-saml.service-provider.principal-name-mapping-attribute-name=Principal name mapping attribute name
+keycloak-saml.service-provider.key=A key definition
+keycloak-saml.service-provider.identity-provider=Identity provider definition
+
+keycloak-saml.key=A key configuration for service provider or identity provider
+keycloak-saml.key.add=Add a key definition
+keycloak-saml.key.remove=Remove a key definition
+keycloak-saml.key.signing=Key can be used for signing
+keycloak-saml.key.encryption=Key can be used for encryption
+keycloak-saml.key.private-key-pem=Private key string in pem format
+keycloak-saml.key.public-key-pem=Public key string in pem format
+keycloak-saml.key.certificate-pem=Certificate key string in pem format
+keycloak-saml.key.key-store=Key store definition
+keycloak-saml.key.key-store.file=Key store filesystem path
+keycloak-saml.key.key-store.resource=Key store resource URI
+keycloak-saml.key.key-store.password=Key store password
+keycloak-saml.key.key-store.type=Key store format
+keycloak-saml.key.key-store.alias=Key alias
+keycloak-saml.key.key-store.private-key-alias=Private key alias
+keycloak-saml.key.key-store.private-key-password=Private key password
+keycloak-saml.key.key-store.certificate-alias=Certificate alias
+
+keycloak-saml.identity-provider=An identity provider configuration
+keycloak-saml.identity-provider.add=Add an identity provider
+keycloak-saml.identity-provider.remove=Remove an identity provider
+keycloak-saml.identity-provider.signatures-required=Require signatures for single-sign-on and single-logout
+keycloak-saml.identity-provider.signature-algorithm=Signature algorithm
+keycloak-saml.identity-provider.signature-canonicalization-method=Signature canonicalization method
+keycloak-saml.identity-provider.single-sign-on=Single sign-on configuration
+keycloak-saml.identity-provider.single-sign-on.sign-request=Sign SSO requests
+keycloak-saml.identity-provider.single-sign-on.validate-response-signature=Validate an SSO response signature
+keycloak-saml.identity-provider.single-sign-on.request-binding=HTTP method to use for requests
+keycloak-saml.identity-provider.single-sign-on.response-binding=HTTP method to use for responses
+keycloak-saml.identity-provider.single-sign-on.binding-url=SSO endpoint URL
+keycloak-saml.identity-provider.single-logout=Single logout configuration
+keycloak-saml.identity-provider.single-logout.validate-request-signature=Validate a single-logout request signature
+keycloak-saml.identity-provider.single-logout.validate-response-signature=Validate a single-logout response signature
+keycloak-saml.identity-provider.single-logout.sign-request=Sign single-logout requests
+keycloak-saml.identity-provider.single-logout.sign-response=Sign single-logout responses
+keycloak-saml.identity-provider.single-logout.request-binding=HTTP method to use for request
+keycloak-saml.identity-provider.single-logout.response-binding=HTTP method to use for response
+keycloak-saml.identity-provider.single-logout.post-binding-url=Endpoint URL for posting
+keycloak-saml.identity-provider.single-logout.redirect-binding-url=Endpoint URL for redirects
+keycloak-saml.identity-provider.key=Key definition for identity provider
\ No newline at end of file
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
new file mode 100755
index 0000000..725104b
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="urn:jboss:domain:keycloak-saml:1.1"
+ xmlns="urn:jboss:domain:keycloak-saml:1.1"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ version="1.0">
+
+ <!-- The subsystem root element -->
+ <xs:element name="subsystem" type="subsystem-type"/>
+
+ <xs:complexType name="subsystem-type">
+ <xs:annotation>
+ <xs:documentation>
+ <![CDATA[
+ The Keycloak SAML adapter subsystem, used to register deployments managed by Keycloak SAML adapter
+ ]]>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:all>
+ <xs:element name="secure-deployment" minOccurs="0" type="secure-deployment-type"/>
+ </xs:all>
+ </xs:complexType>
+
+ <xs:complexType name="secure-deployment-type">
+ <xs:all>
+ <xs:element name="SP" minOccurs="1" maxOccurs="1" type="sp-type"/>
+ </xs:all>
+ <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:complexType>
+
+ <xs:complexType name="sp-type">
+ <xs:all>
+ <xs:element name="Keys" minOccurs="0" maxOccurs="1" type="keys-type"/>
+ <xs:element name="PrincipalNameMapping" minOccurs="0" maxOccurs="1" type="principal-name-mapping-type"/>
+ <xs:element name="RoleIdentifiers" minOccurs="0" maxOccurs="1" type="role-identifiers-type"/>
+ <xs:element name="IDP" minOccurs="1" maxOccurs="1" type="identity-provider-type"/>
+ </xs:all>
+ <xs:attribute name="entityID" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The entity ID for SAML service provider</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="sslPolicy" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The ssl policy</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="nameIDPolicyFormat" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Name ID policy format URN</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="logoutPage" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>URI to a logout page</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="forceAuthentication" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>Redirected unauthenticated request to a login page</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="identity-provider-type">
+ <xs:all minOccurs="1" maxOccurs="1">
+ <xs:element name="SingleSignOnService" minOccurs="1" maxOccurs="1" type="single-signon-type"/>
+ <xs:element name="SingleLogoutService" minOccurs="0" maxOccurs="1" type="single-logout-type"/>
+ <xs:element name="Keys" minOccurs="0" maxOccurs="1" type="keys-type"/>
+ </xs:all>
+ <xs:attribute name="entityID" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The entity ID for SAML service provider</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signaturesRequired" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>Require signatures for single-sign-on and single-logout</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signatureAlgorithm" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Algorithm used for signatures</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signatureCanonicalizationMethod" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Canonicalization method used for signatures</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="single-signon-type">
+ <xs:attribute name="signRequest" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sign the SSO requests</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Validate the SSO response signature</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requestBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for requests</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="responseBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for response</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="bindingUrl" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>SSO endpoint URL</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="single-logout-type">
+ <xs:attribute name="validateRequestSignature" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Validate a single-logout request signature</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Validate a single-logout response signature</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signRequest" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sign single-logout requests</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="signResponse" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sign single-logout responses</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requestBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for request</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="responseBinding" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>HTTP method to use for response</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="postBindingUrl" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Endpoint URL for posting</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="redirectBindingUrl" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Endpoint URL for redirects</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="keys-type">
+ <xs:sequence>
+ <xs:element name="Key" minOccurs="1" maxOccurs="2" type="key-type"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="key-type">
+ <xs:all>
+ <xs:element name="KeyStore" minOccurs="0" maxOccurs="1" type="keystore-type"/>
+ <xs:element name="PrivateKeyPem" minOccurs="0" maxOccurs="1" type="xs:string"/>
+ <xs:element name="PublicKeyPem" minOccurs="0" maxOccurs="1" type="xs:string"/>
+ <xs:element name="CertificatePem" minOccurs="0" maxOccurs="1" type="xs:string"/>
+ </xs:all>
+ <xs:attribute name="signing" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key can be used for signing</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="encryption" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key can be used for encryption</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="keystore-type">
+ <xs:sequence minOccurs="0" maxOccurs="1">
+ <xs:element name="PrivateKey" minOccurs="0" maxOccurs="1" type="privatekey-type"/>
+ <xs:element name="Certificate" minOccurs="0" maxOccurs="1" type="certificate-type"/>
+ </xs:sequence>
+ <xs:attribute name="file" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key store filesystem path</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="resource" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key store resource URI</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="password" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Key store password</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key store format</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="alias" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Key alias</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="privatekey-type">
+ <xs:attribute name="alias" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Private key alias</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="password" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Private key password</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="certificate-type">
+ <xs:attribute name="alias" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Certificate alias</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="principal-name-mapping-type">
+ <xs:attribute name="policy" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Principal name mapping policy. Possible values: FROM_NAME_ID</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="attribute" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the attribute to use for principal name mapping</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="role-identifiers-type">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="Attribute" minOccurs="0" maxOccurs="unbounded" type="attribute-type"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="attribute-type">
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Role attribute</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/saml/extension/SubsystemParsingTestCase.java b/saml/client-adapter/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/saml/extension/SubsystemParsingTestCase.java
new file mode 100755
index 0000000..fdd8ee2
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/saml/extension/SubsystemParsingTestCase.java
@@ -0,0 +1,56 @@
+/*
+ * 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.adapter.saml.extension;
+
+import org.jboss.as.subsystem.test.AbstractSubsystemBaseTest;
+
+import java.io.IOException;
+
+
+/**
+ * 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>
+ * @author Tomaz Cerar
+ * @author <a href="marko.strukelj@gmail.com">Marko Strukelj</a>
+ */
+public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
+
+ public SubsystemParsingTestCase() {
+ super(KeycloakSamlExtension.SUBSYSTEM_NAME, new KeycloakSamlExtension());
+ }
+
+ @Override
+ protected String getSubsystemXml() throws IOException {
+ return readResource("keycloak-saml-1.1.xml");
+ }
+
+ @Override
+ protected String getSubsystemXsdPath() throws Exception {
+ return "schema/wildfly-keycloak-saml_1_1.xsd";
+ }
+
+ @Override
+ protected String[] getSubsystemTemplatePaths() throws IOException {
+ return new String[]{
+ "/subsystem-templates/keycloak-saml-adapter.xml"
+ };
+ }
+}
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml b/saml/client-adapter/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml
new file mode 100644
index 0000000..6f56fb0
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml
@@ -0,0 +1,50 @@
+<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
+ <secure-deployment name="my-app.war">
+ <SP entityID="http://localhost:8080/sales-post-enc/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+
+ <Keys>
+ <Key encryption="true" signing="true">
+ <PrivateKeyPem>my_key.pem</PrivateKeyPem>
+ <PublicKeyPem>my_key.pub</PublicKeyPem>
+ <CertificatePem>cert.cer</CertificatePem>
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123" file="test" alias="test" type="jks">
+ <PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
+ <Certificate alias="http://localhost:8080/sales-post-enc/"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ <PrincipalNameMapping policy="FROM_NAME_ID" attribute="test"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ <Attribute name="Role2"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test">
+ <SingleSignOnService signRequest="true"
+ validateResponseSignature="true"
+ requestBinding="POST"
+ responseBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+ <SingleLogoutService
+ validateRequestSignature="true"
+ validateResponseSignature="true"
+ signRequest="true"
+ signResponse="true"
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+ <Keys>
+ <Key signing="true">
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <Certificate alias="saml-demo"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ </IDP>
+ </SP>
+ </secure-deployment>
+</subsystem>
\ No newline at end of file
diff --git a/saml/client-adapter/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1-err.xml b/saml/client-adapter/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1-err.xml
new file mode 100644
index 0000000..26d0e98
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1-err.xml
@@ -0,0 +1,50 @@
+<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
+ <secure-deployment name="my-app.war">
+ <SP entityID="http://localhost:8080/sales-post-enc/"
+ sslPolicy="EXTERNAL"
+ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+ logoutPage="/logout.jsp"
+ forceAuthentication="false">
+
+ <Keys>
+ <Key encryption="true" signing="true">
+ <PrivateKeyPem>my_key.pem</PrivateKeyPem>
+ <PublicKeyPem>my_key.pub</PublicKeyPem>
+ <CertificatePem>cert.cer</CertificatePem>
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123" file="test" alias="test" type="jks">
+ <PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
+ <Certificate alias="http://localhost:8080/sales-post-enc/"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ <PrincipalNameMapping policy="FROM_NAME_ID" attribute="test"/>
+ <RoleIdentifiers>
+ <Attribute name="Role"/>
+ <Attribute name="Role2"/>
+ </RoleIdentifiers>
+ <IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test" encryption="test">
+ <SingleSignOnService signRequest="true"
+ validateResponseSignature="true"
+ requestBinding="POST"
+ responseBinding="POST"
+ bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+ <SingleLogoutService
+ validateRequestSignature="true"
+ validateResponseSignature="true"
+ signRequest="true"
+ signResponse="true"
+ requestBinding="POST"
+ responseBinding="POST"
+ postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
+ redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
+ <Keys>
+ <Key signing="true">
+ <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+ <Certificate alias="saml-demo"/>
+ </KeyStore>
+ </Key>
+ </Keys>
+ </IDP>
+ </SP>
+ </secure-deployment>
+</subsystem>
\ No newline at end of file