Merge pull request #1894 from mstruk/saml-subsystem
KEYCLOAK-1924 SAML adapter full subsystem EAP/Wildfly
This commit is contained in:
commit
83fa03e8cc
89 changed files with 5174 additions and 236 deletions
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
<version>1.7.0.Final-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Wildfly 9 SAML Adapter</name>
|
||||
<name>Keycloak Wildfly SAML Adapter</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-saml-wf9-adapter-dist-pom</artifactId>
|
||||
<artifactId>keycloak-saml-wildfly-adapter-dist-pom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>wf9-modules</module>
|
||||
<module>wf9-adapter-zip</module>
|
||||
<module>wildfly-modules</module>
|
||||
<module>wildfly-adapter-zip</module>
|
||||
</modules>
|
||||
</project>
|
|
@ -18,7 +18,7 @@
|
|||
<include>org/keycloak/keycloak-jboss-adapter-core/**</include>
|
||||
<include>org/keycloak/keycloak-saml-undertow-adapter/**</include>
|
||||
<include>org/keycloak/keycloak-saml-wildfly-adapter/**</include>
|
||||
<include>org/keycloak/keycloak-saml-wf9-subsystem/**</include>
|
||||
<include>org/keycloak/keycloak-saml-wildfly-subsystem/**</include>
|
||||
<include>org/keycloak/keycloak-saml-adapter-subsystem/**</include>
|
||||
</includes>
|
||||
<excludes>
|
|
@ -8,15 +8,15 @@
|
|||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-saml-wf9-adapter-dist</artifactId>
|
||||
<artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Keycloak SAML Wildfly 9 Adapter Distro</name>
|
||||
<name>Keycloak SAML Wildfly Adapter Distro</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-wf9-modules</artifactId>
|
||||
<artifactId>keycloak-saml-wildfly-modules</artifactId>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-wf9-modules</artifactId>
|
||||
<artifactId>keycloak-saml-wildfly-modules</artifactId>
|
||||
<type>zip</type>
|
||||
<outputDirectory>${project.build.directory}/unpacked</outputDirectory>
|
||||
</artifactItem>
|
|
@ -69,8 +69,8 @@
|
|||
<maven-resource group="org.keycloak" artifact="keycloak-saml-wildfly-adapter"/>
|
||||
</module-def>
|
||||
|
||||
<module-def name="org.keycloak.keycloak-saml-wf9-subsystem">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-saml-wf9-subsystem"/>
|
||||
<module-def name="org.keycloak.keycloak-saml-wildfly-subsystem">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-saml-wildfly-subsystem"/>
|
||||
</module-def>
|
||||
|
||||
</target>
|
|
@ -12,9 +12,9 @@
|
|||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-saml-wf9-modules</artifactId>
|
||||
<artifactId>keycloak-saml-wildfly-modules</artifactId>
|
||||
|
||||
<name>Keycloak SAML Wildfly 9 Modules</name>
|
||||
<name>Keycloak SAML Wildfly Modules</name>
|
||||
<packaging>pom</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -51,7 +51,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-wf9-subsystem</artifactId>
|
||||
<artifactId>keycloak-saml-wildfly-subsystem</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
@ -30,6 +30,6 @@
|
|||
</resources>
|
||||
|
||||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-saml-wf9-subsystem" export="true" services="export"/>
|
||||
<module name="org.keycloak.keycloak-saml-wildfly-subsystem" export="true" services="export"/>
|
||||
</dependencies>
|
||||
</module>
|
|
@ -22,7 +22,7 @@
|
|||
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
-->
|
||||
|
||||
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-saml-wf9-subsystem">
|
||||
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-saml-wildfly-subsystem">
|
||||
|
||||
<resources>
|
||||
<resource-root path="."/>
|
|
@ -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>
|
6
pom.xml
6
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>
|
||||
|
|
|
@ -30,10 +30,6 @@
|
|||
<groupId>org.keycloak</groupId>
|
||||
<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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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,14 +67,68 @@ 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 (webRequiresKC) {
|
||||
log.debug("Setting up KEYCLOAK-SAML auth method for WAR: " + deploymentName);
|
||||
addValve(webMetaData);
|
||||
// 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
List<ValveMetaData> valves = webMetaData.getValves();
|
||||
if (valves == null) {
|
||||
|
@ -89,5 +146,4 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
|
|||
public void undeploy(DeploymentUnit du) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -15,6 +15,6 @@
|
|||
|
||||
<modules>
|
||||
<module>wildfly-adapter</module>
|
||||
<module>wildfly9-subsystem</module>
|
||||
<module>wildfly-subsystem</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-saml-wf9-subsystem</artifactId>
|
||||
<name>Keycloak Wildfly 9 SAML Adapter Subsystem</name>
|
||||
<artifactId>keycloak-saml-wildfly-subsystem</artifactId>
|
||||
<name>Keycloak Wildfly SAML Adapter Subsystem</name>
|
||||
<description/>
|
||||
<packaging>jar</packaging>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.subsystem.adapter.saml.extension;
|
||||
|
||||
import org.jboss.as.server.deployment.DeploymentPhaseContext;
|
||||
import org.jboss.as.server.deployment.DeploymentUnit;
|
||||
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
|
||||
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
|
||||
import org.jboss.as.web.common.WarMetaData;
|
||||
import org.jboss.dmr.ModelNode;
|
||||
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
|
||||
import org.jboss.metadata.web.jboss.JBossWebMetaData;
|
||||
import org.jboss.metadata.web.spec.LoginConfigMetaData;
|
||||
import org.jboss.staxmapper.FormattingXMLStreamWriter;
|
||||
import org.jboss.staxmapper.XMLExtendedStreamWriter;
|
||||
import org.keycloak.adapters.saml.AdapterConstants;
|
||||
import org.keycloak.subsystem.adapter.saml.extension.logging.KeycloakLogger;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Pass authentication data (keycloak.json) as a servlet context param so it can be read by the KeycloakServletExtension.
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||
*/
|
||||
public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitProcessor {
|
||||
|
||||
@Override
|
||||
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
|
||||
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||
|
||||
String deploymentName = deploymentUnit.getName();
|
||||
if (Configuration.INSTANCE.getSecureDeployment(deploymentName) != null) {
|
||||
addKeycloakSamlAuthData(phaseContext, deploymentName);
|
||||
}
|
||||
}
|
||||
|
||||
private void addKeycloakSamlAuthData(DeploymentPhaseContext phaseContext, String deploymentName) throws DeploymentUnitProcessingException {
|
||||
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
|
||||
if (warMetaData == null) {
|
||||
throw new DeploymentUnitProcessingException("WarMetaData not found for " + deploymentName + ". Make sure you have specified a WAR as your secure-deployment in the Keycloak subsystem.");
|
||||
}
|
||||
|
||||
try {
|
||||
addXMLData(getXML(deploymentName), warMetaData);
|
||||
} catch (Exception e) {
|
||||
throw new DeploymentUnitProcessingException("Failed to configure KeycloakSamlExtension from subsystem model", e);
|
||||
}
|
||||
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
|
||||
if (webMetaData == null) {
|
||||
webMetaData = new JBossWebMetaData();
|
||||
warMetaData.setMergedJBossWebMetaData(webMetaData);
|
||||
}
|
||||
|
||||
LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
|
||||
if (loginConfig == null) {
|
||||
loginConfig = new LoginConfigMetaData();
|
||||
webMetaData.setLoginConfig(loginConfig);
|
||||
}
|
||||
loginConfig.setAuthMethod("KEYCLOAK-SAML");
|
||||
|
||||
KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undeploy(DeploymentUnit du) {
|
||||
|
||||
}
|
||||
}
|
|
@ -29,7 +29,6 @@ import org.jboss.modules.ModuleIdentifier;
|
|||
import org.jboss.modules.ModuleLoader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||
*/
|
||||
public abstract class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
|
|
@ -37,13 +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 ModelVersion MGMT_API_VERSION = ModelVersion.create(1,1,0);
|
||||
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);
|
||||
|
@ -68,7 +67,12 @@ public class KeycloakSamlExtension implements Extension {
|
|||
public void initialize(final ExtensionContext context) {
|
||||
final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, MGMT_API_VERSION);
|
||||
|
||||
ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
|
||||
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);
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.keycloak.subsystem.adapter.saml.extension;
|
||||
|
||||
|
||||
import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
|
||||
import org.jboss.as.controller.OperationContext;
|
||||
import org.jboss.as.server.AbstractDeploymentChainStep;
|
|
@ -14,7 +14,6 @@
|
|||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.subsystem.adapter.saml.extension;
|
||||
|
||||
import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
|
||||
|
@ -23,12 +22,15 @@ import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler
|
|||
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||
|
||||
/**
|
||||
* 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,5 +43,4 @@ public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
|
|||
super.registerOperations(resourceRegistration);
|
||||
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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>
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Template used by WildFly build when directed to include Keycloak subsystem in a configuration. -->
|
||||
<!-- Template used by WildFly build when directed to include Keycloak SAML subsystem in a configuration. -->
|
||||
<config>
|
||||
<extension-module>org.keycloak.keycloak-saml-adapter-subsystem</extension-module>
|
||||
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.6">
|
||||
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
|
||||
</subsystem>
|
||||
</config>
|
|
@ -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"
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.subsystem.adapter.saml.extension;
|
||||
|
||||
import org.jboss.as.server.deployment.DeploymentPhaseContext;
|
||||
import org.jboss.as.server.deployment.DeploymentUnit;
|
||||
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
|
||||
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
|
||||
import org.jboss.as.web.common.WarMetaData;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
|
||||
import org.jboss.metadata.web.jboss.JBossWebMetaData;
|
||||
import org.jboss.metadata.web.spec.LoginConfigMetaData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Pass authentication data (keycloak.json) as a servlet context param so it can be read by the KeycloakServletExtension.
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||
*/
|
||||
public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitProcessor {
|
||||
protected Logger log = Logger.getLogger(KeycloakAdapterConfigDeploymentProcessor.class);
|
||||
|
||||
@Override
|
||||
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
|
||||
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||
|
||||
String deploymentName = deploymentUnit.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undeploy(DeploymentUnit du) {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package org.keycloak.subsystem.adapter.saml.extension;
|
||||
|
||||
import org.jboss.as.controller.AttributeDefinition;
|
||||
import org.jboss.as.controller.PathAddress;
|
||||
import org.jboss.as.controller.PathElement;
|
||||
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
|
||||
import org.jboss.as.controller.operations.common.Util;
|
||||
import org.jboss.as.controller.parsing.ParseUtils;
|
||||
import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
|
||||
import org.jboss.dmr.ModelNode;
|
||||
import org.jboss.dmr.Property;
|
||||
import org.jboss.staxmapper.XMLElementReader;
|
||||
import org.jboss.staxmapper.XMLElementWriter;
|
||||
import org.jboss.staxmapper.XMLExtendedStreamReader;
|
||||
import org.jboss.staxmapper.XMLExtendedStreamWriter;
|
||||
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
}
|
||||
}
|
||||
|
||||
// used for debugging
|
||||
private int nextTag(XMLExtendedStreamReader reader) throws XMLStreamException {
|
||||
return reader.nextTag();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
|
||||
context.startSubsystemElement(KeycloakSamlExtension.NAMESPACE, false);
|
||||
writer.writeEndElement();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// code taken from org.jboss.as.controller.AttributeMarshaller
|
||||
private void writeCharacters(XMLExtendedStreamWriter writer, String content) throws XMLStreamException {
|
||||
if (content.indexOf('\n') > -1) {
|
||||
// Multiline content. Use the overloaded variant that staxmapper will format
|
||||
writer.writeCharacters(content);
|
||||
} else {
|
||||
// Staxmapper will just output the chars without adding newlines if this is used
|
||||
char[] chars = content.toCharArray();
|
||||
writer.writeCharacters(chars, 0, chars.length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue