Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
143d176dcd
132 changed files with 8240 additions and 182 deletions
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.representations.idm;
|
package org.keycloak.representations.idm;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +12,7 @@ public class UserFederationMapperTypeRepresentation {
|
||||||
protected String category;
|
protected String category;
|
||||||
protected String helpText;
|
protected String helpText;
|
||||||
|
|
||||||
protected List<ConfigPropertyRepresentation> properties;
|
protected List<ConfigPropertyRepresentation> properties = new LinkedList<>();
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
|
|
|
@ -38,5 +38,6 @@
|
||||||
<module>tomcat7-adapter-zip</module>
|
<module>tomcat7-adapter-zip</module>
|
||||||
<module>tomcat8-adapter-zip</module>
|
<module>tomcat8-adapter-zip</module>
|
||||||
<module>wildfly-adapter-zip</module>
|
<module>wildfly-adapter-zip</module>
|
||||||
|
<module>wf8-adapter</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
|
|
20
distribution/adapters/wf8-adapter/pom.xml
Normal file
20
distribution/adapters/wf8-adapter/pom.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.3.0.Final-SNAPSHOT</version>
|
||||||
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<name>Keycloak Wildfly 8 Adapter</name>
|
||||||
|
<description/>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>keycloak-wf8-adapter-dist-pom</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>wf8-modules</module>
|
||||||
|
<module>wf8-adapter-zip</module>
|
||||||
|
</modules>
|
||||||
|
</project>
|
29
distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml
Executable file
29
distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
<assembly>
|
||||||
|
<id>war-dist</id>
|
||||||
|
|
||||||
|
<formats>
|
||||||
|
<format>zip</format>
|
||||||
|
<format>tar.gz</format>
|
||||||
|
</formats>
|
||||||
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
|
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.build.directory}/unpacked</directory>
|
||||||
|
<includes>
|
||||||
|
<include>net/iharder/base64/**</include>
|
||||||
|
<include>org/apache/httpcomponents/**</include>
|
||||||
|
<include>org/keycloak/keycloak-core/**</include>
|
||||||
|
<include>org/keycloak/keycloak-adapter-core/**</include>
|
||||||
|
<include>org/keycloak/keycloak-jboss-adapter-core/**</include>
|
||||||
|
<include>org/keycloak/keycloak-undertow-adapter/**</include>
|
||||||
|
<include>org/keycloak/keycloak-wildfly-adapter/**</include>
|
||||||
|
<include>org/keycloak/keycloak-wf8-subsystem/**</include>
|
||||||
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/*.war</exclude>
|
||||||
|
</excludes>
|
||||||
|
<outputDirectory>modules/system/layers/base</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
</assembly>
|
76
distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
Executable file
76
distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
Executable file
|
@ -0,0 +1,76 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.3.0.Final-SNAPSHOT</version>
|
||||||
|
<relativePath>../../../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>keycloak-wf8-adapter-dist</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<name>Keycloak Wildfly 8 Adapter Distro</name>
|
||||||
|
<description/>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-wf8-modules</artifactId>
|
||||||
|
<type>zip</type>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>unpack</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-wf8-modules</artifactId>
|
||||||
|
<type>zip</type>
|
||||||
|
<outputDirectory>${project.build.directory}/unpacked</outputDirectory>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>assemble</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>assembly.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
<outputDirectory>
|
||||||
|
target
|
||||||
|
</outputDirectory>
|
||||||
|
<workDirectory>
|
||||||
|
target/assembly/work
|
||||||
|
</workDirectory>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
22
distribution/adapters/wf8-adapter/wf8-modules/assembly.xml
Executable file
22
distribution/adapters/wf8-adapter/wf8-modules/assembly.xml
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
<assembly>
|
||||||
|
<id>dist</id>
|
||||||
|
|
||||||
|
<formats>
|
||||||
|
<format>zip</format>
|
||||||
|
</formats>
|
||||||
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
|
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>../../</directory>
|
||||||
|
<includes>
|
||||||
|
<include>License.html</include>
|
||||||
|
</includes>
|
||||||
|
<outputDirectory></outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.build.directory}/modules</directory>
|
||||||
|
<outputDirectory></outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
</assembly>
|
88
distribution/adapters/wf8-adapter/wf8-modules/build.xml
Executable file
88
distribution/adapters/wf8-adapter/wf8-modules/build.xml
Executable file
|
@ -0,0 +1,88 @@
|
||||||
|
<!--
|
||||||
|
~ JBoss, Home of Professional Open Source.
|
||||||
|
~ Copyright 2012, 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project name="module-repository" basedir="." default="all">
|
||||||
|
|
||||||
|
<import file="lib.xml"/>
|
||||||
|
|
||||||
|
<property name="output.dir" value="target"/>
|
||||||
|
|
||||||
|
<target name="all">
|
||||||
|
<antcall target="modules">
|
||||||
|
<param name="mavenized.modules" value="false"/>
|
||||||
|
<param name="output.dir" value="target"/>
|
||||||
|
</antcall>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
|
||||||
|
<target name="modules">
|
||||||
|
|
||||||
|
<!-- server min dependencies -->
|
||||||
|
|
||||||
|
<module-def name="org.keycloak.keycloak-core">
|
||||||
|
<maven-resource group="org.keycloak" artifact="keycloak-core"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
<module-def name="net.iharder.base64">
|
||||||
|
<maven-resource group="net.iharder" artifact="base64"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- subsystems -->
|
||||||
|
|
||||||
|
<module-def name="org.keycloak.keycloak-adapter-core">
|
||||||
|
<maven-resource group="org.keycloak" artifact="keycloak-adapter-core"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
<module-def name="org.keycloak.keycloak-jboss-adapter-core">
|
||||||
|
<maven-resource group="org.keycloak" artifact="keycloak-jboss-adapter-core"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
<module-def name="org.keycloak.keycloak-undertow-adapter">
|
||||||
|
<maven-resource group="org.keycloak" artifact="keycloak-undertow-adapter"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
<module-def name="org.keycloak.keycloak-wildfly-adapter">
|
||||||
|
<maven-resource group="org.keycloak" artifact="keycloak-wildfly-adapter"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
<module-def name="org.keycloak.keycloak-wf8-subsystem">
|
||||||
|
<maven-resource group="org.keycloak" artifact="keycloak-wf8-subsystem"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
<module-def name="org.apache.httpcomponents" slot="4.3">
|
||||||
|
<maven-resource group="org.apache.httpcomponents" artifact="httpclient"/>
|
||||||
|
<maven-resource group="org.apache.httpcomponents" artifact="httpcore"/>
|
||||||
|
<maven-resource group="org.apache.httpcomponents" artifact="httpmime"/>
|
||||||
|
</module-def>
|
||||||
|
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clean-target">
|
||||||
|
<delete dir="${output.dir}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clean" depends="clean-target">
|
||||||
|
<delete file="maven-ant-tasks.jar"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
</project>
|
282
distribution/adapters/wf8-adapter/wf8-modules/lib.xml
Executable file
282
distribution/adapters/wf8-adapter/wf8-modules/lib.xml
Executable file
|
@ -0,0 +1,282 @@
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project name="module-repository-lib">
|
||||||
|
|
||||||
|
<property name="src.dir" value="src"/>
|
||||||
|
<property name="module.repo.src.dir" value="${src.dir}/main/resources/modules"/>
|
||||||
|
<property name="module.xml" value="module.xml"/>
|
||||||
|
|
||||||
|
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
|
||||||
|
<taskdef name="jandex" classname="org.jboss.jandex.JandexAntTask" />
|
||||||
|
|
||||||
|
<macrodef name="module-def">
|
||||||
|
<attribute name="name"/>
|
||||||
|
<attribute name="slot" default="main"/>
|
||||||
|
<element name="resources" implicit="yes" optional="yes"/>
|
||||||
|
|
||||||
|
<sequential>
|
||||||
|
<echo message="Initializing module -> @{name}"/>
|
||||||
|
<property name="module.repo.output.dir" value="${output.dir}/modules"/>
|
||||||
|
<!-- Figure out the correct module path -->
|
||||||
|
<define-module-dir name="@{name}" slot="@{slot}"/>
|
||||||
|
|
||||||
|
<!-- Make the module output director -->
|
||||||
|
<mkdir dir="${module.repo.output.dir}/${current.module.path}"/>
|
||||||
|
|
||||||
|
<!-- Copy the module.xml and other stuff to the output director -->
|
||||||
|
<copy todir="${module.repo.output.dir}/${current.module.path}" overwrite="true">
|
||||||
|
<fileset dir="${module.repo.src.dir}/${current.module.path}">
|
||||||
|
<include name="**"/>
|
||||||
|
</fileset>
|
||||||
|
</copy>
|
||||||
|
|
||||||
|
<!-- Process the resource -->
|
||||||
|
<resources/>
|
||||||
|
|
||||||
|
<!-- Add keycloak version property to module xml -->
|
||||||
|
<replace file="${module.repo.output.dir}/${current.module.path}/${module.xml}"
|
||||||
|
token="$${project.version}"
|
||||||
|
value="${project.version}"/>
|
||||||
|
|
||||||
|
<!-- Some final cleanup -->
|
||||||
|
<replace file="${module.repo.output.dir}/${current.module.path}/${module.xml}">
|
||||||
|
<replacetoken>
|
||||||
|
<![CDATA[
|
||||||
|
<!-- Insert resources here -->]]></replacetoken>
|
||||||
|
<replacevalue>
|
||||||
|
</replacevalue>
|
||||||
|
</replace>
|
||||||
|
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<macrodef name="bundle-def">
|
||||||
|
<attribute name="name"/>
|
||||||
|
<attribute name="slot" default="main"/>
|
||||||
|
<element name="resources" implicit="yes" optional="yes"/>
|
||||||
|
|
||||||
|
<sequential>
|
||||||
|
<echo message="Initializing bundle -> @{name}"/>
|
||||||
|
<property name="bundle.repo.output.dir" value="${output.dir}/bundles/system/layers/base"/>
|
||||||
|
<!-- Figure out the correct bundle path -->
|
||||||
|
<define-bundle-dir name="@{name}" slot="@{slot}" />
|
||||||
|
|
||||||
|
<!-- Make the bundle output director -->
|
||||||
|
<mkdir dir="${bundle.repo.output.dir}/${current.bundle.path}"/>
|
||||||
|
|
||||||
|
<!-- Process the resource -->
|
||||||
|
<resources/>
|
||||||
|
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<macrodef name="maven-bundle" >
|
||||||
|
<attribute name="group"/>
|
||||||
|
<attribute name="artifact"/>
|
||||||
|
|
||||||
|
<sequential>
|
||||||
|
<!-- Copy the jar to the bundle dir -->
|
||||||
|
<property name="bundle.repo.output.dir" value="${output.dir}/bundles/system/layers/base"/>
|
||||||
|
<copy todir="${bundle.repo.output.dir}/${current.bundle.path}" failonerror="true">
|
||||||
|
<fileset file="${@{group}:@{artifact}:jar}"/>
|
||||||
|
<mapper type="flatten" />
|
||||||
|
</copy>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<scriptdef name="define-module-dir" language="javascript" manager="bsf">
|
||||||
|
<attribute name="name"/>
|
||||||
|
<attribute name="slot"/>
|
||||||
|
<![CDATA[
|
||||||
|
name = attributes.get("name");
|
||||||
|
name = name.replace(".", "/");
|
||||||
|
project.setProperty("current.module.path", name + "/" + attributes.get("slot"));
|
||||||
|
]]>
|
||||||
|
</scriptdef>
|
||||||
|
|
||||||
|
<scriptdef name="define-bundle-dir" language="javascript" manager="bsf">
|
||||||
|
<attribute name="name"/>
|
||||||
|
<attribute name="slot"/>
|
||||||
|
<![CDATA[
|
||||||
|
name = attributes.get("name");
|
||||||
|
name = name.replace(".", "/");
|
||||||
|
project.setProperty("current.bundle.path", name + "/" + attributes.get("slot"));
|
||||||
|
]]>
|
||||||
|
</scriptdef>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Get the version from the parent directory of the jar. If the parent directory is 'target' this
|
||||||
|
means that the jar is contained in AS build so extract the version from the file name
|
||||||
|
-->
|
||||||
|
<scriptdef name="define-maven-artifact" language="javascript" manager="bsf">
|
||||||
|
<attribute name="group"/>
|
||||||
|
<attribute name="artifact"/>
|
||||||
|
<attribute name="classifier"/>
|
||||||
|
<attribute name="element"/>
|
||||||
|
<attribute name="path"/>
|
||||||
|
<![CDATA[
|
||||||
|
importClass(Packages.java.io.File);
|
||||||
|
group = attributes.get("group");
|
||||||
|
artifact = attributes.get("artifact");
|
||||||
|
classifier = attributes.get("classifier");
|
||||||
|
element = attributes.get("element");
|
||||||
|
path = attributes.get("path");
|
||||||
|
if(path.indexOf('${') != -1) {
|
||||||
|
throw "Module resource root not found, make sure it is listed in build/pom.xml" + path;
|
||||||
|
}
|
||||||
|
fp = new File(path);
|
||||||
|
version = fp.getParentFile().getName();
|
||||||
|
if (version.equals("target")) {
|
||||||
|
version = fp.getName();
|
||||||
|
version = version.substring(artifact.length() + 1);
|
||||||
|
suffix = ".jar";
|
||||||
|
if (classifier) {
|
||||||
|
suffix = "-" + classifier + suffix;
|
||||||
|
}
|
||||||
|
version = version.replace(suffix, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
root = "<" + element + " name=\"" + group + ":" + artifact + ":" + version;
|
||||||
|
if (classifier) {
|
||||||
|
root = root + ":" + classifier;
|
||||||
|
}
|
||||||
|
root = root + "\"/>";
|
||||||
|
project.setProperty("current.maven.root", root);
|
||||||
|
]]>
|
||||||
|
</scriptdef>
|
||||||
|
|
||||||
|
<macrodef name="maven-resource" >
|
||||||
|
<attribute name="group"/>
|
||||||
|
<attribute name="artifact"/>
|
||||||
|
<attribute name="jandex" default="false" />
|
||||||
|
|
||||||
|
<sequential>
|
||||||
|
<if>
|
||||||
|
<equals arg1="${mavenized.modules}" arg2="true"/>
|
||||||
|
<then>
|
||||||
|
<define-maven-artifact group="@{group}" artifact="@{artifact}" element="artifact" path="${@{group}:@{artifact}:jar}"/>
|
||||||
|
<replace file="${module.repo.output.dir}/${current.module.path}/${module.xml}">
|
||||||
|
<replacefilter token="<!-- Insert resources here -->" value="${current.maven.root} <!-- Insert resources here -->"/>
|
||||||
|
</replace>
|
||||||
|
</then>
|
||||||
|
|
||||||
|
<else>
|
||||||
|
<!-- Copy the jar to the module dir -->
|
||||||
|
<copy todir="${module.repo.output.dir}/${current.module.path}" failonerror="true">
|
||||||
|
<fileset file="${@{group}:@{artifact}:jar}"/>
|
||||||
|
<mapper type="flatten" />
|
||||||
|
</copy>
|
||||||
|
|
||||||
|
<basename file="${@{group}:@{artifact}:jar}" property="resourcename.@{group}.@{artifact}"/>
|
||||||
|
<!-- Generate the Jandex Index -->
|
||||||
|
<jandex run="@{jandex}" newJar="true" >
|
||||||
|
<fileset dir="${module.repo.output.dir}/${current.module.path}" />
|
||||||
|
</jandex>
|
||||||
|
<!-- Update the resource entry in module.xml -->
|
||||||
|
<define-resource-root path="${resourcename.@{group}.@{artifact}}" jandex="@{jandex}"/>
|
||||||
|
<replace file="${module.repo.output.dir}/${current.module.path}/${module.xml}">
|
||||||
|
<replacefilter token="<!-- Insert resources here -->" value="${current.resource.root} <!-- Insert resources here -->"/>
|
||||||
|
</replace>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<macrodef name="maven-resource-with-classifier" >
|
||||||
|
<attribute name="group"/>
|
||||||
|
<attribute name="artifact"/>
|
||||||
|
<attribute name="classifier"/>
|
||||||
|
<attribute name="jandex" default="false" />
|
||||||
|
|
||||||
|
<sequential>
|
||||||
|
<if>
|
||||||
|
<equals arg1="${mavenized.modules}" arg2="true"/>
|
||||||
|
<then>
|
||||||
|
<define-maven-artifact group="@{group}" artifact="@{artifact}" element="artifact" classifier="@{classifier}" path="${@{group}:@{artifact}:jar:@{classifier}}"/>
|
||||||
|
<replace file="${module.repo.output.dir}/${current.module.path}/${module.xml}">
|
||||||
|
<replacefilter token="<!-- Insert resources here -->" value="${current.maven.root} <!-- Insert resources here -->"/>
|
||||||
|
</replace>
|
||||||
|
</then>
|
||||||
|
<else>
|
||||||
|
<!-- Copy the jar to the module dir -->
|
||||||
|
<copy todir="${module.repo.output.dir}/${current.module.path}" failonerror="true">
|
||||||
|
<fileset file="${@{group}:@{artifact}:jar:@{classifier}}"/>
|
||||||
|
<!-- http://jira.codehaus.org/browse/MANTRUN-159 -->
|
||||||
|
<mapper type="flatten" />
|
||||||
|
</copy>
|
||||||
|
|
||||||
|
<basename file="${@{group}:@{artifact}:jar:@{classifier}}" property="resourcename.@{group}.@{artifact}.@{classifier}"/>
|
||||||
|
|
||||||
|
<!-- Update the resource entry in module.xml -->
|
||||||
|
<define-resource-root path="${resourcename.@{group}.@{artifact}.@{classifier}}"/>
|
||||||
|
<replace file="${module.repo.output.dir}/${current.module.path}/${module.xml}">
|
||||||
|
<replacefilter token="<!-- Insert resources here -->" value="${current.resource.root} <!-- Insert resources here -->"/>
|
||||||
|
</replace>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<macrodef name="extract-native-jar" >
|
||||||
|
<attribute name="group"/>
|
||||||
|
<attribute name="artifact"/>
|
||||||
|
<sequential>
|
||||||
|
<if>
|
||||||
|
<equals arg1="${mavenized.modules}" arg2="true"/>
|
||||||
|
<then>
|
||||||
|
<define-maven-artifact group="@{group}" artifact="@{artifact}" element="native-artifact" path="${@{group}:@{artifact}:jar}"/>
|
||||||
|
<replace file="${module.repo.output.dir}/${current.module.path}/${module.xml}">
|
||||||
|
<replacefilter token="<!-- Insert resources here -->" value="${current.maven.root} <!-- Insert resources here -->"/>
|
||||||
|
</replace>
|
||||||
|
</then>
|
||||||
|
|
||||||
|
<else>
|
||||||
|
<unzip src="${@{group}:@{artifact}:jar}" dest="${module.repo.output.dir}/${current.module.path}">
|
||||||
|
<patternset>
|
||||||
|
<include name="lib/**"/>
|
||||||
|
</patternset>
|
||||||
|
</unzip>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<scriptdef name="define-resource-root" language="javascript" manager="bsf">
|
||||||
|
<attribute name="path"/>
|
||||||
|
<attribute name="jandex"/>
|
||||||
|
<![CDATA[
|
||||||
|
path = attributes.get("path");
|
||||||
|
root = "<resource-root path=\"" + path + "\"/>";
|
||||||
|
if(path.indexOf('${') != -1) {
|
||||||
|
throw "Module resource root not found, make sure it is listed in build/pom.xml" + path;
|
||||||
|
}
|
||||||
|
if(attributes.get("jandex") == "true" ) {
|
||||||
|
root = root + "\n\t<resource-root path=\"" + path.replace(".jar","-jandex.jar") + "\"/>";
|
||||||
|
}
|
||||||
|
project.setProperty("current.resource.root", root);
|
||||||
|
]]>
|
||||||
|
</scriptdef>
|
||||||
|
|
||||||
|
</project>
|
137
distribution/adapters/wf8-adapter/wf8-modules/pom.xml
Executable file
137
distribution/adapters/wf8-adapter/wf8-modules/pom.xml
Executable file
|
@ -0,0 +1,137 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.3.0.Final-SNAPSHOT</version>
|
||||||
|
<relativePath>../../../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>keycloak-wf8-modules</artifactId>
|
||||||
|
|
||||||
|
<name>Keycloak Wildfly 8 Modules</name>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-adapter-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-jboss-adapter-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-undertow-adapter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-wildfly-adapter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-wf8-subsystem</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpmime</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpcore</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-antrun-plugin</artifactId>
|
||||||
|
<inherited>false</inherited>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>build-dist</id>
|
||||||
|
<goals>
|
||||||
|
<goal>run</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<configuration>
|
||||||
|
<target>
|
||||||
|
<ant antfile="build.xml" inheritRefs="true">
|
||||||
|
<target name="all"/>
|
||||||
|
</ant>
|
||||||
|
</target>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss</groupId>
|
||||||
|
<artifactId>jandex</artifactId>
|
||||||
|
<version>1.0.3.Final</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ant-contrib</groupId>
|
||||||
|
<artifactId>ant-contrib</artifactId>
|
||||||
|
<version>1.0b3</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>ant</groupId>
|
||||||
|
<artifactId>ant</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.ant</groupId>
|
||||||
|
<artifactId>ant-apache-bsf</artifactId>
|
||||||
|
<version>1.9.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.bsf</groupId>
|
||||||
|
<artifactId>bsf-api</artifactId>
|
||||||
|
<version>3.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>rhino</groupId>
|
||||||
|
<artifactId>js</artifactId>
|
||||||
|
<version>1.7R2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>assemble</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>assembly.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
<outputDirectory>
|
||||||
|
target
|
||||||
|
</outputDirectory>
|
||||||
|
<workDirectory>
|
||||||
|
target/assembly/work
|
||||||
|
</workDirectory>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="net.iharder.base64">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</module>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.apache.httpcomponents" slot="4.3">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="org.apache.commons.codec"/>
|
||||||
|
<module name="org.apache.commons.logging"/>
|
||||||
|
<module name="org.apache.james.mime4j"/>
|
||||||
|
</dependencies>
|
||||||
|
</module>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-adapter-core">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-core-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-xc"/>
|
||||||
|
<module name="org.apache.httpcomponents" slot="4.3" />
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
<module name="net.iharder.base64"/>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</module>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-core">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
<dependencies>
|
||||||
|
<module name="org.codehaus.jackson.jackson-core-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-xc"/>
|
||||||
|
<module name="org.bouncycastle" />
|
||||||
|
<module name="net.iharder.base64"/>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="javax.activation.api"/>
|
||||||
|
<module name="sun.jdk" optional="true" />
|
||||||
|
<module name="sun.jdk.jgss" optional="true" />
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</module>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-jboss-adapter-core">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="org.picketbox"/>
|
||||||
|
<module name="org.keycloak.keycloak-adapter-core"/>
|
||||||
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</module>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-undertow-adapter">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="org.bouncycastle" />
|
||||||
|
<module name="org.codehaus.jackson.jackson-core-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-xc"/>
|
||||||
|
<module name="org.apache.httpcomponents" slot="4.3" />
|
||||||
|
<module name="javax.servlet.api"/>
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="org.jboss.xnio"/>
|
||||||
|
<module name="io.undertow.core"/>
|
||||||
|
<module name="io.undertow.servlet"/>
|
||||||
|
<module name="org.keycloak.keycloak-adapter-core"/>
|
||||||
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</module>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ JBoss, Home of Professional Open Source.
|
||||||
|
~ Copyright 2014, Red Hat, Inc., and individual contributors
|
||||||
|
~ as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
~ distribution for a full listing of individual contributors.
|
||||||
|
~
|
||||||
|
~ This is free software; you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU Lesser General Public License as
|
||||||
|
~ published by the Free Software Foundation; either version 2.1 of
|
||||||
|
~ the License, or (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This software is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
~ Lesser General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Lesser General Public
|
||||||
|
~ License along with this software; if not, write to the Free
|
||||||
|
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wf8-subsystem">
|
||||||
|
<properties>
|
||||||
|
<property name="keycloak-version" value="${project.version}"/>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<resource-root path="."/>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="org.jboss.staxmapper"/>
|
||||||
|
<module name="org.jboss.as.controller"/>
|
||||||
|
<module name="org.jboss.as.ee"/>
|
||||||
|
<module name="org.jboss.as.server"/>
|
||||||
|
<module name="org.jboss.modules"/>
|
||||||
|
<module name="org.jboss.msc"/>
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="org.jboss.vfs"/>
|
||||||
|
<module name="org.jboss.as.web-common"/>
|
||||||
|
<module name="org.jboss.metadata"/>
|
||||||
|
</dependencies>
|
||||||
|
</module>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wildfly-adapter">
|
||||||
|
<resources>
|
||||||
|
<!-- Insert resources here -->
|
||||||
|
</resources>
|
||||||
|
<dependencies>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="org.bouncycastle" />
|
||||||
|
<module name="org.codehaus.jackson.jackson-core-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
|
||||||
|
<module name="org.codehaus.jackson.jackson-xc"/>
|
||||||
|
<module name="org.apache.httpcomponents" slot="4.3" />
|
||||||
|
<module name="javax.servlet.api"/>
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="io.undertow.core"/>
|
||||||
|
<module name="io.undertow.servlet"/>
|
||||||
|
<module name="org.picketbox"/>
|
||||||
|
<module name="org.keycloak.keycloak-undertow-adapter"/>
|
||||||
|
<module name="org.keycloak.keycloak-adapter-core"/>
|
||||||
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</module>
|
|
@ -18,7 +18,7 @@
|
||||||
<include>org/keycloak/keycloak-jboss-adapter-core/**</include>
|
<include>org/keycloak/keycloak-jboss-adapter-core/**</include>
|
||||||
<include>org/keycloak/keycloak-undertow-adapter/**</include>
|
<include>org/keycloak/keycloak-undertow-adapter/**</include>
|
||||||
<include>org/keycloak/keycloak-wildfly-adapter/**</include>
|
<include>org/keycloak/keycloak-wildfly-adapter/**</include>
|
||||||
<include>org/keycloak/keycloak-subsystem/**</include>
|
<include>org/keycloak/keycloak-adapter-subsystem/**</include>
|
||||||
</includes>
|
</includes>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/*.war</exclude>
|
<exclude>**/*.war</exclude>
|
||||||
|
|
|
@ -7,10 +7,10 @@ import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.constants.ServiceUrlConstants;
|
import org.keycloak.constants.ServiceUrlConstants;
|
||||||
import org.keycloak.adapters.HttpClientBuilder;
|
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.util.HostUtils;
|
import org.keycloak.util.HostUtils;
|
||||||
|
@ -70,8 +70,7 @@ public class AdminClient {
|
||||||
|
|
||||||
public static AccessTokenResponse getToken(HttpServletRequest request) throws IOException {
|
public static AccessTokenResponse getToken(HttpServletRequest request) throws IOException {
|
||||||
|
|
||||||
HttpClient client = new HttpClientBuilder()
|
HttpClient client = new DefaultHttpClient();
|
||||||
.disableTrustManager().build();
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -104,8 +103,7 @@ public class AdminClient {
|
||||||
|
|
||||||
public static void logout(HttpServletRequest request, AccessTokenResponse res) throws IOException {
|
public static void logout(HttpServletRequest request, AccessTokenResponse res) throws IOException {
|
||||||
|
|
||||||
HttpClient client = new HttpClientBuilder()
|
HttpClient client = new DefaultHttpClient();
|
||||||
.disableTrustManager().build();
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -135,8 +133,7 @@ public class AdminClient {
|
||||||
|
|
||||||
public static List<RoleRepresentation> getRealmRoles(HttpServletRequest request, AccessTokenResponse res) throws Failure {
|
public static List<RoleRepresentation> getRealmRoles(HttpServletRequest request, AccessTokenResponse res) throws Failure {
|
||||||
|
|
||||||
HttpClient client = new HttpClientBuilder()
|
HttpClient client = new DefaultHttpClient();
|
||||||
.disableTrustManager().build();
|
|
||||||
try {
|
try {
|
||||||
HttpGet get = new HttpGet(getBaseUrl(request) + "/auth/admin/realms/demo/roles");
|
HttpGet get = new HttpGet(getBaseUrl(request) + "/auth/admin/realms/demo/roles");
|
||||||
get.addHeader("Authorization", "Bearer " + res.getToken());
|
get.addHeader("Authorization", "Bearer " + res.getToken());
|
||||||
|
|
|
@ -4,9 +4,9 @@ import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
import org.keycloak.adapters.HttpClientBuilder;
|
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
@ -40,8 +40,7 @@ public class AdminClient {
|
||||||
public static List<RoleRepresentation> getRealmRoles(HttpServletRequest req) throws Failure {
|
public static List<RoleRepresentation> getRealmRoles(HttpServletRequest req) throws Failure {
|
||||||
KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
|
KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
|
||||||
|
|
||||||
HttpClient client = new HttpClientBuilder()
|
HttpClient client = new DefaultHttpClient();
|
||||||
.disableTrustManager().build();
|
|
||||||
try {
|
try {
|
||||||
HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/auth/admin/realms/demo/roles");
|
HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/auth/admin/realms/demo/roles");
|
||||||
get.addHeader("Authorization", "Bearer " + session.getTokenString());
|
get.addHeader("Authorization", "Bearer " + session.getTokenString());
|
||||||
|
|
|
@ -4,13 +4,11 @@ import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
import org.keycloak.adapters.HttpClientBuilder;
|
|
||||||
import org.keycloak.constants.ServiceUrlConstants;
|
|
||||||
import org.keycloak.representations.IDToken;
|
import org.keycloak.representations.IDToken;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
import org.keycloak.util.KeycloakUriBuilder;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
@ -49,8 +47,7 @@ public class CustomerDatabaseClient {
|
||||||
public static List<String> getCustomers(HttpServletRequest req) throws Failure {
|
public static List<String> getCustomers(HttpServletRequest req) throws Failure {
|
||||||
KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
|
KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
|
||||||
|
|
||||||
HttpClient client = new HttpClientBuilder()
|
HttpClient client = new DefaultHttpClient();
|
||||||
.disableTrustManager().build();
|
|
||||||
try {
|
try {
|
||||||
HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/database/customers");
|
HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/database/customers");
|
||||||
get.addHeader("Authorization", "Bearer " + session.getTokenString());
|
get.addHeader("Authorization", "Bearer " + session.getTokenString());
|
||||||
|
|
|
@ -4,9 +4,9 @@ import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.adapters.AdapterUtils;
|
import org.keycloak.adapters.AdapterUtils;
|
||||||
import org.keycloak.adapters.HttpClientBuilder;
|
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -37,8 +37,8 @@ public class ProductDatabaseClient
|
||||||
|
|
||||||
public static List<String> getProducts(HttpServletRequest req) throws Failure {
|
public static List<String> getProducts(HttpServletRequest req) throws Failure {
|
||||||
KeycloakSecurityContext session = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
|
KeycloakSecurityContext session = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
|
||||||
HttpClient client = new HttpClientBuilder()
|
|
||||||
.disableTrustManager().build();
|
HttpClient client = new DefaultHttpClient();
|
||||||
try {
|
try {
|
||||||
HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/database/products");
|
HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/database/products");
|
||||||
get.addHeader("Authorization", "Bearer " + session.getTokenString());
|
get.addHeader("Authorization", "Bearer " + session.getTokenString());
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserFederationEventAwareProviderFactory;
|
import org.keycloak.models.UserFederationEventAwareProviderFactory;
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
import org.keycloak.models.UserFederationProvider;
|
import org.keycloak.models.UserFederationProvider;
|
||||||
import org.keycloak.models.UserFederationProviderFactory;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
import org.keycloak.models.UserFederationSyncResult;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
@ -89,7 +88,7 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
|
||||||
String usernameLdapAttribute = ldapConfig.getUsernameLdapAttribute();
|
String usernameLdapAttribute = ldapConfig.getUsernameLdapAttribute();
|
||||||
|
|
||||||
UserFederationMapperModel mapperModel;
|
UserFederationMapperModel mapperModel;
|
||||||
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("usernameMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
|
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("username", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
|
||||||
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.USERNAME,
|
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.USERNAME,
|
||||||
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, usernameLdapAttribute,
|
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, usernameLdapAttribute,
|
||||||
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
||||||
|
@ -97,25 +96,25 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
|
||||||
|
|
||||||
// For AD deployments with sAMAccountName is probably more common to map "cn" to full name of user
|
// For AD deployments with sAMAccountName is probably more common to map "cn" to full name of user
|
||||||
if (activeDirectory && usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
|
if (activeDirectory && usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
|
||||||
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("fullNameMapper", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.ID,
|
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
|
||||||
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
|
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
|
||||||
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
||||||
realm.addUserFederationMapper(mapperModel);
|
realm.addUserFederationMapper(mapperModel);
|
||||||
} else {
|
} else {
|
||||||
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("firstNameMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
|
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
|
||||||
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
|
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
|
||||||
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.CN,
|
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.CN,
|
||||||
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
||||||
realm.addUserFederationMapper(mapperModel);
|
realm.addUserFederationMapper(mapperModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("lastNameMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
|
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("last name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
|
||||||
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.LAST_NAME,
|
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.LAST_NAME,
|
||||||
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.SN,
|
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.SN,
|
||||||
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
||||||
realm.addUserFederationMapper(mapperModel);
|
realm.addUserFederationMapper(mapperModel);
|
||||||
|
|
||||||
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("emailMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
|
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("email", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
|
||||||
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.EMAIL,
|
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.EMAIL,
|
||||||
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.EMAIL,
|
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.EMAIL,
|
||||||
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
|
||||||
|
@ -125,14 +124,14 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
|
||||||
String modifyTimestampLdapAttrName = activeDirectory ? "whenChanged" : LDAPConstants.MODIFY_TIMESTAMP;
|
String modifyTimestampLdapAttrName = activeDirectory ? "whenChanged" : LDAPConstants.MODIFY_TIMESTAMP;
|
||||||
|
|
||||||
// map createTimeStamp as read-only
|
// map createTimeStamp as read-only
|
||||||
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("creationDateMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
|
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("creation date", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
|
||||||
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, LDAPConstants.CREATE_TIMESTAMP,
|
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, LDAPConstants.CREATE_TIMESTAMP,
|
||||||
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, createTimestampLdapAttrName,
|
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, createTimestampLdapAttrName,
|
||||||
UserAttributeLDAPFederationMapper.READ_ONLY, "true");
|
UserAttributeLDAPFederationMapper.READ_ONLY, "true");
|
||||||
realm.addUserFederationMapper(mapperModel);
|
realm.addUserFederationMapper(mapperModel);
|
||||||
|
|
||||||
// map modifyTimeStamp as read-only
|
// map modifyTimeStamp as read-only
|
||||||
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("modifyDateMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
|
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("modify date", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
|
||||||
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, LDAPConstants.MODIFY_TIMESTAMP,
|
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, LDAPConstants.MODIFY_TIMESTAMP,
|
||||||
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, modifyTimestampLdapAttrName,
|
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, modifyTimestampLdapAttrName,
|
||||||
UserAttributeLDAPFederationMapper.READ_ONLY, "true");
|
UserAttributeLDAPFederationMapper.READ_ONLY, "true");
|
||||||
|
|
|
@ -1,25 +1,65 @@
|
||||||
package org.keycloak.federation.ldap.mappers;
|
package org.keycloak.federation.ldap.mappers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
||||||
|
import org.keycloak.mappers.MapperConfigValidationException;
|
||||||
import org.keycloak.mappers.UserFederationMapperFactory;
|
import org.keycloak.mappers.UserFederationMapperFactory;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractLDAPFederationMapperFactory implements UserFederationMapperFactory {
|
public abstract class AbstractLDAPFederationMapperFactory implements UserFederationMapperFactory {
|
||||||
|
|
||||||
|
// Used to map attributes from LDAP to UserModel attributes
|
||||||
|
public static final String ATTRIBUTE_MAPPER_CATEGORY = "Attribute Mapper";
|
||||||
|
|
||||||
|
// Used to map roles from LDAP to UserModel users
|
||||||
|
public static final String ROLE_MAPPER_CATEGORY = "Role Mapper";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFederationProviderType() {
|
||||||
|
return LDAPFederationProviderFactory.PROVIDER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postInit(KeycloakSessionFactory factory) {
|
public void postInit(KeycloakSessionFactory factory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
throw new IllegalStateException("Method not supported for this implementation");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ProviderConfigProperty createConfigProperty(String name, String label, String helpText, String type, Object defaultValue) {
|
||||||
|
ProviderConfigProperty configProperty = new ProviderConfigProperty();
|
||||||
|
configProperty.setName(name);
|
||||||
|
configProperty.setLabel(label);
|
||||||
|
configProperty.setHelpText(helpText);
|
||||||
|
configProperty.setType(type);
|
||||||
|
configProperty.setDefaultValue(defaultValue);
|
||||||
|
return configProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkMandatoryConfigAttribute(String name, String displayName, UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
|
String attrConfigValue = mapperModel.getConfig().get(name);
|
||||||
|
if (attrConfigValue == null || attrConfigValue.trim().isEmpty()) {
|
||||||
|
throw new MapperConfigValidationException("Missing configuration for '" + displayName + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
package org.keycloak.federation.ldap.mappers;
|
package org.keycloak.federation.ldap.mappers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.keycloak.mappers.MapperConfigValidationException;
|
||||||
import org.keycloak.mappers.UserFederationMapper;
|
import org.keycloak.mappers.UserFederationMapper;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,21 +16,48 @@ import org.keycloak.provider.ProviderConfigProperty;
|
||||||
*/
|
*/
|
||||||
public class FullNameLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
|
public class FullNameLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
|
||||||
|
|
||||||
public static final String ID = "full-name-ldap-mapper";
|
public static final String PROVIDER_ID = "full-name-ldap-mapper";
|
||||||
|
|
||||||
@Override
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
public String getHelpText() {
|
|
||||||
return "Some help text - full name mapper - TODO";
|
static {
|
||||||
|
ProviderConfigProperty userModelAttribute = createConfigProperty(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, "LDAP Full Name Attribute",
|
||||||
|
"Name of LDAP attribute, which contains fullName of user. In most cases it will be 'cn' ", ProviderConfigProperty.STRING_TYPE, LDAPConstants.CN);
|
||||||
|
configProperties.add(userModelAttribute);
|
||||||
|
|
||||||
|
ProviderConfigProperty readOnly = createConfigProperty(UserAttributeLDAPFederationMapper.READ_ONLY, "Read Only",
|
||||||
|
"For Read-only is data imported from LDAP to Keycloak DB, but it's not saved back to LDAP when user is updated in Keycloak.", ProviderConfigProperty.BOOLEAN_TYPE, "false");
|
||||||
|
configProperties.add(readOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public String getHelpText() {
|
||||||
return null;
|
return "Used to map full-name of user from single attribute in LDAP (usually 'cn' attribute) to firstName and lastName attributes of UserModel in Keycloak DB";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayCategory() {
|
||||||
|
return ATTRIBUTE_MAPPER_CATEGORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayType() {
|
||||||
|
return "Full Name";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties(RealmModel realm) {
|
||||||
|
return configProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return ID;
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
|
checkMandatoryConfigAttribute(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, "LDAP Full Name Attribute", mapperModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -178,7 +178,6 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
|
||||||
}
|
}
|
||||||
String[] objClasses = objectClasses.split(",");
|
String[] objClasses = objectClasses.split(",");
|
||||||
|
|
||||||
// TODO: util method for trim and convert array to collection?
|
|
||||||
Set<String> trimmed = new HashSet<String>();
|
Set<String> trimmed = new HashSet<String>();
|
||||||
for (String objectClass : objClasses) {
|
for (String objectClass : objClasses) {
|
||||||
objectClass = objectClass.trim();
|
objectClass = objectClass.trim();
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
package org.keycloak.federation.ldap.mappers;
|
package org.keycloak.federation.ldap.mappers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.keycloak.mappers.MapperConfigValidationException;
|
||||||
import org.keycloak.mappers.UserFederationMapper;
|
import org.keycloak.mappers.UserFederationMapper;
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,21 +20,95 @@ import org.keycloak.provider.ProviderConfigProperty;
|
||||||
*/
|
*/
|
||||||
public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
|
public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
|
||||||
|
|
||||||
public static final String ID = "role-ldap-mapper";
|
public static final String PROVIDER_ID = "role-ldap-mapper";
|
||||||
|
|
||||||
@Override
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
public String getHelpText() {
|
|
||||||
return "Some help text - role mapper - TODO";
|
static {
|
||||||
|
ProviderConfigProperty rolesDn = createConfigProperty(RoleLDAPFederationMapper.ROLES_DN, "LDAP Roles DN",
|
||||||
|
"LDAP DN where are roles of this tree saved. For example 'ou=finance,dc=example,dc=org' ", ProviderConfigProperty.STRING_TYPE, null);
|
||||||
|
configProperties.add(rolesDn);
|
||||||
|
|
||||||
|
ProviderConfigProperty roleNameLDAPAttribute = createConfigProperty(RoleLDAPFederationMapper.ROLE_NAME_LDAP_ATTRIBUTE, "Role Name LDAP Attribute",
|
||||||
|
"Name of LDAP attribute, which is used in role objects for name and RDN of role. Usually it will be 'cn' . In this case typical group/role object may have DN like 'cn=role1,ou=finance,dc=example,dc=org' ",
|
||||||
|
ProviderConfigProperty.STRING_TYPE, LDAPConstants.CN);
|
||||||
|
configProperties.add(roleNameLDAPAttribute);
|
||||||
|
|
||||||
|
ProviderConfigProperty membershipLDAPAttribute = createConfigProperty(RoleLDAPFederationMapper.MEMBERSHIP_LDAP_ATTRIBUTE, "Membership LDAP Attribute",
|
||||||
|
"Name of LDAP attribute on role, which is used for membership mappings. Usually it will be 'member' ",
|
||||||
|
ProviderConfigProperty.STRING_TYPE, LDAPConstants.MEMBER);
|
||||||
|
configProperties.add(membershipLDAPAttribute);
|
||||||
|
|
||||||
|
ProviderConfigProperty roleObjectClasses = createConfigProperty(RoleLDAPFederationMapper.ROLE_OBJECT_CLASSES, "Role Object Classes",
|
||||||
|
"Object classes of the role object divided by comma (if more values needed). In typical LDAP deployment it could be 'groupOfNames' or 'groupOfEntries' ",
|
||||||
|
ProviderConfigProperty.STRING_TYPE, LDAPConstants.GROUP_OF_NAMES);
|
||||||
|
configProperties.add(roleObjectClasses);
|
||||||
|
|
||||||
|
List<String> modes = new LinkedList<String>();
|
||||||
|
for (RoleLDAPFederationMapper.Mode mode : RoleLDAPFederationMapper.Mode.values()) {
|
||||||
|
modes.add(mode.toString());
|
||||||
|
}
|
||||||
|
ProviderConfigProperty mode = createConfigProperty(RoleLDAPFederationMapper.MODE, "Mode",
|
||||||
|
"LDAP_ONLY means that all role mappings are retrieved from LDAP and saved into LDAP. READ_ONLY is Read-only LDAP mode where role mappings are " +
|
||||||
|
"retrieved from both LDAP and DB and merged together. New role grants are not saved to LDAP but to DB. IMPORT is Read-only LDAP mode where role mappings are retrieved from LDAP just at the time when user is imported from LDAP and then " +
|
||||||
|
"they are saved to local keycloak DB.",
|
||||||
|
ProviderConfigProperty.LIST_TYPE, modes);
|
||||||
|
configProperties.add(mode);
|
||||||
|
|
||||||
|
ProviderConfigProperty useRealmRolesMappings = createConfigProperty(RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING, "Use Realm Roles Mapping",
|
||||||
|
"If true, then LDAP role mappings will be mapped to realm role mappings in Keycloak. Otherwise it will be mapped to client role mappings", ProviderConfigProperty.BOOLEAN_TYPE, "true");
|
||||||
|
configProperties.add(useRealmRolesMappings);
|
||||||
|
|
||||||
|
// NOTE: ClientID will be computed dynamically from available clients
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public String getHelpText() {
|
||||||
return null;
|
return "Used to map role mappings of roles from some LDAP DN to Keycloak role mappings of either realm roles or client roles of particular client";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayCategory() {
|
||||||
|
return ROLE_MAPPER_CATEGORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayType() {
|
||||||
|
return "Role mappings";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties(RealmModel realm) {
|
||||||
|
List<ProviderConfigProperty> props = new ArrayList<ProviderConfigProperty>(configProperties);
|
||||||
|
|
||||||
|
Map<String, ClientModel> clients = realm.getClientNameMap();
|
||||||
|
List<String> clientIds = new ArrayList<String>(clients.keySet());
|
||||||
|
|
||||||
|
ProviderConfigProperty clientIdProperty = createConfigProperty(RoleLDAPFederationMapper.CLIENT_ID, "Client ID",
|
||||||
|
"Client ID of client to which LDAP role mappings will be mapped. Applicable just if 'Use Realm Roles Mapping' is false",
|
||||||
|
ProviderConfigProperty.LIST_TYPE, clientIds);
|
||||||
|
props.add(clientIdProperty);
|
||||||
|
|
||||||
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return ID ;
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
|
checkMandatoryConfigAttribute(RoleLDAPFederationMapper.ROLES_DN, "LDAP Roles DN", mapperModel);
|
||||||
|
|
||||||
|
String realmMappings = mapperModel.getConfig().get(RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING);
|
||||||
|
boolean useRealmMappings = Boolean.parseBoolean(realmMappings);
|
||||||
|
if (!useRealmMappings) {
|
||||||
|
String clientId = mapperModel.getConfig().get(RoleLDAPFederationMapper.CLIENT_ID);
|
||||||
|
if (clientId == null || clientId.trim().isEmpty()) {
|
||||||
|
throw new MapperConfigValidationException("Client ID needs to be provided in config when Realm Roles Mapping is not used");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package org.keycloak.federation.ldap.mappers;
|
package org.keycloak.federation.ldap.mappers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.keycloak.mappers.MapperConfigValidationException;
|
||||||
import org.keycloak.mappers.UserFederationMapper;
|
import org.keycloak.mappers.UserFederationMapper;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,21 +15,52 @@ import org.keycloak.provider.ProviderConfigProperty;
|
||||||
*/
|
*/
|
||||||
public class UserAttributeLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
|
public class UserAttributeLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
|
||||||
|
|
||||||
public static final String ID = "user-attribute-ldap-mapper";
|
public static final String PROVIDER_ID = "user-attribute-ldap-mapper";
|
||||||
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
@Override
|
static {
|
||||||
public String getHelpText() {
|
ProviderConfigProperty userModelAttribute = createConfigProperty(UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "User Model Attribute",
|
||||||
return "Some help text TODO";
|
"Name of mapped UserModel property or UserModel attribute in Keycloak DB. For example 'firstName', 'lastName, 'email', 'street' etc.", ProviderConfigProperty.STRING_TYPE, null);
|
||||||
|
configProperties.add(userModelAttribute);
|
||||||
|
|
||||||
|
ProviderConfigProperty ldapAttribute = createConfigProperty(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "LDAP Attribute",
|
||||||
|
"Name of mapped attribute on LDAP object. For example 'cn', 'sn, 'mail', 'street' etc.", ProviderConfigProperty.STRING_TYPE, null);
|
||||||
|
configProperties.add(ldapAttribute);
|
||||||
|
|
||||||
|
ProviderConfigProperty readOnly = createConfigProperty(UserAttributeLDAPFederationMapper.READ_ONLY, "Read Only",
|
||||||
|
"Read-only attribute is imported from LDAP to Keycloak DB, but it's not saved back to LDAP when user is updated in Keycloak.", ProviderConfigProperty.BOOLEAN_TYPE, "false");
|
||||||
|
configProperties.add(readOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public String getHelpText() {
|
||||||
return null;
|
return "Used to map single attribute from LDAP user to attribute of UserModel in Keycloak DB";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayCategory() {
|
||||||
|
return ATTRIBUTE_MAPPER_CATEGORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayType() {
|
||||||
|
return "User Attribute";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties(RealmModel realm) {
|
||||||
|
return configProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return ID;
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
|
checkMandatoryConfigAttribute(UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "User Model Attribute", mapperModel);
|
||||||
|
checkMandatoryConfigAttribute(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "LDAP Attribute", mapperModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -952,6 +952,58 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'GenericUserFederationCtrl'
|
controller : 'GenericUserFederationCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/realms/:realm/user-federation/providers/:provider/:instance/mappers', {
|
||||||
|
templateUrl : function(params){ return resourceUrl + '/partials/federated-mappers.html'; },
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
provider : function(UserFederationInstanceLoader) {
|
||||||
|
return UserFederationInstanceLoader();
|
||||||
|
},
|
||||||
|
mapperTypes : function(UserFederationMapperTypesLoader) {
|
||||||
|
return UserFederationMapperTypesLoader();
|
||||||
|
},
|
||||||
|
mappers : function(UserFederationMappersLoader) {
|
||||||
|
return UserFederationMappersLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'UserFederationMapperListCtrl'
|
||||||
|
})
|
||||||
|
.when('/realms/:realm/user-federation/providers/:provider/:instance/mappers/:mapperId', {
|
||||||
|
templateUrl : function(params){ return resourceUrl + '/partials/federated-mapper-detail.html'; },
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
provider : function(UserFederationInstanceLoader) {
|
||||||
|
return UserFederationInstanceLoader();
|
||||||
|
},
|
||||||
|
mapperTypes : function(UserFederationMapperTypesLoader) {
|
||||||
|
return UserFederationMapperTypesLoader();
|
||||||
|
},
|
||||||
|
mapper : function(UserFederationMapperLoader) {
|
||||||
|
return UserFederationMapperLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'UserFederationMapperCtrl'
|
||||||
|
})
|
||||||
|
.when('/create/user-federation-mappers/:realm/:provider/:instance', {
|
||||||
|
templateUrl : function(params){ return resourceUrl + '/partials/federated-mapper-detail.html'; },
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
provider : function(UserFederationInstanceLoader) {
|
||||||
|
return UserFederationInstanceLoader();
|
||||||
|
},
|
||||||
|
mapperTypes : function(UserFederationMapperTypesLoader) {
|
||||||
|
return UserFederationMapperTypesLoader();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
controller : 'UserFederationMapperCreateCtrl'
|
||||||
|
})
|
||||||
|
|
||||||
.when('/realms/:realm/defense/headers', {
|
.when('/realms/:realm/defense/headers', {
|
||||||
templateUrl : resourceUrl + '/partials/defense-headers.html',
|
templateUrl : resourceUrl + '/partials/defense-headers.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
|
|
|
@ -511,8 +511,8 @@ module.controller('GenericUserFederationCtrl', function($scope, $location, Notif
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerSync(action) {
|
function triggerSync(action) {
|
||||||
UserFederationSync.get({ action: action, realm: $scope.realm.realm, provider: $scope.instance.id }, function() {
|
UserFederationSync.save({ action: action, realm: $scope.realm.realm, provider: $scope.instance.id }, {}, function(syncResult) {
|
||||||
Notifications.success("Sync of users finished successfully");
|
Notifications.success("Sync of users finished successfully. " + syncResult.status);
|
||||||
}, function() {
|
}, function() {
|
||||||
Notifications.error("Error during sync of users");
|
Notifications.error("Error during sync of users");
|
||||||
});
|
});
|
||||||
|
@ -734,3 +734,128 @@ module.controller('LDAPCtrl', function($scope, $location, $route, Notifications,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.controller('UserFederationMapperListCtrl', function($scope, $location, Notifications, $route, Dialog, realm, provider, mapperTypes, mappers) {
|
||||||
|
console.log('UserFederationMapperListCtrl');
|
||||||
|
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.provider = provider;
|
||||||
|
|
||||||
|
$scope.mapperTypes = mapperTypes;
|
||||||
|
$scope.mappers = mappers;
|
||||||
|
|
||||||
|
$scope.hasAnyMapperTypes = false;
|
||||||
|
for (var property in mapperTypes) {
|
||||||
|
if (!(property.startsWith('$'))) {
|
||||||
|
$scope.hasAnyMapperTypes = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('UserFederationMapperCtrl', function($scope, realm, provider, mapperTypes, mapper, UserFederationMapper, Notifications, Dialog, $location) {
|
||||||
|
console.log('UserFederationMapperCtrl');
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.provider = provider;
|
||||||
|
$scope.create = false;
|
||||||
|
$scope.mapper = angular.copy(mapper);
|
||||||
|
$scope.changed = false;
|
||||||
|
$scope.mapperType = mapperTypes[mapper.federationMapperType];
|
||||||
|
|
||||||
|
$scope.$watch('mapper', function() {
|
||||||
|
if (!angular.equals($scope.mapper, mapper)) {
|
||||||
|
$scope.changed = true;
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
UserFederationMapper.update({
|
||||||
|
realm : realm.realm,
|
||||||
|
provider: provider.id,
|
||||||
|
mapperId : mapper.id
|
||||||
|
}, $scope.mapper, function() {
|
||||||
|
$scope.changed = false;
|
||||||
|
mapper = angular.copy($scope.mapper);
|
||||||
|
$location.url("/realms/" + realm.realm + '/user-federation/providers/' + provider.providerName + '/' + provider.id + '/mappers/' + mapper.id);
|
||||||
|
Notifications.success("Your changes have been saved.");
|
||||||
|
}, function(error) {
|
||||||
|
if (error.status == 400) {
|
||||||
|
Notifications.error('Error in configuration of mapper: ' + error.data.error_description);
|
||||||
|
} else {
|
||||||
|
Notification.error('Unexpected error when creating mapper');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.reset = function() {
|
||||||
|
$scope.mapper = angular.copy(mapper);
|
||||||
|
$scope.changed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
window.history.back();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.remove = function() {
|
||||||
|
Dialog.confirmDelete($scope.mapper.name, 'mapper', function() {
|
||||||
|
UserFederationMapper.remove({ realm: realm.realm, provider: provider.id, mapperId : $scope.mapper.id }, function() {
|
||||||
|
Notifications.success("The mapper has been deleted.");
|
||||||
|
$location.url("/realms/" + realm.realm + '/user-federation/providers/' + provider.providerName + '/' + provider.id + '/mappers');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('UserFederationMapperCreateCtrl', function($scope, realm, provider, mapperTypes, UserFederationMapper, Notifications, Dialog, $location) {
|
||||||
|
console.log('UserFederationMapperCreateCtrl');
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.provider = provider;
|
||||||
|
$scope.create = true;
|
||||||
|
$scope.mapper = { federationProviderDisplayName: provider.displayName, config: {}};
|
||||||
|
$scope.mapperTypes = mapperTypes;
|
||||||
|
$scope.mapperType = null;
|
||||||
|
|
||||||
|
$scope.$watch('mapperType', function() {
|
||||||
|
if ($scope.mapperType != null) {
|
||||||
|
$scope.mapper.config = {};
|
||||||
|
for ( var i = 0; i < $scope.mapperType.properties.length; i++) {
|
||||||
|
var property = $scope.mapperType.properties[i];
|
||||||
|
if (property.type === 'String' || property.type === 'boolean') {
|
||||||
|
$scope.mapper.config[ property.name ] = property.defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
if ($scope.mapperType == null) {
|
||||||
|
Notifications.error("You need to select mapper type!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.mapper.federationMapperType = $scope.mapperType.id;
|
||||||
|
UserFederationMapper.save({
|
||||||
|
realm : realm.realm, provider: provider.id
|
||||||
|
}, $scope.mapper, function(data, headers) {
|
||||||
|
var l = headers().location;
|
||||||
|
var id = l.substring(l.lastIndexOf("/") + 1);
|
||||||
|
$location.url('/realms/' + realm.realm +'/user-federation/providers/' + provider.providerName + '/' + provider.id + '/mappers/' + id);
|
||||||
|
Notifications.success("Mapper has been created.");
|
||||||
|
}, function(error) {
|
||||||
|
if (error.status == 400) {
|
||||||
|
Notifications.error('Error in configuration of mapper: ' + error.data.error_description);
|
||||||
|
} else {
|
||||||
|
Notification.error('Unexpected error when creating mapper');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
window.history.back();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,34 @@ module.factory('UserFederationFactoryLoader', function(Loader, UserFederationPro
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.factory('UserFederationMapperTypesLoader', function(Loader, UserFederationMapperTypes, $route, $q) {
|
||||||
|
return Loader.get(UserFederationMapperTypes, function () {
|
||||||
|
return {
|
||||||
|
realm: $route.current.params.realm,
|
||||||
|
provider: $route.current.params.instance
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('UserFederationMappersLoader', function(Loader, UserFederationMappers, $route, $q) {
|
||||||
|
return Loader.query(UserFederationMappers, function () {
|
||||||
|
return {
|
||||||
|
realm: $route.current.params.realm,
|
||||||
|
provider: $route.current.params.instance
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('UserFederationMapperLoader', function(Loader, UserFederationMapper, $route, $q) {
|
||||||
|
return Loader.get(UserFederationMapper, function () {
|
||||||
|
return {
|
||||||
|
realm: $route.current.params.realm,
|
||||||
|
provider: $route.current.params.instance,
|
||||||
|
mapperId: $route.current.params.mapperId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.factory('UserSessionStatsLoader', function(Loader, UserSessionStats, $route, $q) {
|
module.factory('UserSessionStatsLoader', function(Loader, UserSessionStats, $route, $q) {
|
||||||
return Loader.get(UserSessionStats, function() {
|
return Loader.get(UserSessionStats, function() {
|
||||||
|
|
|
@ -238,7 +238,33 @@ module.factory('UserFederationProviders', function($resource) {
|
||||||
});
|
});
|
||||||
|
|
||||||
module.factory('UserFederationSync', function($resource) {
|
module.factory('UserFederationSync', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/user-federation/sync/:provider');
|
return $resource(authUrl + '/admin/realms/:realm/user-federation/instances/:provider/sync');
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('UserFederationMapperTypes', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/user-federation/instances/:provider/mapper-types', {
|
||||||
|
realm : '@realm',
|
||||||
|
provider : '@provider'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('UserFederationMappers', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/user-federation/instances/:provider/mappers', {
|
||||||
|
realm : '@realm',
|
||||||
|
provider : '@provider'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('UserFederationMapper', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/user-federation/instances/:provider/mappers/:mapperId', {
|
||||||
|
realm : '@realm',
|
||||||
|
provider : '@provider',
|
||||||
|
mapperId: '@mapperId'
|
||||||
|
}, {
|
||||||
|
update: {
|
||||||
|
method : 'PUT'
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,13 @@
|
||||||
<li data-ng-show="create">Add User Federation Provider</li>
|
<li data-ng-show="create">Add User Federation Provider</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h1 data-ng-hide="create"><strong>User Federation Provider</strong> {{instance.displayName|capitalize}}</h1>
|
<h1 data-ng-hide="create"><strong>{{instance.providerName|capitalize}} User Federation Provider</strong> {{instance.displayName|capitalize}}</h1>
|
||||||
<h1 data-ng-show="create"><strong>Add User Federation Provider</strong></h1>
|
<h1 data-ng-show="create"><strong>Add {{instance.providerName|capitalize}} User Federation Provider</strong></h1>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" data-ng-hide="create">
|
||||||
|
<li class="active"><a href="#/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}">Settings</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}/mappers">Mappers</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
<h1 data-ng-hide="create"><strong>Kerberos User Federation Provider</strong> {{instance.displayName|capitalize}}</h1>
|
<h1 data-ng-hide="create"><strong>Kerberos User Federation Provider</strong> {{instance.displayName|capitalize}}</h1>
|
||||||
<h1 data-ng-show="create"><strong>Add Kerberos User Federation Provider</strong></h1>
|
<h1 data-ng-show="create"><strong>Add Kerberos User Federation Provider</strong></h1>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" data-ng-hide="create">
|
||||||
|
<li class="active"><a href="#/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}">Settings</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}/mappers">Mappers</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend><span class="text">Required Settings</span></legend>
|
<legend><span class="text">Required Settings</span></legend>
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
<h1 data-ng-hide="create"><strong>LDAP User Federation Provider</strong> {{instance.displayName|capitalize}}</h1>
|
<h1 data-ng-hide="create"><strong>LDAP User Federation Provider</strong> {{instance.displayName|capitalize}}</h1>
|
||||||
<h1 data-ng-show="create"><strong>Add LDAP User Federation Provider</strong></h1>
|
<h1 data-ng-show="create"><strong>Add LDAP User Federation Provider</strong></h1>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" data-ng-hide="create">
|
||||||
|
<li class="active"><a href="#/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}">Settings</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}/mappers">Mappers</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation">User Federation</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation/providers/{{provider.providerName}}/{{provider.id}}">{{provider.displayName|capitalize}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation/providers/{{provider.providerName}}/{{provider.id}}/mappers">User Federation Mappers</a></li>
|
||||||
|
<li class="active" data-ng-show="create">Create User Federation Mapper</li>
|
||||||
|
<li class="active" data-ng-hide="create">{{mapper.name}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h1 data-ng-hide="create"><strong>User Federation Mapper</strong> {{mapper.name}}</h1>
|
||||||
|
<h1 data-ng-show="create"><strong>Add User Federation Mapper</strong></h1>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group clearfix" data-ng-show="!create">
|
||||||
|
<label class="col-md-2 control-label" for="mapperId">ID </label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input class="form-control" id="mapperId" type="text" ng-model="mapper.id" readonly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-md-2 control-label" for="name">Name <span class="required">*</span></label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input class="form-control" id="name" type="text" ng-model="mapper.name" data-ng-readonly="!create" required>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>Name of the mapper.</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-show="create">
|
||||||
|
<label class="col-md-2 control-label" for="mapperTypeCreate">Mapper Type</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div>
|
||||||
|
<select class="form-control" id="mapperTypeCreate"
|
||||||
|
ng-model="mapperType"
|
||||||
|
ng-options="mapperType.name for (mapperKey, mapperType) in mapperTypes">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{mapperType.helpText}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix" data-ng-hide="create">
|
||||||
|
<label class="col-md-2 control-label" for="mapperType">Mapper Type</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input class="form-control" id="mapperType" type="text" ng-model="mapperType.name" data-ng-readonly="true">
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{mapperType.helpText}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div data-ng-repeat="option in mapperType.properties" class="form-group">
|
||||||
|
<label class="col-md-2 control-label">{{option.label}}</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4" data-ng-hide="option.type == 'boolean' || option.type == 'List'">
|
||||||
|
<input class="form-control" type="text" data-ng-model="mapper.config[ option.name ]">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4" data-ng-show="option.type == 'boolean'">
|
||||||
|
<input ng-model="mapper.config[ option.name ]" value="'true'" name="option.name" id="option.name" onoffswitchmodel />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4" data-ng-show="option.type == 'List'">
|
||||||
|
<select ng-model="mapper.config[ option.name ]" ng-options="data for data in option.defaultValue">
|
||||||
|
<option value="" selected> Select one... </option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{option.helpText}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
<div class="pull-right form-actions" data-ng-show="create && access.manageRealm">
|
||||||
|
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||||
|
<button kc-save>Save</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pull-right form-actions" data-ng-show="!create && access.manageRealm">
|
||||||
|
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||||
|
<button kc-save data-ng-show="changed">Save</button>
|
||||||
|
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation">User Federation</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation/providers/{{provider.providerName}}/{{provider.id}}">{{provider.displayName|capitalize}}</a></li>
|
||||||
|
<li>User Federation Mappers</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h1><strong>{{provider.providerName === 'ldap' ? 'LDAP' : (provider.providerName|capitalize)}} User Federation Provider</strong> {{provider.displayName|capitalize}}</h1>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" data-ng-hide="create">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/user-federation/providers/{{provider.providerName}}/{{provider.id}}">Settings</a></li>
|
||||||
|
<li class="active"><a href="#/realms/{{realm.realm}}/user-federation/providers/{{provider.providerName}}/{{provider.id}}/mappers">Mappers</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="kc-table-actions" colspan="4">
|
||||||
|
<div class="form-inline">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" placeholder="Search..." data-ng-model="search.name" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
|
||||||
|
<div class="input-group-addon">
|
||||||
|
<i class="fa fa-search" type="submit"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right" data-ng-show="hasAnyMapperTypes">
|
||||||
|
<a class="btn btn-primary" href="#/create/user-federation-mappers/{{realm.realm}}/{{provider.providerName}}/{{provider.id}}">Create</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr data-ng-hide="mappers.length == 0">
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Category</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="mapper in mappers | filter:search">
|
||||||
|
<td><a href="#/realms/{{realm.realm}}/user-federation/providers/{{provider.providerName}}/{{provider.id}}/mappers/{{mapper.id}}">{{mapper.name}}</a></td>
|
||||||
|
<td>{{mapperTypes[mapper.federationMapperType].category}}</td>
|
||||||
|
<td>{{mapperTypes[mapper.federationMapperType].name}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr data-ng-show="mappers.length == 0">
|
||||||
|
<td>No mappers available</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -18,5 +18,6 @@
|
||||||
<module>wildfly-extensions</module>
|
<module>wildfly-extensions</module>
|
||||||
<module>wildfly-server-subsystem</module>
|
<module>wildfly-server-subsystem</module>
|
||||||
<module>wildfly-adapter-subsystem</module>
|
<module>wildfly-adapter-subsystem</module>
|
||||||
|
<module>wf8-subsystem</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
115
integration/wildfly/wf8-subsystem/pom.xml
Executable file
115
integration/wildfly/wf8-subsystem/pom.xml
Executable file
|
@ -0,0 +1,115 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2013 JBoss Inc
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<version>1.3.0.Final-SNAPSHOT</version>
|
||||||
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>keycloak-wf8-subsystem</artifactId>
|
||||||
|
<name>Keycloak Adapter Subsystem</name>
|
||||||
|
<description/>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<wildfly.version>8.2.0.Final</wildfly.version>
|
||||||
|
<wildfly.core.version>8.2.0.Final</wildfly.core.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<redirectTestOutputToFile>false</redirectTestOutputToFile>
|
||||||
|
<enableAssertions>true</enableAssertions>
|
||||||
|
<systemProperties>
|
||||||
|
<property>
|
||||||
|
<name>jboss.home</name>
|
||||||
|
<value>${jboss.home}</value>
|
||||||
|
</property>
|
||||||
|
</systemProperties>
|
||||||
|
<includes>
|
||||||
|
<include>**/*TestCase.java</include>
|
||||||
|
</includes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-controller</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-server</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-web-common</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging-annotations</artifactId>
|
||||||
|
<version>${jboss-logging-tools.version}</version>
|
||||||
|
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
||||||
|
projects that depend on this project.-->
|
||||||
|
<scope>provided</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging-processor</artifactId>
|
||||||
|
<version>${jboss-logging-tools.version}</version>
|
||||||
|
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
||||||
|
projects that depend on this project.-->
|
||||||
|
<scope>provided</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-subsystem-test-framework</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-wildfly-adapter</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractAddStepHandler;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.as.controller.ServiceVerificationHandler;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a credential to a deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class CredentialAddHandler extends AbstractAddStepHandler {
|
||||||
|
|
||||||
|
public CredentialAddHandler(AttributeDefinition... attributes) {
|
||||||
|
super(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.addCredential(operation, context.resolveExpressions(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.PathElement;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
|
||||||
|
import org.jboss.as.controller.SimpleResourceDefinition;
|
||||||
|
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
|
||||||
|
import org.jboss.as.controller.operations.validation.StringLengthValidator;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
import org.jboss.dmr.ModelType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes and operations for a credential.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class CredentialDefinition extends SimpleResourceDefinition {
|
||||||
|
|
||||||
|
public static final String TAG_NAME = "credential";
|
||||||
|
|
||||||
|
protected static final AttributeDefinition VALUE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("value", ModelType.STRING, false)
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public CredentialDefinition() {
|
||||||
|
super(PathElement.pathElement(TAG_NAME),
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
|
||||||
|
new CredentialAddHandler(VALUE),
|
||||||
|
CredentialRemoveHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerOperations(resourceRegistration);
|
||||||
|
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerAttributes(resourceRegistration);
|
||||||
|
resourceRegistration.registerReadWriteAttribute(VALUE, null, new CredentialReadWriteAttributeHandler());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractWriteAttributeHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a credential value.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class CredentialReadWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode resolvedValue, ModelNode currentValue, AbstractWriteAttributeHandler.HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
|
||||||
|
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.updateCredential(operation, attributeName, resolvedValue);
|
||||||
|
|
||||||
|
hh.setHandback(ckService);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
|
||||||
|
ckService.updateCredential(operation, attributeName, valueToRestore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractRemoveStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a credential from a deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public final class CredentialRemoveHandler extends AbstractRemoveStepHandler {
|
||||||
|
|
||||||
|
public static CredentialRemoveHandler INSTANCE = new CredentialRemoveHandler();
|
||||||
|
|
||||||
|
private CredentialRemoveHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.removeCredential(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.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 org.keycloak.subsystem.wf8.logging.KeycloakLogger;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// This param name is defined again in Keycloak Undertow Integration class
|
||||||
|
// org.keycloak.adapters.undertow.KeycloakServletExtension. We have this value in
|
||||||
|
// two places to avoid dependency between Keycloak Subsystem and Keyclaok Undertow Integration.
|
||||||
|
public static final String AUTH_DATA_PARAM_NAME = "org.keycloak.json.adapterConfig";
|
||||||
|
|
||||||
|
// not sure if we need this yet, keeping here just in case
|
||||||
|
protected void addSecurityDomain(DeploymentUnit deploymentUnit, KeycloakAdapterConfigService service) {
|
||||||
|
String deploymentName = deploymentUnit.getName();
|
||||||
|
if (!service.isSecureDeployment(deploymentName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
|
||||||
|
if (warMetaData == null) return;
|
||||||
|
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
|
||||||
|
if (webMetaData == null) return;
|
||||||
|
|
||||||
|
LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
|
||||||
|
if (loginConfig == null || !loginConfig.getAuthMethod().equalsIgnoreCase("KEYCLOAK")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
webMetaData.setSecurityDomain("keycloak");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
|
||||||
|
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||||
|
|
||||||
|
String deploymentName = deploymentUnit.getName();
|
||||||
|
KeycloakAdapterConfigService service = KeycloakAdapterConfigService.getInstance();
|
||||||
|
if (service.isSecureDeployment(deploymentName)) {
|
||||||
|
addKeycloakAuthData(phaseContext, deploymentName, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FYI, Undertow Extension will find deployments that have auth-method set to KEYCLOAK
|
||||||
|
|
||||||
|
// todo notsure if we need this
|
||||||
|
// addSecurityDomain(deploymentUnit, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addKeycloakAuthData(DeploymentPhaseContext phaseContext, String deploymentName, KeycloakAdapterConfigService service) 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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
addJSONData(service.getJSON(deploymentName), warMetaData);
|
||||||
|
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");
|
||||||
|
loginConfig.setRealmName(service.getRealmName(deploymentName));
|
||||||
|
KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addJSONData(String json, WarMetaData warMetaData) {
|
||||||
|
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
|
||||||
|
if (webMetaData == null) {
|
||||||
|
webMetaData = new JBossWebMetaData();
|
||||||
|
warMetaData.setMergedJBossWebMetaData(webMetaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ParamValueMetaData> contextParams = webMetaData.getContextParams();
|
||||||
|
if (contextParams == null) {
|
||||||
|
contextParams = new ArrayList<ParamValueMetaData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamValueMetaData param = new ParamValueMetaData();
|
||||||
|
param.setParamName(AUTH_DATA_PARAM_NAME);
|
||||||
|
param.setParamValue(json);
|
||||||
|
contextParams.add(param);
|
||||||
|
|
||||||
|
webMetaData.setContextParams(contextParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undeploy(DeploymentUnit du) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.Property;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This service keeps track of the entire Keycloak management model so as to provide
|
||||||
|
* adapter configuration to each deployment at deploy time.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public final class KeycloakAdapterConfigService {
|
||||||
|
|
||||||
|
private static final String CREDENTIALS_JSON_NAME = "credentials";
|
||||||
|
|
||||||
|
private static final KeycloakAdapterConfigService INSTANCE = new KeycloakAdapterConfigService();
|
||||||
|
|
||||||
|
public static KeycloakAdapterConfigService getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, ModelNode> realms = new HashMap<String, ModelNode>();
|
||||||
|
|
||||||
|
// keycloak-secured deployments
|
||||||
|
private final Map<String, ModelNode> secureDeployments = new HashMap<String, ModelNode>();
|
||||||
|
|
||||||
|
|
||||||
|
private KeycloakAdapterConfigService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRealm(ModelNode operation, ModelNode model) {
|
||||||
|
this.realms.put(realmNameFromOp(operation), model.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateRealm(ModelNode operation, String attrName, ModelNode resolvedValue) {
|
||||||
|
ModelNode realm = this.realms.get(realmNameFromOp(operation));
|
||||||
|
realm.get(attrName).set(resolvedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRealm(ModelNode operation) {
|
||||||
|
this.realms.remove(realmNameFromOp(operation));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSecureDeployment(ModelNode operation, ModelNode model) {
|
||||||
|
ModelNode deployment = model.clone();
|
||||||
|
this.secureDeployments.put(deploymentNameFromOp(operation), deployment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSecureDeployment(ModelNode operation, String attrName, ModelNode resolvedValue) {
|
||||||
|
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
|
||||||
|
deployment.get(attrName).set(resolvedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSecureDeployment(ModelNode operation) {
|
||||||
|
this.secureDeployments.remove(deploymentNameFromOp(operation));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCredential(ModelNode operation, ModelNode model) {
|
||||||
|
ModelNode credentials = credentialsFromOp(operation);
|
||||||
|
if (!credentials.isDefined()) {
|
||||||
|
credentials = new ModelNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
String credentialName = credentialNameFromOp(operation);
|
||||||
|
credentials.get(credentialName).set(model.get("value").asString());
|
||||||
|
|
||||||
|
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
|
||||||
|
deployment.get(CREDENTIALS_JSON_NAME).set(credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeCredential(ModelNode operation) {
|
||||||
|
ModelNode credentials = credentialsFromOp(operation);
|
||||||
|
if (!credentials.isDefined()) {
|
||||||
|
throw new RuntimeException("Can not remove credential. No credential defined for deployment in op " + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String credentialName = credentialNameFromOp(operation);
|
||||||
|
credentials.remove(credentialName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCredential(ModelNode operation, String attrName, ModelNode resolvedValue) {
|
||||||
|
ModelNode credentials = credentialsFromOp(operation);
|
||||||
|
if (!credentials.isDefined()) {
|
||||||
|
throw new RuntimeException("Can not update credential. No credential defined for deployment in op " + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String credentialName = credentialNameFromOp(operation);
|
||||||
|
credentials.get(credentialName).set(resolvedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelNode credentialsFromOp(ModelNode operation) {
|
||||||
|
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
|
||||||
|
return deployment.get(CREDENTIALS_JSON_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String realmNameFromOp(ModelNode operation) {
|
||||||
|
return valueFromOpAddress(RealmDefinition.TAG_NAME, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String deploymentNameFromOp(ModelNode operation) {
|
||||||
|
return valueFromOpAddress(SecureDeploymentDefinition.TAG_NAME, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String credentialNameFromOp(ModelNode operation) {
|
||||||
|
return valueFromOpAddress(CredentialDefinition.TAG_NAME, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String valueFromOpAddress(String addrElement, ModelNode operation) {
|
||||||
|
String deploymentName = getValueOfAddrElement(operation.get(ADDRESS), addrElement);
|
||||||
|
if (deploymentName == null) throw new RuntimeException("Can't find '" + addrElement + "' in address " + operation.toString());
|
||||||
|
return deploymentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValueOfAddrElement(ModelNode address, String elementName) {
|
||||||
|
for (ModelNode element : address.asList()) {
|
||||||
|
if (element.has(elementName)) return element.get(elementName).asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealmName(String deploymentName) {
|
||||||
|
ModelNode deployment = this.secureDeployments.get(deploymentName);
|
||||||
|
return deployment.get(RealmDefinition.TAG_NAME).asString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJSON(String deploymentName) {
|
||||||
|
ModelNode deployment = this.secureDeployments.get(deploymentName);
|
||||||
|
String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
|
||||||
|
ModelNode realm = this.realms.get(realmName);
|
||||||
|
|
||||||
|
ModelNode json = new ModelNode();
|
||||||
|
json.get(RealmDefinition.TAG_NAME).set(realmName);
|
||||||
|
|
||||||
|
// Realm values set first. Some can be overridden by deployment values.
|
||||||
|
if (realm != null) setJSONValues(json, realm);
|
||||||
|
setJSONValues(json, deployment);
|
||||||
|
return json.toJSONString(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setJSONValues(ModelNode json, ModelNode values) {
|
||||||
|
for (Property prop : values.asPropertyList()) {
|
||||||
|
String name = prop.getName();
|
||||||
|
ModelNode value = prop.getValue();
|
||||||
|
if (value.isDefined()) {
|
||||||
|
json.get(name).set(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecureDeployment(String deploymentName) {
|
||||||
|
//log.info("********* CHECK KEYCLOAK DEPLOYMENT: deployments.size()" + deployments.size());
|
||||||
|
|
||||||
|
return this.secureDeployments.containsKey(deploymentName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.server.deployment.Attachments;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentPhaseContext;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnit;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
|
||||||
|
import org.jboss.as.server.deployment.module.ModuleDependency;
|
||||||
|
import org.jboss.as.server.deployment.module.ModuleSpecification;
|
||||||
|
import org.jboss.modules.Module;
|
||||||
|
import org.jboss.modules.ModuleIdentifier;
|
||||||
|
import org.jboss.modules.ModuleLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public abstract class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
|
||||||
|
|
||||||
|
private static final ModuleIdentifier KEYCLOAK_JBOSS_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-jboss-adapter-core");
|
||||||
|
private static final ModuleIdentifier KEYCLOAK_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-adapter-core");
|
||||||
|
private static final ModuleIdentifier KEYCLOAK_CORE = ModuleIdentifier.create("org.keycloak.keycloak-core");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
|
||||||
|
final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
|
||||||
|
|
||||||
|
// Next phase, need to detect if this is a Keycloak deployment. If not, don't add the modules.
|
||||||
|
|
||||||
|
final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
|
||||||
|
final ModuleLoader moduleLoader = Module.getBootModuleLoader();
|
||||||
|
addCommonModules(moduleSpecification, moduleLoader);
|
||||||
|
addPlatformSpecificModules(moduleSpecification, moduleLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCommonModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
|
||||||
|
// ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JBOSS_CORE_ADAPTER, false, false, false, false));
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE_ADAPTER, false, false, false, false));
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE, false, false, false, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected void addPlatformSpecificModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undeploy(DeploymentUnit du) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.server.deployment.module.ModuleDependency;
|
||||||
|
import org.jboss.as.server.deployment.module.ModuleSpecification;
|
||||||
|
import org.jboss.modules.ModuleIdentifier;
|
||||||
|
import org.jboss.modules.ModuleLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add platform-specific modules for WildFly.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakDependencyProcessorWildFly extends KeycloakDependencyProcessor {
|
||||||
|
|
||||||
|
private static final ModuleIdentifier KEYCLOAK_WILDFLY_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-wildfly-adapter");
|
||||||
|
private static final ModuleIdentifier KEYCLOAK_UNDERTOW_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-undertow-adapter");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addPlatformSpecificModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
|
||||||
|
// ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_WILDFLY_ADAPTER, false, false, true, false));
|
||||||
|
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_UNDERTOW_ADAPTER, false, false, false, false));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
|
||||||
|
import org.jboss.as.controller.parsing.ExtensionParsingContext;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
import org.keycloak.subsystem.wf8.logging.KeycloakLogger;
|
||||||
|
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main Extension class for the subsystem.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakExtension implements Extension {
|
||||||
|
|
||||||
|
public static final String SUBSYSTEM_NAME = "keycloak";
|
||||||
|
public static final String NAMESPACE = "urn:jboss:domain:keycloak:1.1";
|
||||||
|
private static final KeycloakSubsystemParser PARSER = new KeycloakSubsystemParser();
|
||||||
|
static final PathElement PATH_SUBSYSTEM = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
|
||||||
|
private static final String RESOURCE_NAME = KeycloakExtension.class.getPackage().getName() + ".LocalDescriptions";
|
||||||
|
private static final int MANAGEMENT_API_MAJOR_VERSION = 1;
|
||||||
|
private static final int MANAGEMENT_API_MINOR_VERSION = 0;
|
||||||
|
private static final int MANAGEMENT_API_MICRO_VERSION = 0;
|
||||||
|
static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
|
||||||
|
private static final ResourceDefinition KEYCLOAK_SUBSYSTEM_RESOURCE = new KeycloakSubsystemDefinition();
|
||||||
|
static final RealmDefinition REALM_DEFINITION = new RealmDefinition();
|
||||||
|
static final SecureDeploymentDefinition SECURE_DEPLOYMENT_DEFINITION = new SecureDeploymentDefinition();
|
||||||
|
static final CredentialDefinition CREDENTIAL_DEFINITION = new CredentialDefinition();
|
||||||
|
|
||||||
|
public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
|
||||||
|
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
|
||||||
|
for (String kp : keyPrefix) {
|
||||||
|
prefix.append('.').append(kp);
|
||||||
|
}
|
||||||
|
return new StandardResourceDescriptionResolver(prefix.toString(), RESOURCE_NAME, KeycloakExtension.class.getClassLoader(), true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeParsers(final ExtensionParsingContext context) {
|
||||||
|
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, KeycloakExtension.NAMESPACE, PARSER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initialize(final ExtensionContext context) {
|
||||||
|
KeycloakLogger.ROOT_LOGGER.debug("Activating Keycloak Extension");
|
||||||
|
final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, MANAGEMENT_API_MAJOR_VERSION, MANAGEMENT_API_MINOR_VERSION, MANAGEMENT_API_MICRO_VERSION);
|
||||||
|
|
||||||
|
ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
|
||||||
|
registration.registerSubModel(REALM_DEFINITION);
|
||||||
|
ManagementResourceRegistration secureDeploymentRegistration = registration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION);
|
||||||
|
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
|
||||||
|
|
||||||
|
subsystem.registerXMLElementWriter(PARSER);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.ServiceVerificationHandler;
|
||||||
|
import org.jboss.as.server.AbstractDeploymentChainStep;
|
||||||
|
import org.jboss.as.server.DeploymentProcessorTarget;
|
||||||
|
import org.jboss.as.server.deployment.Phase;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Keycloak subsystem add update handler.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
|
||||||
|
|
||||||
|
static final KeycloakSubsystemAdd INSTANCE = new KeycloakSubsystemAdd();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performBoottime(final OperationContext context, ModelNode operation, final ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) {
|
||||||
|
context.addStep(new AbstractDeploymentChainStep() {
|
||||||
|
@Override
|
||||||
|
protected void execute(DeploymentProcessorTarget processorTarget) {
|
||||||
|
processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, 0, chooseDependencyProcessor());
|
||||||
|
processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME,
|
||||||
|
Phase.POST_MODULE, // PHASE
|
||||||
|
Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
|
||||||
|
chooseConfigDeploymentProcessor());
|
||||||
|
}
|
||||||
|
}, OperationContext.Stage.RUNTIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeploymentUnitProcessor chooseDependencyProcessor() {
|
||||||
|
return new KeycloakDependencyProcessorWildFly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeploymentUnitProcessor chooseConfigDeploymentProcessor() {
|
||||||
|
return new KeycloakAdapterConfigDeploymentProcessor();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definition of subsystem=keycloak.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
|
||||||
|
protected KeycloakSubsystemDefinition() {
|
||||||
|
super(KeycloakExtension.SUBSYSTEM_PATH,
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver("subsystem"),
|
||||||
|
KeycloakSubsystemAdd.INSTANCE,
|
||||||
|
ReloadRequiredRemoveStepHandler.INSTANCE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerOperations(resourceRegistration);
|
||||||
|
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.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.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(KeycloakExtension.PATH_SUBSYSTEM));
|
||||||
|
list.add(addKeycloakSub);
|
||||||
|
|
||||||
|
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
|
||||||
|
if (reader.getLocalName().equals(RealmDefinition.TAG_NAME)) {
|
||||||
|
readRealm(reader, list);
|
||||||
|
}
|
||||||
|
else if (reader.getLocalName().equals(SecureDeploymentDefinition.TAG_NAME)) {
|
||||||
|
readDeployment(reader, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for debugging
|
||||||
|
private int nextTag(XMLExtendedStreamReader reader) throws XMLStreamException {
|
||||||
|
return reader.nextTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readRealm(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
|
||||||
|
String realmName = readNameAttribute(reader);
|
||||||
|
ModelNode addRealm = new ModelNode();
|
||||||
|
addRealm.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
|
||||||
|
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
|
||||||
|
PathElement.pathElement(RealmDefinition.TAG_NAME, realmName));
|
||||||
|
addRealm.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
|
||||||
|
|
||||||
|
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
|
||||||
|
String tagName = reader.getLocalName();
|
||||||
|
SimpleAttributeDefinition def = RealmDefinition.lookup(tagName);
|
||||||
|
if (def == null) throw new XMLStreamException("Unknown realm tag " + tagName);
|
||||||
|
def.parseAndSetParameter(reader.getElementText(), addRealm, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
|
||||||
|
//TODO: externalize the message
|
||||||
|
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
|
||||||
|
}
|
||||||
|
|
||||||
|
list.add(addRealm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readDeployment(XMLExtendedStreamReader reader, List<ModelNode> resourcesToAdd) throws XMLStreamException {
|
||||||
|
String name = readNameAttribute(reader);
|
||||||
|
ModelNode addSecureDeployment = new ModelNode();
|
||||||
|
addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
|
||||||
|
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
|
||||||
|
PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
|
||||||
|
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
|
||||||
|
List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>();
|
||||||
|
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
|
||||||
|
String tagName = reader.getLocalName();
|
||||||
|
if (tagName.equals(CredentialDefinition.TAG_NAME)) {
|
||||||
|
readCredential(reader, addr, credentialsToAdd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleAttributeDefinition def = SecureDeploymentDefinition.lookup(tagName);
|
||||||
|
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
|
||||||
|
def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO need to check realm-ref first.
|
||||||
|
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
|
||||||
|
//TODO: externalize the message
|
||||||
|
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Must add credentials after the deployment is added.
|
||||||
|
resourcesToAdd.add(addSecureDeployment);
|
||||||
|
resourcesToAdd.addAll(credentialsToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readCredential(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> credentialsToAdd) throws XMLStreamException {
|
||||||
|
String name = readNameAttribute(reader);
|
||||||
|
ModelNode addCredential = new ModelNode();
|
||||||
|
addCredential.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
|
||||||
|
PathAddress addr = PathAddress.pathAddress(parent, PathElement.pathElement(CredentialDefinition.TAG_NAME, name));
|
||||||
|
addCredential.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
|
||||||
|
addCredential.get(CredentialDefinition.VALUE.getName()).set(reader.getElementText());
|
||||||
|
credentialsToAdd.add(addCredential);
|
||||||
|
}
|
||||||
|
|
||||||
|
// expects that the current tag will have one single attribute called "name"
|
||||||
|
private String readNameAttribute(XMLExtendedStreamReader reader) throws XMLStreamException {
|
||||||
|
String name = null;
|
||||||
|
for (int i = 0; i < reader.getAttributeCount(); i++) {
|
||||||
|
String attr = reader.getAttributeLocalName(i);
|
||||||
|
if (attr.equals("name")) {
|
||||||
|
name = reader.getAttributeValue(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw ParseUtils.unexpectedAttribute(reader, i);
|
||||||
|
}
|
||||||
|
if (name == null) {
|
||||||
|
throw ParseUtils.missingRequired(reader, Collections.singleton("name"));
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
|
||||||
|
context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
|
||||||
|
writeRealms(writer, context);
|
||||||
|
writeSecureDeployments(writer, context);
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeRealms(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
|
||||||
|
if (!context.getModelNode().get(RealmDefinition.TAG_NAME).isDefined()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Property realm : context.getModelNode().get(RealmDefinition.TAG_NAME).asPropertyList()) {
|
||||||
|
writer.writeStartElement(RealmDefinition.TAG_NAME);
|
||||||
|
writer.writeAttribute("name", realm.getName());
|
||||||
|
ModelNode realmElements = realm.getValue();
|
||||||
|
for (AttributeDefinition element : RealmDefinition.ALL_ATTRIBUTES) {
|
||||||
|
element.marshallAsElement(realmElements, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeSecureDeployments(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
|
||||||
|
if (!context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).isDefined()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Property deployment : context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).asPropertyList()) {
|
||||||
|
writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME);
|
||||||
|
writer.writeAttribute("name", deployment.getName());
|
||||||
|
ModelNode deploymentElements = deployment.getValue();
|
||||||
|
for (AttributeDefinition element : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
|
||||||
|
element.marshallAsElement(deploymentElements, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode credentials = deploymentElements.get(CredentialDefinition.TAG_NAME);
|
||||||
|
if (credentials.isDefined()) {
|
||||||
|
writeCredentials(writer, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeCredentials(XMLExtendedStreamWriter writer, ModelNode credentials) throws XMLStreamException {
|
||||||
|
for (Property credential : credentials.asPropertyList()) {
|
||||||
|
writer.writeStartElement(CredentialDefinition.TAG_NAME);
|
||||||
|
writer.writeAttribute("name", credential.getName());
|
||||||
|
String credentialValue = credential.getValue().get(CredentialDefinition.VALUE.getName()).asString();
|
||||||
|
writeCharacters(writer, credentialValue);
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// code taken from org.jboss.as.controller.AttributeMarshaller
|
||||||
|
private void writeCharacters(XMLExtendedStreamWriter writer, String content) throws XMLStreamException {
|
||||||
|
if (content.indexOf('\n') > -1) {
|
||||||
|
// Multiline content. Use the overloaded variant that staxmapper will format
|
||||||
|
writer.writeCharacters(content);
|
||||||
|
} else {
|
||||||
|
// Staxmapper will just output the chars without adding newlines if this is used
|
||||||
|
char[] chars = content.toCharArray();
|
||||||
|
writer.writeCharacters(chars, 0, chars.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractAddStepHandler;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.as.controller.ServiceVerificationHandler;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public final class RealmAddHandler extends AbstractAddStepHandler {
|
||||||
|
|
||||||
|
public static RealmAddHandler INSTANCE = new RealmAddHandler();
|
||||||
|
|
||||||
|
private RealmAddHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
// TODO: localize exception. get id number
|
||||||
|
if (!operation.get(OP).asString().equals(ADD)) {
|
||||||
|
throw new OperationFailedException("Unexpected operation for add realm. operation=" + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AttributeDefinition attrib : RealmDefinition.ALL_ATTRIBUTES) {
|
||||||
|
attrib.validateAndSet(operation, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
|
||||||
|
//TODO: externalize message
|
||||||
|
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.addRealm(operation, context.resolveExpressions(model));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.PathElement;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||||
|
import org.jboss.as.controller.SimpleResourceDefinition;
|
||||||
|
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes and operations for the Realm
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmDefinition extends SimpleResourceDefinition {
|
||||||
|
|
||||||
|
public static final String TAG_NAME = "realm";
|
||||||
|
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> REALM_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
ALL_ATTRIBUTES.addAll(REALM_ONLY_ATTRIBUTES);
|
||||||
|
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
|
||||||
|
DEFINITION_LOOKUP.put(def.getXmlName(), def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final RealmWriteAttributeHandler realmAttrHandler = new RealmWriteAttributeHandler(ALL_ATTRIBUTES.toArray(new SimpleAttributeDefinition[0]));
|
||||||
|
|
||||||
|
public RealmDefinition() {
|
||||||
|
super(PathElement.pathElement("realm"),
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver("realm"),
|
||||||
|
RealmAddHandler.INSTANCE,
|
||||||
|
RealmRemoveHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerOperations(resourceRegistration);
|
||||||
|
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerAttributes(resourceRegistration);
|
||||||
|
|
||||||
|
for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
|
||||||
|
//TODO: use subclass of realmAttrHandler that can call RealmDefinition.validateTruststoreSetIfRequired
|
||||||
|
resourceRegistration.registerReadWriteAttribute(attrDef, null, realmAttrHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static SimpleAttributeDefinition lookup(String name) {
|
||||||
|
return DEFINITION_LOOKUP.get(name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractRemoveStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public final class RealmRemoveHandler extends AbstractRemoveStepHandler {
|
||||||
|
|
||||||
|
public static RealmRemoveHandler INSTANCE = new RealmRemoveHandler();
|
||||||
|
|
||||||
|
private RealmRemoveHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.removeRealm(operation);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractWriteAttributeHandler;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an attribute on a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
|
||||||
|
|
||||||
|
public RealmWriteAttributeHandler(AttributeDefinition... definitions) {
|
||||||
|
super(definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode resolvedValue, ModelNode currentValue, HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.updateRealm(operation, attributeName, resolvedValue);
|
||||||
|
|
||||||
|
hh.setHandback(ckService);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
|
||||||
|
ckService.updateRealm(operation, attributeName, valueToRestore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractAddStepHandler;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.as.controller.ServiceVerificationHandler;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.msc.service.ServiceController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
|
||||||
|
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a deployment to a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public final class SecureDeploymentAddHandler extends AbstractAddStepHandler {
|
||||||
|
|
||||||
|
public static SecureDeploymentAddHandler INSTANCE = new SecureDeploymentAddHandler();
|
||||||
|
|
||||||
|
private SecureDeploymentAddHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
// TODO: localize exception. get id number
|
||||||
|
if (!operation.get(OP).asString().equals(ADD)) {
|
||||||
|
throw new OperationFailedException("Unexpected operation for add secure deployment. operation=" + operation.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AttributeDefinition attr : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
|
||||||
|
attr.validateAndSet(operation, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.addSecureDeployment(operation, context.resolveExpressions(model));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.PathElement;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
|
||||||
|
import org.jboss.as.controller.SimpleResourceDefinition;
|
||||||
|
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
|
||||||
|
import org.jboss.as.controller.operations.validation.StringLengthValidator;
|
||||||
|
import org.jboss.as.controller.registry.ManagementResourceRegistration;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.ModelType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes and operations for a secure-deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
||||||
|
|
||||||
|
public static final String TAG_NAME = "secure-deployment";
|
||||||
|
|
||||||
|
protected static final SimpleAttributeDefinition REALM =
|
||||||
|
new SimpleAttributeDefinitionBuilder("realm", ModelType.STRING, true)
|
||||||
|
.setXmlName("realm")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition RESOURCE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
|
||||||
|
.setXmlName("resource")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition USE_RESOURCE_ROLE_MAPPINGS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("use-resource-role-mappings", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("use-resource-role-mappings")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition BEARER_ONLY =
|
||||||
|
new SimpleAttributeDefinitionBuilder("bearer-only", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("bearer-only")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition ENABLE_BASIC_AUTH =
|
||||||
|
new SimpleAttributeDefinitionBuilder("enable-basic-auth", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("enable-basic-auth")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
|
||||||
|
new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("public-client")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
|
||||||
|
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
ALL_ATTRIBUTES.addAll(DEPLOYMENT_ONLY_ATTRIBUTES);
|
||||||
|
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
|
||||||
|
DEFINITION_LOOKUP.put(def.getXmlName(), def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecureDeploymentWriteAttributeHandler attrHandler = new SecureDeploymentWriteAttributeHandler(ALL_ATTRIBUTES);
|
||||||
|
|
||||||
|
public SecureDeploymentDefinition() {
|
||||||
|
super(PathElement.pathElement(TAG_NAME),
|
||||||
|
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
|
||||||
|
SecureDeploymentAddHandler.INSTANCE,
|
||||||
|
SecureDeploymentRemoveHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerOperations(resourceRegistration);
|
||||||
|
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
|
||||||
|
super.registerAttributes(resourceRegistration);
|
||||||
|
for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
|
||||||
|
resourceRegistration.registerReadWriteAttribute(attrDef, null, attrHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimpleAttributeDefinition lookup(String name) {
|
||||||
|
return DEFINITION_LOOKUP.get(name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractRemoveStepHandler;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a secure-deployment from a realm.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public final class SecureDeploymentRemoveHandler extends AbstractRemoveStepHandler {
|
||||||
|
|
||||||
|
public static SecureDeploymentRemoveHandler INSTANCE = new SecureDeploymentRemoveHandler();
|
||||||
|
|
||||||
|
private SecureDeploymentRemoveHandler() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
ckService.removeSecureDeployment(operation);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.AbstractWriteAttributeHandler;
|
||||||
|
import org.jboss.as.controller.AttributeDefinition;
|
||||||
|
import org.jboss.as.controller.OperationContext;
|
||||||
|
import org.jboss.as.controller.OperationFailedException;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an attribute on a secure-deployment.
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SecureDeploymentWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
|
||||||
|
|
||||||
|
public SecureDeploymentWriteAttributeHandler(List<SimpleAttributeDefinition> definitions) {
|
||||||
|
this(definitions.toArray(new AttributeDefinition[definitions.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecureDeploymentWriteAttributeHandler(AttributeDefinition... definitions) {
|
||||||
|
super(definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode resolvedValue, ModelNode currentValue, HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
|
||||||
|
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
|
||||||
|
hh.setHandback(ckService);
|
||||||
|
ckService.updateSecureDeployment(operation, attributeName, resolvedValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
|
||||||
|
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
|
||||||
|
ckService.updateSecureDeployment(operation, attributeName, valueToRestore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinition;
|
||||||
|
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
|
||||||
|
import org.jboss.as.controller.operations.validation.IntRangeValidator;
|
||||||
|
import org.jboss.as.controller.operations.validation.StringLengthValidator;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.jboss.dmr.ModelType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines attributes that can be present in both a realm and an application (secure-deployment).
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class SharedAttributeDefinitons {
|
||||||
|
|
||||||
|
protected static final SimpleAttributeDefinition REALM_PUBLIC_KEY =
|
||||||
|
new SimpleAttributeDefinitionBuilder("realm-public-key", ModelType.STRING, true)
|
||||||
|
.setXmlName("realm-public-key")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition AUTH_SERVER_URL =
|
||||||
|
new SimpleAttributeDefinitionBuilder("auth-server-url", ModelType.STRING, true)
|
||||||
|
.setXmlName("auth-server-url")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition SSL_REQUIRED =
|
||||||
|
new SimpleAttributeDefinitionBuilder("ssl-required", ModelType.STRING, true)
|
||||||
|
.setXmlName("ssl-required")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode("external"))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition ALLOW_ANY_HOSTNAME =
|
||||||
|
new SimpleAttributeDefinitionBuilder("allow-any-hostname", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("allow-any-hostname")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition DISABLE_TRUST_MANAGER =
|
||||||
|
new SimpleAttributeDefinitionBuilder("disable-trust-manager", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("disable-trust-manager")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition TRUSTSTORE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("truststore", ModelType.STRING, true)
|
||||||
|
.setXmlName("truststore")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition TRUSTSTORE_PASSWORD =
|
||||||
|
new SimpleAttributeDefinitionBuilder("truststore-password", ModelType.STRING, true)
|
||||||
|
.setXmlName("truststore-password")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CONNECTION_POOL_SIZE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("connection-pool-size", ModelType.INT, true)
|
||||||
|
.setXmlName("connection-pool-size")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new IntRangeValidator(0, true))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
protected static final SimpleAttributeDefinition ENABLE_CORS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("enable-cors", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("enable-cors")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CLIENT_KEYSTORE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("client-keystore", ModelType.STRING, true)
|
||||||
|
.setXmlName("client-keystore")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CLIENT_KEYSTORE_PASSWORD =
|
||||||
|
new SimpleAttributeDefinitionBuilder("client-keystore-password", ModelType.STRING, true)
|
||||||
|
.setXmlName("client-keystore-password")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CLIENT_KEY_PASSWORD =
|
||||||
|
new SimpleAttributeDefinitionBuilder("client-key-password", ModelType.STRING, true)
|
||||||
|
.setXmlName("client-key-password")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CORS_MAX_AGE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("cors-max-age", ModelType.INT, true)
|
||||||
|
.setXmlName("cors-max-age")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new IntRangeValidator(-1, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CORS_ALLOWED_HEADERS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("cors-allowed-headers", ModelType.STRING, true)
|
||||||
|
.setXmlName("cors-allowed-headers")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition CORS_ALLOWED_METHODS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("cors-allowed-methods", ModelType.STRING, true)
|
||||||
|
.setXmlName("cors-allowed-methods")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition EXPOSE_TOKEN =
|
||||||
|
new SimpleAttributeDefinitionBuilder("expose-token", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("expose-token")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition AUTH_SERVER_URL_FOR_BACKEND_REQUESTS =
|
||||||
|
new SimpleAttributeDefinitionBuilder("auth-server-url-for-backend-requests", ModelType.STRING, true)
|
||||||
|
.setXmlName("auth-server-url-for-backend-requests")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition ALWAYS_REFRESH_TOKEN =
|
||||||
|
new SimpleAttributeDefinitionBuilder("always-refresh-token", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("always-refresh-token")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition REGISTER_NODE_AT_STARTUP =
|
||||||
|
new SimpleAttributeDefinitionBuilder("register-node-at-startup", ModelType.BOOLEAN, true)
|
||||||
|
.setXmlName("register-node-at-startup")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setDefaultValue(new ModelNode(false))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition REGISTER_NODE_PERIOD =
|
||||||
|
new SimpleAttributeDefinitionBuilder("register-node-period", ModelType.INT, true)
|
||||||
|
.setXmlName("register-node-period")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new IntRangeValidator(-1, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition TOKEN_STORE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("token-store", ModelType.STRING, true)
|
||||||
|
.setXmlName("token-store")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
protected static final SimpleAttributeDefinition PRINCIPAL_ATTRIBUTE =
|
||||||
|
new SimpleAttributeDefinitionBuilder("principal-attribute", ModelType.STRING, true)
|
||||||
|
.setXmlName("principal-attribute")
|
||||||
|
.setAllowExpression(true)
|
||||||
|
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||||
|
static {
|
||||||
|
ATTRIBUTES.add(REALM_PUBLIC_KEY);
|
||||||
|
ATTRIBUTES.add(AUTH_SERVER_URL);
|
||||||
|
ATTRIBUTES.add(TRUSTSTORE);
|
||||||
|
ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
|
||||||
|
ATTRIBUTES.add(SSL_REQUIRED);
|
||||||
|
ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
|
||||||
|
ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
|
||||||
|
ATTRIBUTES.add(CONNECTION_POOL_SIZE);
|
||||||
|
ATTRIBUTES.add(ENABLE_CORS);
|
||||||
|
ATTRIBUTES.add(CLIENT_KEYSTORE);
|
||||||
|
ATTRIBUTES.add(CLIENT_KEYSTORE_PASSWORD);
|
||||||
|
ATTRIBUTES.add(CLIENT_KEY_PASSWORD);
|
||||||
|
ATTRIBUTES.add(CORS_MAX_AGE);
|
||||||
|
ATTRIBUTES.add(CORS_ALLOWED_HEADERS);
|
||||||
|
ATTRIBUTES.add(CORS_ALLOWED_METHODS);
|
||||||
|
ATTRIBUTES.add(EXPOSE_TOKEN);
|
||||||
|
ATTRIBUTES.add(AUTH_SERVER_URL_FOR_BACKEND_REQUESTS);
|
||||||
|
ATTRIBUTES.add(ALWAYS_REFRESH_TOKEN);
|
||||||
|
ATTRIBUTES.add(REGISTER_NODE_AT_STARTUP);
|
||||||
|
ATTRIBUTES.add(REGISTER_NODE_PERIOD);
|
||||||
|
ATTRIBUTES.add(TOKEN_STORE);
|
||||||
|
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.
|
||||||
|
*
|
||||||
|
* @param attributes The full set of attributes.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the attributes are valid, <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean validateTruststoreSetIfRequired(ModelNode attributes) {
|
||||||
|
if (isSet(attributes, DISABLE_TRUST_MANAGER)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSet(attributes, SSL_REQUIRED) && attributes.get(SSL_REQUIRED.getName()).asString().equals("none")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSet(attributes, TRUSTSTORE) && isSet(attributes, TRUSTSTORE_PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
|
||||||
|
ModelNode attribute = attributes.get(def.getName());
|
||||||
|
|
||||||
|
if (def.getType() == ModelType.BOOLEAN) {
|
||||||
|
return attribute.isDefined() && attribute.asBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
return attribute.isDefined() && !attribute.asString().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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.wf8.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.wf8.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 @@
|
||||||
|
org.keycloak.subsystem.wf8.extension.KeycloakExtension
|
|
@ -0,0 +1,72 @@
|
||||||
|
keycloak.subsystem=Keycloak adapter subsystem
|
||||||
|
keycloak.subsystem.add=Operation Adds Keycloak adapter subsystem
|
||||||
|
keycloak.subsystem.remove=Operation removes Keycloak adapter subsystem
|
||||||
|
keycloak.subsystem.realm=A Keycloak realm.
|
||||||
|
keycloak.subsystem.secure-deployment=A deployment secured by Keycloak.
|
||||||
|
|
||||||
|
keycloak.realm=A Keycloak realm.
|
||||||
|
keycloak.realm.add=Add a realm definition to the subsystem.
|
||||||
|
keycloak.realm.remove=Remove a realm from the subsystem.
|
||||||
|
keycloak.realm.realm-public-key=Public key of the realm
|
||||||
|
keycloak.realm.auth-server-url=Base URL of the Realm Auth Server
|
||||||
|
keycloak.realm.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
|
||||||
|
keycloak.realm.ssl-required=Specify if SSL is required (valid values are all, external and none)
|
||||||
|
keycloak.realm.allow-any-hostname=SSL Setting
|
||||||
|
keycloak.realm.truststore=Truststore used for adapter client HTTPS requests
|
||||||
|
keycloak.realm.truststore-password=Password of the Truststore
|
||||||
|
keycloak.realm.connection-pool-size=Connection pool size for the client used by the adapter
|
||||||
|
keycloak.realm.enable-cors=Enable Keycloak CORS support
|
||||||
|
keycloak.realm.client-keystore=n/a
|
||||||
|
keycloak.realm.client-keystore-password=n/a
|
||||||
|
keycloak.realm.client-key-password=n/a
|
||||||
|
keycloak.realm.cors-max-age=CORS max-age header
|
||||||
|
keycloak.realm.cors-allowed-headers=CORS allowed headers
|
||||||
|
keycloak.realm.cors-allowed-methods=CORS allowed methods
|
||||||
|
keycloak.realm.expose-token=Enable secure URL that exposes access token
|
||||||
|
keycloak.realm.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
|
||||||
|
keycloak.realm.always-refresh-token=Refresh token on every single web request
|
||||||
|
keycloak.realm.register-node-at-startup=Cluster setting
|
||||||
|
keycloak.realm.register-node-period=how often to re-register node
|
||||||
|
keycloak.realm.token-store=cookie or session storage for auth session data
|
||||||
|
keycloak.realm.principal-attribute=token attribute to use to set Principal name
|
||||||
|
|
||||||
|
|
||||||
|
keycloak.secure-deployment=A deployment secured by Keycloak
|
||||||
|
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
|
||||||
|
keycloak.secure-deployment.realm=Keycloak realm
|
||||||
|
keycloak.secure-deployment.remove=Remove a deployment to be secured by Keycloak
|
||||||
|
keycloak.secure-deployment.realm-public-key=Public key of the realm
|
||||||
|
keycloak.secure-deployment.auth-server-url=Base URL of the Realm Auth Server
|
||||||
|
keycloak.secure-deployment.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
|
||||||
|
keycloak.secure-deployment.ssl-required=Specify if SSL is required (valid values are all, external and none)
|
||||||
|
keycloak.secure-deployment.allow-any-hostname=SSL Setting
|
||||||
|
keycloak.secure-deployment.truststore=Truststore used for adapter client HTTPS requests
|
||||||
|
keycloak.secure-deployment.truststore-password=Password of the Truststore
|
||||||
|
keycloak.secure-deployment.connection-pool-size=Connection pool size for the client used by the adapter
|
||||||
|
keycloak.secure-deployment.resource=Application name
|
||||||
|
keycloak.secure-deployment.use-resource-role-mappings=Use resource level permissions from token
|
||||||
|
keycloak.secure-deployment.credentials=Adapter credentials
|
||||||
|
keycloak.secure-deployment.bearer-only=Bearer Token Auth only
|
||||||
|
keycloak.secure-deployment.enable-basic-auth=Enable Basic Authentication
|
||||||
|
keycloak.secure-deployment.public-client=Public client
|
||||||
|
keycloak.secure-deployment.enable-cors=Enable Keycloak CORS support
|
||||||
|
keycloak.secure-deployment.client-keystore=n/a
|
||||||
|
keycloak.secure-deployment.client-keystore-password=n/a
|
||||||
|
keycloak.secure-deployment.client-key-password=n/a
|
||||||
|
keycloak.secure-deployment.cors-max-age=CORS max-age header
|
||||||
|
keycloak.secure-deployment.cors-allowed-headers=CORS allowed headers
|
||||||
|
keycloak.secure-deployment.cors-allowed-methods=CORS allowed methods
|
||||||
|
keycloak.secure-deployment.expose-token=Enable secure URL that exposes access token
|
||||||
|
keycloak.secure-deployment.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
|
||||||
|
keycloak.secure-deployment.always-refresh-token=Refresh token on every single web request
|
||||||
|
keycloak.secure-deployment.register-node-at-startup=Cluster setting
|
||||||
|
keycloak.secure-deployment.register-node-period=how often to re-register node
|
||||||
|
keycloak.secure-deployment.token-store=cookie or session storage for auth session data
|
||||||
|
keycloak.secure-deployment.principal-attribute=token attribute to use to set Principal name
|
||||||
|
|
||||||
|
keycloak.secure-deployment.credential=Credential value
|
||||||
|
|
||||||
|
keycloak.credential=Credential
|
||||||
|
keycloak.credential.value=Credential value
|
||||||
|
keycloak.credential.add=Credential add
|
||||||
|
keycloak.credential.remove=Credential remove
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="urn:jboss:domain:keycloak:1.1"
|
||||||
|
xmlns="urn:jboss:domain:keycloak: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 adapter subsystem, used to register deployments managed by Keycloak
|
||||||
|
]]>
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="realm-type"/>
|
||||||
|
<xs:element name="secure-deployment" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
|
||||||
|
</xs:choice>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="realm-type">
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="cors-allowed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="client-keystore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="client-keystore" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="enable-cors" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="client-key-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="cors-max-age" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="auth-server-url" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xs:element name="expose-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="register-node-at-startup" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="register-node-period" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</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="secure-deployment-type">
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="client-keystore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="client-keystore" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="enable-cors" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="cors-max-age" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="auth-server-url" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xs:element name="realm" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="cors-allowed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="client-key-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="public-client" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="expose-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xs:element name="credential" type="credential-type" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="register-node-at-startup" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="register-node-period" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xs:element name="enable-basic-auth" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</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="credential-type">
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:string">
|
||||||
|
<xs:attribute name="name" type="xs:string" />
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:schema>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<!-- Template used by WildFly build when directed to include Keycloak subsystem in a configuration. -->
|
||||||
|
<config>
|
||||||
|
<extension-module>org.keycloak.keycloak-wf8-subsystem</extension-module>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
|
||||||
|
</subsystem>
|
||||||
|
</config>
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
|
||||||
|
*/
|
||||||
|
public class RealmDefinitionTestCase {
|
||||||
|
|
||||||
|
private ModelNode model;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
model = new ModelNode();
|
||||||
|
model.get("realm").set("demo");
|
||||||
|
model.get("resource").set("customer-portal");
|
||||||
|
model.get("realm-public-key").set("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB");
|
||||||
|
model.get("auth-url").set("http://localhost:8080/auth-server/rest/realms/demo/protocol/openid-connect/login");
|
||||||
|
model.get("code-url").set("http://localhost:8080/auth-server/rest/realms/demo/protocol/openid-connect/access/codes");
|
||||||
|
model.get("expose-token").set(true);
|
||||||
|
ModelNode credential = new ModelNode();
|
||||||
|
credential.get("password").set("password");
|
||||||
|
model.get("credentials").set(credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsTruststoreSetIfRequired() throws Exception {
|
||||||
|
model.get("ssl-required").set("none");
|
||||||
|
model.get("disable-trust-manager").set(true);
|
||||||
|
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-required").set("none");
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-required").set("all");
|
||||||
|
model.get("disable-trust-manager").set(true);
|
||||||
|
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-required").set("all");
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-required").set("external");
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-required").set("all");
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
model.get("truststore").set("foo");
|
||||||
|
Assert.assertFalse(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-required").set("all");
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
model.get("truststore").set("foo");
|
||||||
|
model.get("truststore-password").set("password");
|
||||||
|
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
|
||||||
|
model.get("ssl-required").set("external");
|
||||||
|
model.get("disable-trust-manager").set(false);
|
||||||
|
model.get("truststore").set("foo");
|
||||||
|
model.get("truststore-password").set("password");
|
||||||
|
Assert.assertTrue(SharedAttributeDefinitons.validateTruststoreSetIfRequired(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @author tags. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.subsystem.wf8.extension;
|
||||||
|
|
||||||
|
import org.jboss.as.subsystem.test.AbstractSubsystemBaseTest;
|
||||||
|
import org.jboss.dmr.ModelNode;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
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(KeycloakExtension.SUBSYSTEM_NAME, new KeycloakExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJson() throws Exception {
|
||||||
|
ModelNode node = new ModelNode();
|
||||||
|
node.get("realm").set("demo");
|
||||||
|
node.get("resource").set("customer-portal");
|
||||||
|
node.get("realm-public-key").set("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB");
|
||||||
|
node.get("auth-url").set("http://localhost:8080/auth-server/rest/realms/demo/protocol/openid-connect/login");
|
||||||
|
node.get("code-url").set("http://localhost:8080/auth-server/rest/realms/demo/protocol/openid-connect/access/codes");
|
||||||
|
node.get("ssl-required").set("external");
|
||||||
|
node.get("expose-token").set(true);
|
||||||
|
ModelNode credential = new ModelNode();
|
||||||
|
credential.get("password").set("password");
|
||||||
|
node.get("credentials").set(credential);
|
||||||
|
|
||||||
|
System.out.println("json=" + node.toJSONString(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSubsystemXml() throws IOException {
|
||||||
|
return readResource("keycloak-1.1.xml");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
|
||||||
|
<secure-deployment name="web-console">
|
||||||
|
<realm>master</realm>
|
||||||
|
<resource>web-console</resource>
|
||||||
|
<use-resource-role-mappings>true</use-resource-role-mappings>
|
||||||
|
<realm-public-key>
|
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4siLKUew0WYxdtq6/rwk4Uj/4amGFFnE/yzIxQVU0PUqz3QBRVkUWpDj0K6ZnS5nzJV/y6DHLEy7hjZTdRDphyF1sq09aDOYnVpzu8o2sIlMM8q5RnUyEfIyUZqwo8pSZDJ90fS0s+IDUJNCSIrAKO3w1lqZDHL6E/YFHXyzkvQIDAQAB
|
||||||
|
</realm-public-key>
|
||||||
|
<auth-server-url>http://localhost:8080/auth</auth-server-url>
|
||||||
|
<ssl-required>EXTERNAL</ssl-required>
|
||||||
|
<credential name="secret">0aa31d98-e0aa-404c-b6e0-e771dba1e798</credential>
|
||||||
|
</secure-deployment>
|
||||||
|
<secure-deployment name="http-endpoint">
|
||||||
|
<realm>master</realm>
|
||||||
|
<resource>http-endpoint</resource>
|
||||||
|
<use-resource-role-mappings>true</use-resource-role-mappings>
|
||||||
|
<realm-public-key>
|
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4siLKUew0WYxdtq6/rwk4Uj/4amGFFnE/yzIxQVU0PUqz3QBRVkUWpDj0K6ZnS5nzJV/y6DHLEy7hjZTdRDphyF1sq09aDOYnVpzu8o2sIlMM8q5RnUyEfIyUZqwo8pSZDJ90fS0s+IDUJNCSIrAKO3w1lqZDHL6E/YFHXyzkvQIDAQAB
|
||||||
|
</realm-public-key>
|
||||||
|
<auth-server-url>http://localhost:8080/auth</auth-server-url>
|
||||||
|
<ssl-required>EXTERNAL</ssl-required>
|
||||||
|
<credential name="secret">2769a4a2-5be0-454f-838f-f33b7755b667</credential>
|
||||||
|
</secure-deployment>
|
||||||
|
</subsystem>
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.keycloak.mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class MapperConfigValidationException extends Exception {
|
||||||
|
|
||||||
|
public MapperConfigValidationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapperConfigValidationException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,36 @@
|
||||||
package org.keycloak.mappers;
|
package org.keycloak.mappers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
import org.keycloak.provider.ConfiguredProvider;
|
import org.keycloak.provider.ConfiguredProvider;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public interface UserFederationMapperFactory extends ProviderFactory<UserFederationMapper>, ConfiguredProvider {
|
public interface UserFederationMapperFactory extends ProviderFactory<UserFederationMapper>, ConfiguredProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refers to providerName (type) of the federation provider, which this mapper can be used for. For example "ldap" or "kerberos"
|
||||||
|
*
|
||||||
|
* @return providerName
|
||||||
|
*/
|
||||||
|
String getFederationProviderType();
|
||||||
|
|
||||||
|
String getDisplayCategory();
|
||||||
|
String getDisplayType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when instance of mapperModel is created for this factory through admin endpoint
|
||||||
|
*
|
||||||
|
* @param mapperModel
|
||||||
|
* @throws MapperConfigValidationException if configuration provided in mapperModel is not valid
|
||||||
|
*/
|
||||||
|
void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException;
|
||||||
|
|
||||||
|
// TODO: Remove this and add realm to the method on ConfiguredProvider?
|
||||||
|
List<ProviderConfigProperty> getConfigProperties(RealmModel realm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.keycloak.models.utils;
|
package org.keycloak.models.utils;
|
||||||
|
|
||||||
import org.bouncycastle.openssl.PEMWriter;
|
import org.bouncycastle.openssl.PEMWriter;
|
||||||
|
import org.keycloak.constants.KerberosConstants;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
@ -8,6 +9,7 @@ import org.keycloak.models.KeycloakSessionTask;
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
import org.keycloak.models.KeycloakTransaction;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RequiredCredentialModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
|
@ -349,4 +351,31 @@ public final class KeycloakModelUtils {
|
||||||
|
|
||||||
return mapperModel;
|
return mapperModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically add "kerberos" to required realm credentials if it's supported by saved provider
|
||||||
|
*
|
||||||
|
* @param realm
|
||||||
|
* @param model
|
||||||
|
* @return true if kerberos credentials were added
|
||||||
|
*/
|
||||||
|
public static boolean checkKerberosCredential(RealmModel realm, UserFederationProviderModel model) {
|
||||||
|
String allowKerberosCfg = model.getConfig().get(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION);
|
||||||
|
if (Boolean.valueOf(allowKerberosCfg)) {
|
||||||
|
boolean found = false;
|
||||||
|
List<RequiredCredentialModel> currentCreds = realm.getRequiredCredentials();
|
||||||
|
for (RequiredCredentialModel cred : currentCreds) {
|
||||||
|
if (cred.getType().equals(UserCredentialModel.KERBEROS)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
realm.addRequiredCredential(UserCredentialModel.KERBEROS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
12
pom.xml
12
pom.xml
|
@ -1079,6 +1079,12 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<type>zip</type>
|
<type>zip</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-wf8-modules</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>zip</type>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-server-overlay</artifactId>
|
<artifactId>keycloak-server-overlay</artifactId>
|
||||||
|
@ -1272,7 +1278,9 @@
|
||||||
<profile>
|
<profile>
|
||||||
<id>jboss-earlyaccess-repository</id>
|
<id>jboss-earlyaccess-repository</id>
|
||||||
<activation>
|
<activation>
|
||||||
<activeByDefault>true</activeByDefault>
|
<property>
|
||||||
|
<name>!no-jboss-ea-repo</name>
|
||||||
|
</property>
|
||||||
</activation>
|
</activation>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
|
@ -1303,6 +1311,7 @@
|
||||||
<id>distribution</id>
|
<id>distribution</id>
|
||||||
<modules>
|
<modules>
|
||||||
<module>distribution</module>
|
<module>distribution</module>
|
||||||
|
<module>testsuite/integration-arquillian</module>
|
||||||
</modules>
|
</modules>
|
||||||
</profile>
|
</profile>
|
||||||
<profile>
|
<profile>
|
||||||
|
@ -1310,6 +1319,7 @@
|
||||||
<modules>
|
<modules>
|
||||||
<module>docbook</module>
|
<module>docbook</module>
|
||||||
<module>distribution</module>
|
<module>distribution</module>
|
||||||
|
<module>testsuite/integration-arquillian</module>
|
||||||
</modules>
|
</modules>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|
|
@ -892,6 +892,13 @@ public class LoginActionsService {
|
||||||
ClientSessionModel clientSession = accessCode.getClientSession();
|
ClientSessionModel clientSession = accessCode.getClientSession();
|
||||||
|
|
||||||
String username = formData.getFirst("username");
|
String username = formData.getFirst("username");
|
||||||
|
if(username == null || username.isEmpty()) {
|
||||||
|
event.error(Errors.USERNAME_MISSING);
|
||||||
|
return session.getProvider(LoginFormsProvider.class)
|
||||||
|
.setError(Messages.MISSING_USERNAME)
|
||||||
|
.setClientSessionCode(accessCode.getCode())
|
||||||
|
.createPasswordReset();
|
||||||
|
}
|
||||||
|
|
||||||
ClientModel client = clientSession.getClient();
|
ClientModel client = clientSession.getClient();
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
|
|
|
@ -235,8 +235,8 @@ public class RealmAdminResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("user-federation")
|
@Path("user-federation")
|
||||||
public UserFederationResource userFederation() {
|
public UserFederationProvidersResource userFederation() {
|
||||||
UserFederationResource fed = new UserFederationResource(realm, auth, adminEvent);
|
UserFederationProvidersResource fed = new UserFederationProvidersResource(realm, auth, adminEvent);
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(fed);
|
ResteasyProviderFactory.getInstance().injectProperties(fed);
|
||||||
//resourceContext.initResource(fed);
|
//resourceContext.initResource(fed);
|
||||||
return fed;
|
return fed;
|
||||||
|
|
|
@ -0,0 +1,298 @@
|
||||||
|
package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
|
import org.keycloak.events.admin.OperationType;
|
||||||
|
import org.keycloak.mappers.MapperConfigValidationException;
|
||||||
|
import org.keycloak.mappers.UserFederationMapper;
|
||||||
|
import org.keycloak.mappers.UserFederationMapperFactory;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
|
import org.keycloak.models.UserFederationSyncResult;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
|
import org.keycloak.models.utils.RepresentationToModel;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserFederationMapperRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserFederationMapperTypeRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||||
|
import org.keycloak.services.ErrorResponseException;
|
||||||
|
import org.keycloak.services.managers.UsersSyncManager;
|
||||||
|
import org.keycloak.timer.TimerProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class UserFederationProviderResource {
|
||||||
|
|
||||||
|
protected static final Logger logger = Logger.getLogger(UserFederationProviderResource.class);
|
||||||
|
|
||||||
|
private final KeycloakSession session;
|
||||||
|
private final RealmModel realm;
|
||||||
|
private final RealmAuth auth;
|
||||||
|
private final UserFederationProviderModel federationProviderModel;
|
||||||
|
private final AdminEventBuilder adminEvent;
|
||||||
|
|
||||||
|
@Context
|
||||||
|
private UriInfo uriInfo;
|
||||||
|
|
||||||
|
public UserFederationProviderResource(KeycloakSession session, RealmModel realm, RealmAuth auth, UserFederationProviderModel federationProviderModel, AdminEventBuilder adminEvent) {
|
||||||
|
this.session = session;
|
||||||
|
this.realm = realm;
|
||||||
|
this.auth = auth;
|
||||||
|
this.federationProviderModel = federationProviderModel;
|
||||||
|
this.adminEvent = adminEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a provider
|
||||||
|
*
|
||||||
|
* @param rep
|
||||||
|
*/
|
||||||
|
@PUT
|
||||||
|
@NoCache
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public void updateProviderInstance(UserFederationProviderRepresentation rep) {
|
||||||
|
auth.requireManage();
|
||||||
|
String displayName = rep.getDisplayName();
|
||||||
|
if (displayName != null && displayName.trim().equals("")) {
|
||||||
|
displayName = null;
|
||||||
|
}
|
||||||
|
UserFederationProviderModel model = new UserFederationProviderModel(rep.getId(), rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
||||||
|
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
||||||
|
realm.updateUserFederationProvider(model);
|
||||||
|
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
||||||
|
boolean kerberosCredsAdded = KeycloakModelUtils.checkKerberosCredential(realm, model);
|
||||||
|
if (kerberosCredsAdded) {
|
||||||
|
logger.info("Added 'kerberos' to required realm credentials");
|
||||||
|
}
|
||||||
|
|
||||||
|
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a provider
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public UserFederationProviderRepresentation getProviderInstance() {
|
||||||
|
auth.requireView();
|
||||||
|
return ModelToRepresentation.toRepresentation(this.federationProviderModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a provider
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@NoCache
|
||||||
|
public void deleteProviderInstance() {
|
||||||
|
auth.requireManage();
|
||||||
|
|
||||||
|
realm.removeUserFederationProvider(this.federationProviderModel);
|
||||||
|
new UsersSyncManager().removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), this.federationProviderModel);
|
||||||
|
|
||||||
|
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* trigger sync of users
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("sync")
|
||||||
|
@NoCache
|
||||||
|
public UserFederationSyncResult syncUsers(@QueryParam("action") String action) {
|
||||||
|
logger.debug("Syncing users");
|
||||||
|
auth.requireManage();
|
||||||
|
|
||||||
|
UsersSyncManager syncManager = new UsersSyncManager();
|
||||||
|
UserFederationSyncResult syncResult = null;
|
||||||
|
if ("triggerFullSync".equals(action)) {
|
||||||
|
syncResult = syncManager.syncAllUsers(session.getKeycloakSessionFactory(), realm.getId(), this.federationProviderModel);
|
||||||
|
} else if ("triggerChangedUsersSync".equals(action)) {
|
||||||
|
syncResult = syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), this.federationProviderModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
||||||
|
return syncResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of available User Federation mapper types
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("mapper-types")
|
||||||
|
@NoCache
|
||||||
|
public Map<String, UserFederationMapperTypeRepresentation> getMapperTypes() {
|
||||||
|
this.auth.requireView();
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
Map<String, UserFederationMapperTypeRepresentation> types = new HashMap<>();
|
||||||
|
List<ProviderFactory> factories = sessionFactory.getProviderFactories(UserFederationMapper.class);
|
||||||
|
|
||||||
|
for (ProviderFactory factory : factories) {
|
||||||
|
UserFederationMapperFactory mapperFactory = (UserFederationMapperFactory)factory;
|
||||||
|
if (mapperFactory.getFederationProviderType().equals(this.federationProviderModel.getProviderName())) {
|
||||||
|
|
||||||
|
UserFederationMapperTypeRepresentation rep = new UserFederationMapperTypeRepresentation();
|
||||||
|
rep.setId(mapperFactory.getId());
|
||||||
|
rep.setCategory(mapperFactory.getDisplayCategory());
|
||||||
|
rep.setName(mapperFactory.getDisplayType());
|
||||||
|
rep.setHelpText(mapperFactory.getHelpText());
|
||||||
|
List<ProviderConfigProperty> configProperties = mapperFactory.getConfigProperties(realm);
|
||||||
|
for (ProviderConfigProperty prop : configProperties) {
|
||||||
|
ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation();
|
||||||
|
propRep.setName(prop.getName());
|
||||||
|
propRep.setLabel(prop.getLabel());
|
||||||
|
propRep.setType(prop.getType());
|
||||||
|
propRep.setDefaultValue(prop.getDefaultValue());
|
||||||
|
propRep.setHelpText(prop.getHelpText());
|
||||||
|
rep.getProperties().add(propRep);
|
||||||
|
}
|
||||||
|
types.put(rep.getId(), rep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get mappers configured for this provider
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("mappers")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
public List<UserFederationMapperRepresentation> getMappers() {
|
||||||
|
this.auth.requireView();
|
||||||
|
List<UserFederationMapperRepresentation> mappers = new LinkedList<>();
|
||||||
|
for (UserFederationMapperModel model : realm.getUserFederationMappersByFederationProvider(this.federationProviderModel.getId())) {
|
||||||
|
mappers.add(ModelToRepresentation.toRepresentation(realm, model));
|
||||||
|
}
|
||||||
|
return mappers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mapper
|
||||||
|
*
|
||||||
|
* @param mapper
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("mappers")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public Response addMapper(UserFederationMapperRepresentation mapper) {
|
||||||
|
auth.requireManage();
|
||||||
|
UserFederationMapperModel model = RepresentationToModel.toModel(realm, mapper);
|
||||||
|
|
||||||
|
validateModel(model);
|
||||||
|
|
||||||
|
model = realm.addUserFederationMapper(model);
|
||||||
|
|
||||||
|
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId())
|
||||||
|
.representation(mapper).success();
|
||||||
|
|
||||||
|
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get mapper
|
||||||
|
*
|
||||||
|
* @param id mapperId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Path("mappers/{id}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public UserFederationMapperRepresentation getMapperById(@PathParam("id") String id) {
|
||||||
|
auth.requireView();
|
||||||
|
UserFederationMapperModel model = realm.getUserFederationMapperById(id);
|
||||||
|
if (model == null) throw new NotFoundException("Model not found");
|
||||||
|
return ModelToRepresentation.toRepresentation(realm, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update mapper
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @param rep
|
||||||
|
*/
|
||||||
|
@PUT
|
||||||
|
@NoCache
|
||||||
|
@Path("mappers/{id}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public void update(@PathParam("id") String id, UserFederationMapperRepresentation rep) {
|
||||||
|
auth.requireManage();
|
||||||
|
UserFederationMapperModel model = realm.getUserFederationMapperById(id);
|
||||||
|
if (model == null) throw new NotFoundException("Model not found");
|
||||||
|
model = RepresentationToModel.toModel(realm, rep);
|
||||||
|
|
||||||
|
validateModel(model);
|
||||||
|
|
||||||
|
realm.updateUserFederationMapper(model);
|
||||||
|
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete mapper with given ID
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@NoCache
|
||||||
|
@Path("mappers/{id}")
|
||||||
|
public void delete(@PathParam("id") String id) {
|
||||||
|
auth.requireManage();
|
||||||
|
UserFederationMapperModel model = realm.getUserFederationMapperById(id);
|
||||||
|
if (model == null) throw new NotFoundException("Model not found");
|
||||||
|
realm.removeUserFederationMapper(model);
|
||||||
|
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateModel(UserFederationMapperModel model) {
|
||||||
|
try {
|
||||||
|
UserFederationMapperFactory mapperFactory = (UserFederationMapperFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationMapper.class, model.getFederationMapperType());
|
||||||
|
mapperFactory.validateConfig(model);
|
||||||
|
} catch (MapperConfigValidationException ex) {
|
||||||
|
throw new ErrorResponseException("Validation error", ex.getMessage(), Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,16 +3,14 @@ package org.keycloak.services.resources.admin;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
import org.keycloak.constants.KerberosConstants;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.keycloak.events.admin.OperationType;
|
import org.keycloak.events.admin.OperationType;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RequiredCredentialModel;
|
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserFederationProvider;
|
import org.keycloak.models.UserFederationProvider;
|
||||||
import org.keycloak.models.UserFederationProviderFactory;
|
import org.keycloak.models.UserFederationProviderFactory;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserFederationSyncResult;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
|
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
|
||||||
|
@ -21,14 +19,11 @@ import org.keycloak.services.managers.UsersSyncManager;
|
||||||
import org.keycloak.timer.TimerProvider;
|
import org.keycloak.timer.TimerProvider;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -43,8 +38,8 @@ import java.util.List;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UserFederationResource {
|
public class UserFederationProvidersResource {
|
||||||
protected static final Logger logger = Logger.getLogger(UserFederationResource.class);
|
protected static final Logger logger = Logger.getLogger(UserFederationProvidersResource.class);
|
||||||
|
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
|
|
||||||
|
@ -58,7 +53,7 @@ public class UserFederationResource {
|
||||||
@Context
|
@Context
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
|
||||||
public UserFederationResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
public UserFederationProvidersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent;
|
||||||
|
@ -88,7 +83,7 @@ public class UserFederationResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get List of available provider factories
|
* Get factory with given ID
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -130,77 +125,17 @@ public class UserFederationResource {
|
||||||
UserFederationProviderModel model = realm.addUserFederationProvider(rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
UserFederationProviderModel model = realm.addUserFederationProvider(rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
||||||
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
||||||
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
||||||
checkKerberosCredential(model);
|
boolean kerberosCredsAdded = KeycloakModelUtils.checkKerberosCredential(realm, model);
|
||||||
|
if (kerberosCredsAdded) {
|
||||||
|
logger.info("Added 'kerberos' to required realm credentials");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(rep).success();
|
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(rep).success();
|
||||||
|
|
||||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
|
return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a provider
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* @param rep
|
|
||||||
*/
|
|
||||||
@PUT
|
|
||||||
@Path("instances/{id}")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public void updateProviderInstance(@PathParam("id") String id, UserFederationProviderRepresentation rep) {
|
|
||||||
auth.requireManage();
|
|
||||||
String displayName = rep.getDisplayName();
|
|
||||||
if (displayName != null && displayName.trim().equals("")) {
|
|
||||||
displayName = null;
|
|
||||||
}
|
|
||||||
UserFederationProviderModel model = new UserFederationProviderModel(id, rep.getProviderName(), rep.getConfig(), rep.getPriority(), displayName,
|
|
||||||
rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync());
|
|
||||||
realm.updateUserFederationProvider(model);
|
|
||||||
new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId());
|
|
||||||
checkKerberosCredential(model);
|
|
||||||
|
|
||||||
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get a provider
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@NoCache
|
|
||||||
@Path("instances/{id}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public UserFederationProviderRepresentation getProviderInstance(@PathParam("id") String id) {
|
|
||||||
auth.requireView();
|
|
||||||
for (UserFederationProviderModel model : realm.getUserFederationProviders()) {
|
|
||||||
if (model.getId().equals(id)) {
|
|
||||||
return ModelToRepresentation.toRepresentation(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new NotFoundException("could not find provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a provider
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
@DELETE
|
|
||||||
@Path("instances/{id}")
|
|
||||||
public void deleteProviderInstance(@PathParam("id") String id) {
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
UserFederationProviderRepresentation rep = getProviderInstance(id);
|
|
||||||
UserFederationProviderModel model = new UserFederationProviderModel(id, null, null, -1, null, -1, -1, 0);
|
|
||||||
realm.removeUserFederationProvider(model);
|
|
||||||
new UsersSyncManager().removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), model);
|
|
||||||
|
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* list configured providers
|
* list configured providers
|
||||||
*
|
*
|
||||||
|
@ -220,53 +155,18 @@ public class UserFederationResource {
|
||||||
return reps;
|
return reps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Path("instances/{id}")
|
||||||
* trigger sync of users
|
public UserFederationProviderResource getUserFederationInstance(@PathParam("id") String id) {
|
||||||
*
|
this.auth.requireView();
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@POST
|
|
||||||
@Path("sync/{id}")
|
|
||||||
@NoCache
|
|
||||||
public UserFederationSyncResult syncUsers(@PathParam("id") String providerId, @QueryParam("action") String action) {
|
|
||||||
logger.debug("Syncing users");
|
|
||||||
auth.requireManage();
|
|
||||||
|
|
||||||
for (UserFederationProviderModel model : realm.getUserFederationProviders()) {
|
UserFederationProviderModel model = KeycloakModelUtils.findUserFederationProviderById(id, realm);
|
||||||
if (model.getId().equals(providerId)) {
|
if (model == null) {
|
||||||
UsersSyncManager syncManager = new UsersSyncManager();
|
throw new NotFoundException("Could not find federation provider with id: " + id);
|
||||||
UserFederationSyncResult syncResult = null;
|
|
||||||
if ("triggerFullSync".equals(action)) {
|
|
||||||
syncResult = syncManager.syncAllUsers(session.getKeycloakSessionFactory(), realm.getId(), model);
|
|
||||||
} else if ("triggerChangedUsersSync".equals(action)) {
|
|
||||||
syncResult = syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), model);
|
|
||||||
}
|
|
||||||
|
|
||||||
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
|
|
||||||
return syncResult;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotFoundException("could not find provider");
|
UserFederationProviderResource instanceResource = new UserFederationProviderResource(session, realm, this.auth, model, adminEvent);
|
||||||
}
|
ResteasyProviderFactory.getInstance().injectProperties(instanceResource);
|
||||||
|
return instanceResource;
|
||||||
// Automatically add "kerberos" to required realm credentials if it's supported by saved provider
|
|
||||||
private void checkKerberosCredential(UserFederationProviderModel model) {
|
|
||||||
String allowKerberosCfg = model.getConfig().get(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION);
|
|
||||||
if (Boolean.valueOf(allowKerberosCfg)) {
|
|
||||||
boolean found = false;
|
|
||||||
List<RequiredCredentialModel> currentCreds = realm.getRequiredCredentials();
|
|
||||||
for (RequiredCredentialModel cred : currentCreds) {
|
|
||||||
if (cred.getType().equals(UserCredentialModel.KERBEROS)) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
realm.addRequiredCredential(UserCredentialModel.KERBEROS);
|
|
||||||
logger.info("Added 'kerberos' to required realm credentials");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
21
testsuite/integration-arquillian/README.md
Normal file
21
testsuite/integration-arquillian/README.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
Testing admin console with Arquillian
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
There are currently two ways of running the tests with help of Arquillian.
|
||||||
|
|
||||||
|
Remote mode
|
||||||
|
----------
|
||||||
|
|
||||||
|
Just simply typle `mvn verify` and you are all set. This requires the instance of Wildfly with embedded Keycloak to be already running.
|
||||||
|
|
||||||
|
Managed mode
|
||||||
|
------------
|
||||||
|
|
||||||
|
You need to pass two arguments to Maven, first is location of your Wildfly server with embedded Keycloak and the other is name of the profile.
|
||||||
|
|
||||||
|
mvn verify -Pwildfly-8-managed -DjbossHome=/your/server/location
|
||||||
|
|
||||||
|
Browser
|
||||||
|
-------
|
||||||
|
|
||||||
|
There are currently two supported browsers - PhantomJS and Firefox. PhantomJS is the default one, in order to use Firefox just specify `-Dbrowser=firefox` parameter in the Maven command.
|
182
testsuite/integration-arquillian/pom.xml
Normal file
182
testsuite/integration-arquillian/pom.xml
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-testsuite-pom</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.3.0.Final-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>arquillian-integration</artifactId>
|
||||||
|
<name>KeyCloak Admin UI TestSuite</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<browser>phantomjs</browser>
|
||||||
|
|
||||||
|
<arquillian-core.version>1.1.5.Final</arquillian-core.version>
|
||||||
|
<selenium.version>2.45.0</selenium.version>
|
||||||
|
<arquillian-drone.version>1.3.1.Final</arquillian-drone.version>
|
||||||
|
<arquillian-phantomjs.version>1.1.4.Final</arquillian-phantomjs.version>
|
||||||
|
<arquillian-graphene.version>2.0.3.Final</arquillian-graphene.version>
|
||||||
|
<arquillian-wildfly-container.version>8.1.0.Final</arquillian-wildfly-container.version>
|
||||||
|
|
||||||
|
<!-- Used in profile "wildfly-8-remote".
|
||||||
|
Set to "false" if admin password has already been updated after first login. -->
|
||||||
|
<firstAdminLogin>true</firstAdminLogin>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.arquillian.selenium</groupId>
|
||||||
|
<artifactId>selenium-bom</artifactId>
|
||||||
|
<version>${selenium.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.arquillian</groupId>
|
||||||
|
<artifactId>arquillian-bom</artifactId>
|
||||||
|
<version>${arquillian-core.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.arquillian.extension</groupId>
|
||||||
|
<artifactId>arquillian-drone-bom</artifactId>
|
||||||
|
<version>${arquillian-drone.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-arquillian-container-remote</artifactId>
|
||||||
|
<version>${arquillian-wildfly-container.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-arquillian-container-managed</artifactId>
|
||||||
|
<version>${arquillian-wildfly-container.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.arquillian.junit</groupId>
|
||||||
|
<artifactId>arquillian-junit-container</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.arquillian.graphene</groupId>
|
||||||
|
<artifactId>graphene-webdriver</artifactId>
|
||||||
|
<version>${arquillian-graphene.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.arquillian.extension</groupId>
|
||||||
|
<artifactId>arquillian-phantom-driver</artifactId>
|
||||||
|
<version>${arquillian-phantomjs.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>wildfly-8-remote</id>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-arquillian-container-remote</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<shouldDeploy>false</shouldDeploy>
|
||||||
|
<arquillian.launch>wildfly-8-remote</arquillian.launch>
|
||||||
|
<browser>${browser}</browser>
|
||||||
|
<firstAdminLogin>${first.login}</firstAdminLogin>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>wildfly-8-managed</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-arquillian-container-managed</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<properties>
|
||||||
|
<install.directory>${project.build.directory}/install</install.directory>
|
||||||
|
<jbossHome>${install.directory}/keycloak-${project.version}</jbossHome>
|
||||||
|
</properties>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>2.10</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>unpack</id>
|
||||||
|
<phase>process-test-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-server-dist</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>zip</type>
|
||||||
|
<overWrite>false</overWrite>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
<outputDirectory>${install.directory}</outputDirectory>
|
||||||
|
<overWriteReleases>false</overWriteReleases>
|
||||||
|
<overWriteSnapshots>true</overWriteSnapshots>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<shouldDeploy>false</shouldDeploy>
|
||||||
|
<arquillian.launch>wildfly-8-managed</arquillian.launch>
|
||||||
|
<browser>${browser}</browser>
|
||||||
|
<jbossHome>${jbossHome}</jbossHome>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.keycloak.testsuite.ui.page.AbstractPage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
* @param <P>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractKeyCloakTest<P extends AbstractPage> extends AbstractTest {
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected P page;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);
|
||||||
|
driver.manage().window().maximize();
|
||||||
|
loginAsAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
logOut();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.jboss.arquillian.junit.Arquillian;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.keycloak.testsuite.ui.fragment.Navigation;
|
||||||
|
import org.keycloak.testsuite.ui.fragment.MenuPage;
|
||||||
|
import org.keycloak.testsuite.ui.page.LoginPage;
|
||||||
|
import org.keycloak.testsuite.ui.page.account.PasswordPage;
|
||||||
|
import static org.keycloak.testsuite.ui.util.Constants.ADMIN_PSSWD;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.ui.util.URL.BASE_URL;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
@RunWith(Arquillian.class)
|
||||||
|
public abstract class AbstractTest {
|
||||||
|
|
||||||
|
private static boolean firstAdminLogin = Boolean.parseBoolean(
|
||||||
|
System.getProperty("firstAdminLogin", "true"));
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected LoginPage loginPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected PasswordPage passwordPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected MenuPage menuPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected Navigation navigation;
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
protected WebDriver driver;
|
||||||
|
|
||||||
|
public void logOut() {
|
||||||
|
menuPage.logOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loginAsAdmin() {
|
||||||
|
driver.get(BASE_URL);
|
||||||
|
loginPage.loginAsAdmin();
|
||||||
|
if (firstAdminLogin) {
|
||||||
|
passwordPage.confirmNewPassword(ADMIN_PSSWD);
|
||||||
|
passwordPage.submit();
|
||||||
|
firstAdminLogin = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.fragment;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import static org.openqa.selenium.By.id;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class CreateRealm {
|
||||||
|
|
||||||
|
@FindBy(css = ".btn-primary")
|
||||||
|
private WebElement primaryButton;
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
private WebDriver driver;
|
||||||
|
|
||||||
|
public void importRealm(String filePath) {
|
||||||
|
driver.findElement(id("import-file")).sendKeys(filePath);
|
||||||
|
primaryButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createRealm(String name, boolean on) {
|
||||||
|
driver.findElement(id("name")).sendKeys(name);
|
||||||
|
primaryButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createRealm(String name) {
|
||||||
|
createRealm(name, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.fragment;
|
||||||
|
|
||||||
|
import static org.jboss.arquillian.graphene.Graphene.waitGui;
|
||||||
|
import org.jboss.arquillian.graphene.fragment.Root;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.ui.util.SeleniumUtils.waitGuiForElement;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class FlashMessage {
|
||||||
|
|
||||||
|
@Root
|
||||||
|
private WebElement root;
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
waitGui().until("Flash message should be success")
|
||||||
|
.element(root)
|
||||||
|
.attribute("class")
|
||||||
|
.contains("success");
|
||||||
|
return root.getAttribute("class").contains("success");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isError() {
|
||||||
|
waitGui().until("Flash message should be error")
|
||||||
|
.element(root)
|
||||||
|
.attribute("class")
|
||||||
|
.contains("error");
|
||||||
|
return root.getAttribute("class").contains("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDanger() {
|
||||||
|
waitGui().until("Flash message should be danger")
|
||||||
|
.element(root)
|
||||||
|
.attribute("class")
|
||||||
|
.contains("danger");
|
||||||
|
return root.getAttribute("class").contains("danger");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return root.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitUntilPresent() {
|
||||||
|
waitGuiForElement(root, "Flash message should be visible.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.fragment;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import static org.keycloak.testsuite.ui.util.SeleniumUtils.waitGuiForElement;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class MenuPage {
|
||||||
|
|
||||||
|
private static final String MENU_LOCATOR = "ul[class='dropdown-menu']";
|
||||||
|
|
||||||
|
@FindBy(css = MENU_LOCATOR)
|
||||||
|
private List<WebElement> menuList;
|
||||||
|
|
||||||
|
@FindBy(css = ".dropdown-toggle")
|
||||||
|
private List<WebElement> toggle;
|
||||||
|
|
||||||
|
public void logOut() {
|
||||||
|
clickOnMenuElement(Menu.USER, "Sign Out");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void goToAccountManagement() {
|
||||||
|
clickOnMenuElement(Menu.USER, "Manage Account");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void switchRealm(String realmName) {
|
||||||
|
clickOnMenuElement(Menu.REALM, realmName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentRealm() {
|
||||||
|
waitGuiForElement(By.cssSelector(MENU_LOCATOR));
|
||||||
|
return toggle.get(1).getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickOnMenuElement(Menu menuType, String linkText) {
|
||||||
|
int menuOrder = 0;
|
||||||
|
switch(menuType) {
|
||||||
|
case REALM: menuOrder = 1; break;
|
||||||
|
case USER: menuOrder = 0; break;
|
||||||
|
}
|
||||||
|
waitGuiForElement(By.cssSelector(MENU_LOCATOR));
|
||||||
|
if (!menuList.get(menuOrder).isDisplayed())
|
||||||
|
toggle.get(menuOrder).click();
|
||||||
|
for (WebElement item : menuList.get(menuOrder).findElements(By.cssSelector(MENU_LOCATOR + " a"))) {
|
||||||
|
if (item.getText().contains(linkText)) {
|
||||||
|
item.click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Could not find menu item containing \"" + linkText + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Menu {
|
||||||
|
USER, REALM
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.fragment;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import static org.jboss.arquillian.graphene.Graphene.waitModel;
|
||||||
|
import static org.keycloak.testsuite.ui.util.SeleniumUtils.waitGuiForElement;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.findby.FindByJQuery;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class Navigation {
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
private WebDriver driver;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Settings')")
|
||||||
|
private WebElement settingsLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Users')")
|
||||||
|
private WebElement usersLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Roles')")
|
||||||
|
private WebElement rolesLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Clients')")
|
||||||
|
private WebElement clientsLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('OAuth')")
|
||||||
|
private WebElement oauthLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Tokens')")
|
||||||
|
private WebElement tokensLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Sessions')")
|
||||||
|
private WebElement sessionLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Security Defenses')")
|
||||||
|
private WebElement securityLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Events')")
|
||||||
|
private WebElement eventsLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Login')")
|
||||||
|
private WebElement loginLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Themes')")
|
||||||
|
private WebElement themesLink;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Role Mappings')")
|
||||||
|
private WebElement usersRoleMappings;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Add Realm')")
|
||||||
|
private WebElement addRealm;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Credentials')")
|
||||||
|
private WebElement credentials;
|
||||||
|
|
||||||
|
@FindByJQuery("a:contains('Attributes')")
|
||||||
|
private WebElement attributes;
|
||||||
|
|
||||||
|
@FindBy(css = "div h1")
|
||||||
|
private WebElement currentHeader;
|
||||||
|
|
||||||
|
public void selectRealm(String realmName) {
|
||||||
|
driver.findElement(By.linkText(realmName)).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void settings() {
|
||||||
|
openPage(settingsLink, "Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void users() {
|
||||||
|
openPage(usersLink, "Users");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void roles() {
|
||||||
|
openPage(rolesLink, "Roles");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clients() {
|
||||||
|
openPage(clientsLink, "Clients");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void oauth() {
|
||||||
|
openPage(oauthLink, "OAuth Clients");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tokens() {
|
||||||
|
openPage(tokensLink, "Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sessions() {
|
||||||
|
openPage(sessionLink, "Sessions");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void security() {
|
||||||
|
openPage(securityLink, "Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void events() {
|
||||||
|
openPage(eventsLink, "Events");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void login() {
|
||||||
|
openPage(loginLink, "Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void themes() {
|
||||||
|
openPage(themesLink, "Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void roleMappings() {
|
||||||
|
openPage(usersRoleMappings, "User");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRealm() {
|
||||||
|
openPage(addRealm, "Add Realm");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void credentials() {
|
||||||
|
openPage(credentials, "Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attributes() {
|
||||||
|
openPage(attributes, "Attributes");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openPage(WebElement page, String headerText) {
|
||||||
|
waitGuiForElement(page);
|
||||||
|
page.click();
|
||||||
|
waitModel().until().element(currentHeader).text().contains(headerText);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.fragment;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.fragment.Root;
|
||||||
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.interactions.Actions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class OnOffSwitch {
|
||||||
|
|
||||||
|
@Root
|
||||||
|
private WebElement root;
|
||||||
|
|
||||||
|
@ArquillianResource
|
||||||
|
private Actions actions;
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return root.findElement(By.tagName("input")).isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void click() {
|
||||||
|
actions.moveToElement(root.findElements(By.tagName("span")).get(0))
|
||||||
|
.click().build().perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggle() {
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enable() {
|
||||||
|
if(!isEnabled()) {
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable() {
|
||||||
|
if(isEnabled()) {
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.fragment;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.fragment.Root;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class PickList {
|
||||||
|
|
||||||
|
@Root
|
||||||
|
private WebElement root;
|
||||||
|
|
||||||
|
private Select firstSelect;
|
||||||
|
private Select secondSelect;
|
||||||
|
|
||||||
|
@FindBy(className = "kc-icon-arrow-right")
|
||||||
|
private WebElement rightArrow;
|
||||||
|
|
||||||
|
@FindBy(className = "kc-icon-arrow-left")
|
||||||
|
private WebElement leftArrow;
|
||||||
|
|
||||||
|
public void addItems(String... values) {
|
||||||
|
for(String value : values) {
|
||||||
|
firstSelect.selectByVisibleText(value);
|
||||||
|
}
|
||||||
|
rightArrow.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstSelect(By locator) {
|
||||||
|
firstSelect = new Select(root.findElement(locator));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecondSelect(By locator) {
|
||||||
|
secondSelect = new Select(root.findElement(locator));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class Account {
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
private String firstName;
|
||||||
|
|
||||||
|
public Account(String username, String email, String lastName, String firstName) {
|
||||||
|
this.username = username;
|
||||||
|
this.email = email;
|
||||||
|
this.lastName = lastName;
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastName(String lastName) {
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(String firstName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Account account = (Account) o;
|
||||||
|
|
||||||
|
if (email != null ? !email.equals(account.email) : account.email != null) return false;
|
||||||
|
if (firstName != null ? !firstName.equals(account.firstName) : account.firstName != null) return false;
|
||||||
|
if (lastName != null ? !lastName.equals(account.lastName) : account.lastName != null) return false;
|
||||||
|
if (username != null ? !username.equals(account.username) : account.username != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = username != null ? username.hashCode() : 0;
|
||||||
|
result = 31 * result + (email != null ? email.hashCode() : 0);
|
||||||
|
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
|
||||||
|
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Filip Kiss
|
||||||
|
*/
|
||||||
|
public class Client {
|
||||||
|
|
||||||
|
private String clientId;
|
||||||
|
private String name;
|
||||||
|
private boolean enabled;
|
||||||
|
private String accessType;
|
||||||
|
private String uri;
|
||||||
|
|
||||||
|
public Client(String clientId, String uri) {
|
||||||
|
this.name = clientId;
|
||||||
|
this.clientId = clientId;
|
||||||
|
this.uri = uri;
|
||||||
|
this.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Client(String clientId, String name, String uri) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
this.uri = uri;
|
||||||
|
this.enabled = true;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Client() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Client(String name, String uri, String accessType, boolean enabled) {
|
||||||
|
this.name = name;
|
||||||
|
this.uri = uri;
|
||||||
|
this.accessType = accessType;
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
|
||||||
|
public boolean isEnabled() { return enabled; }
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) { this.enabled = enabled; }
|
||||||
|
|
||||||
|
public String getAccessType() { return accessType; }
|
||||||
|
|
||||||
|
public void setAccessType(String accessType) { this.accessType = accessType; }
|
||||||
|
|
||||||
|
public String getUri() { return uri; }
|
||||||
|
|
||||||
|
public void setUri(String uri) { this.uri = uri; }
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Client that = (Client) o;
|
||||||
|
|
||||||
|
if (enabled != that.enabled) return false;
|
||||||
|
if (accessType != null ? !accessType.equals(that.accessType) : that.accessType != null) return false;
|
||||||
|
if (!name.equals(that.name)) return false;
|
||||||
|
if (!uri.equals(that.uri)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = name.hashCode();
|
||||||
|
result = 31 * result + (enabled ? 1 : 0);
|
||||||
|
result = 31 * result + (accessType != null ? accessType.hashCode() : 0);
|
||||||
|
result = 31 * result + uri.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public enum PasswordPolicy {
|
||||||
|
|
||||||
|
HASH_ITERATIONS("Hash Iterations"), LENGTH("Length"), DIGITS("Digits"), LOWER_CASE("Lower Case"),
|
||||||
|
UPPER_CASE("Upper Case"), SPECIAL_CHARS("Special Chars");
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private PasswordPolicy(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class Provider {
|
||||||
|
|
||||||
|
public SocialProvider providerName;
|
||||||
|
public String key;
|
||||||
|
public String secret;
|
||||||
|
|
||||||
|
public Provider() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Provider(SocialProvider providerName, String key, String secret) {
|
||||||
|
this.providerName = providerName;
|
||||||
|
this.key = key;
|
||||||
|
this.secret = secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class Role {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private boolean composite;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public Role() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role(String name) {
|
||||||
|
this(name, false, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role(String name, boolean composite) {
|
||||||
|
this(name, composite, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role(String name, boolean composite, String description) {
|
||||||
|
this.name = name;
|
||||||
|
this.composite = composite;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isComposite() {
|
||||||
|
return composite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComposite(boolean composite) {
|
||||||
|
this.composite = composite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public enum SocialProvider {
|
||||||
|
|
||||||
|
FACEBOOK("Facebook"), GITHUB("Github"), GOOGLE("Google"), TWITTER("Twitter");
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private SocialProvider(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public enum Theme {
|
||||||
|
|
||||||
|
BASE("base"), KEYCLOAK("keycloak"), PATTERNFLY("patternfly");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private Theme(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Filip Kiss
|
||||||
|
*/
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String firstName;
|
||||||
|
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
private boolean userEnabled;
|
||||||
|
|
||||||
|
private boolean emailVerified;
|
||||||
|
|
||||||
|
private String requiredUserActions;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
this.userEnabled = true;
|
||||||
|
this.emailVerified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String userName) {
|
||||||
|
this();
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String userName, String password) {
|
||||||
|
this(userName);
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String userName, String password, String email) {
|
||||||
|
this(userName, password);
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String userName, String password, String email, String firstName, String lastName) {
|
||||||
|
this(userName, password, email);
|
||||||
|
this.firstName = firstName;
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String userName, String password, String email, String firstName, String lastName, boolean userEnabled, boolean emailVerified, String requiredUserActions) {
|
||||||
|
this(userName, password, email, firstName, lastName);
|
||||||
|
this.requiredUserActions = requiredUserActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(User user) {
|
||||||
|
this(user.userName, user.password, user.email, user.firstName, user.lastName,
|
||||||
|
user.userEnabled, user.emailVerified, user.requiredUserActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() { return userName; }
|
||||||
|
|
||||||
|
public void setUserName(String userName) { this.userName = userName; }
|
||||||
|
|
||||||
|
public String getEmail() { return email; }
|
||||||
|
|
||||||
|
public void setEmail(String email) { this.email = email; }
|
||||||
|
|
||||||
|
public String getFirstName() { return firstName; }
|
||||||
|
|
||||||
|
public void setFirstName(String firstName) { this.firstName = firstName; }
|
||||||
|
|
||||||
|
public String getLastName() { return lastName; }
|
||||||
|
|
||||||
|
public void setLastName(String lastName) { this.lastName = lastName; }
|
||||||
|
|
||||||
|
public boolean isUserEnabled() { return userEnabled; }
|
||||||
|
|
||||||
|
public void setUserEnabled(boolean userEnabled) { this.userEnabled = userEnabled; }
|
||||||
|
|
||||||
|
public boolean isEmailVerified() { return emailVerified; }
|
||||||
|
|
||||||
|
public void setEmailVerified(boolean emailVerified) { this.emailVerified = emailVerified; }
|
||||||
|
|
||||||
|
public String getRequiredUserActions() { return requiredUserActions; }
|
||||||
|
|
||||||
|
public void setRequiredUserActions(String requiredUserActions) { this.requiredUserActions = requiredUserActions; }
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
User user = (User) o;
|
||||||
|
|
||||||
|
if (emailVerified != user.emailVerified) return false;
|
||||||
|
if (userEnabled != user.userEnabled) return false;
|
||||||
|
if (email != null ? !email.equals(user.email) : user.email != null) return false;
|
||||||
|
if (firstName != null ? !firstName.equals(user.firstName) : user.firstName != null) return false;
|
||||||
|
if (lastName != null ? !lastName.equals(user.lastName) : user.lastName != null) return false;
|
||||||
|
if (requiredUserActions != null ? !requiredUserActions.equals(user.requiredUserActions) : user.requiredUserActions != null)
|
||||||
|
return false;
|
||||||
|
if (!userName.equals(user.userName)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = userName.hashCode();
|
||||||
|
result = 31 * result + (email != null ? email.hashCode() : 0);
|
||||||
|
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
|
||||||
|
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
|
||||||
|
result = 31 * result + (userEnabled ? 1 : 0);
|
||||||
|
result = 31 * result + (emailVerified ? 1 : 0);
|
||||||
|
result = 31 * result + (requiredUserActions != null ? requiredUserActions.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public enum UserAction {
|
||||||
|
|
||||||
|
UPDATE_PASSWORD("Update Password"), VERIFY_EMAIL("Verify Email"), UPDATE_PROFILE("Update Profile"), CONFIGURE_TOTP("Configure Totp");
|
||||||
|
|
||||||
|
private final String actionName;
|
||||||
|
|
||||||
|
private UserAction(String actionName) {
|
||||||
|
this.actionName = actionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getActionName() {
|
||||||
|
return actionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.page;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import org.keycloak.testsuite.ui.util.Constants;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class AbstractPage {
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
protected WebDriver driver;
|
||||||
|
|
||||||
|
@FindBy(css = ".btn-danger")
|
||||||
|
protected WebElement dangerButton;
|
||||||
|
|
||||||
|
//@FindByJQuery(".btn-primary:visible")
|
||||||
|
@FindBy(css = ".btn-primary")
|
||||||
|
protected WebElement primaryButton;
|
||||||
|
|
||||||
|
@FindBy(css = ".btn-primary")
|
||||||
|
protected List<WebElement> primaryButtons;
|
||||||
|
|
||||||
|
|
||||||
|
@FindBy(css = ".ng-binding.btn.btn-danger")
|
||||||
|
protected WebElement deleteConfirmationButton;
|
||||||
|
|
||||||
|
public void goToPage(String page) {
|
||||||
|
driver.get(String.format(page, Constants.CURRENT_REALM));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.page;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.ui.util.Constants.ADMIN_PSSWD;
|
||||||
|
import static org.keycloak.testsuite.ui.util.SeleniumUtils.waitGuiForElement;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class LoginPage extends AbstractPage {
|
||||||
|
|
||||||
|
@FindBy(id = "username")
|
||||||
|
private WebElement usernameInput;
|
||||||
|
|
||||||
|
@FindBy(id = "password")
|
||||||
|
private WebElement passwordInput;
|
||||||
|
|
||||||
|
@FindBy(linkText = "Register")
|
||||||
|
private WebElement registerLink;
|
||||||
|
|
||||||
|
@FindBy(id = "kc-header")
|
||||||
|
private WebElement loginPageHeader;
|
||||||
|
|
||||||
|
public void login(String username, String password) {
|
||||||
|
waitGuiForElement(usernameInput, "Login form should be visible");
|
||||||
|
usernameInput.sendKeys(username);
|
||||||
|
passwordInput.sendKeys(password);
|
||||||
|
passwordInput.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loginAsAdmin() {
|
||||||
|
login("admin", ADMIN_PSSWD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void goToUserRegistration() {
|
||||||
|
waitGuiForElement(usernameInput, "Login form should be visible");
|
||||||
|
registerLink.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLoginPageHeaderText() {
|
||||||
|
return loginPageHeader.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebElement getLoginPageHeader() {
|
||||||
|
return loginPageHeader;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.page;
|
||||||
|
|
||||||
|
import org.keycloak.testsuite.ui.model.User;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.ui.util.SeleniumUtils.waitGuiForElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Filip Kiss
|
||||||
|
*/
|
||||||
|
public class RegisterPage extends AbstractPage {
|
||||||
|
|
||||||
|
@FindBy(id = "username")
|
||||||
|
private WebElement usernameInput;
|
||||||
|
|
||||||
|
@FindBy(id = "email")
|
||||||
|
private WebElement emailInput;
|
||||||
|
|
||||||
|
@FindBy(id = "firstName")
|
||||||
|
private WebElement firstNameInput;
|
||||||
|
|
||||||
|
@FindBy(id = "lastName")
|
||||||
|
private WebElement lastNameInput;
|
||||||
|
|
||||||
|
@FindBy(id = "password")
|
||||||
|
private WebElement passwordInput;
|
||||||
|
|
||||||
|
@FindBy(id = "password-confirm")
|
||||||
|
private WebElement passwordConfirmInput;
|
||||||
|
|
||||||
|
@FindBy(css = "span.kc-feedback-text")
|
||||||
|
private WebElement feedbackError;
|
||||||
|
|
||||||
|
@FindBy(css = "div[id='kc-form-options'] span a")
|
||||||
|
private WebElement backToLoginForm;
|
||||||
|
|
||||||
|
public void registerNewUser(User user) {
|
||||||
|
registerNewUser(user, user.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerNewUser(User user, String confirmPassword) {
|
||||||
|
driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);
|
||||||
|
waitGuiForElement(passwordConfirmInput, "Register form should be visible");
|
||||||
|
clearAndType(usernameInput, user.getUserName());
|
||||||
|
clearAndType(firstNameInput, user.getFirstName());
|
||||||
|
clearAndType(lastNameInput, user.getLastName());
|
||||||
|
clearAndType(emailInput, user.getEmail());
|
||||||
|
clearAndType(passwordInput, user.getPassword());
|
||||||
|
clearAndType(passwordConfirmInput, confirmPassword);
|
||||||
|
primaryButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearAndType(WebElement webElement, String text) {
|
||||||
|
webElement.clear();
|
||||||
|
webElement.sendKeys(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInvalidEmail() {
|
||||||
|
waitGuiForElement(feedbackError, "Feedback message should be visible");
|
||||||
|
return feedbackError.getText().equals("Invalid email address.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAttributeSpecified(String attribute) {
|
||||||
|
waitGuiForElement(feedbackError, "Feedback message should be visible");
|
||||||
|
return !feedbackError.getText().contains("Please specify " + attribute + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPasswordSame() {
|
||||||
|
waitGuiForElement(feedbackError, "Feedback message should be visible");
|
||||||
|
return !feedbackError.getText().equals("Password confirmation doesn't match.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void backToLoginPage() {
|
||||||
|
backToLoginForm.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
*
|
||||||
|
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||||
|
*
|
||||||
|
* 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.testsuite.ui.page.account;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.findby.FindByJQuery;
|
||||||
|
import org.keycloak.testsuite.ui.model.Account;
|
||||||
|
import org.keycloak.testsuite.ui.page.AbstractPage;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Petr Mensik
|
||||||
|
*/
|
||||||
|
public class AccountPage extends AbstractPage {
|
||||||
|
|
||||||
|
@FindBy(id = "username")
|
||||||
|
private WebElement username;
|
||||||
|
|
||||||
|
@FindBy(id = "email")
|
||||||
|
private WebElement email;
|
||||||
|
|
||||||
|
@FindBy(id = "lastName")
|
||||||
|
private WebElement lastName;
|
||||||
|
|
||||||
|
@FindBy(id = "firstName")
|
||||||
|
private WebElement firstName;
|
||||||
|
|
||||||
|
@FindByJQuery("button[value='Save']")
|
||||||
|
private WebElement save;
|
||||||
|
|
||||||
|
@FindByJQuery(".nav li:eq(0) a")
|
||||||
|
private WebElement keyclockConsole;
|
||||||
|
|
||||||
|
@FindByJQuery(".nav li:eq(1) a")
|
||||||
|
private WebElement signOutLink;
|
||||||
|
|
||||||
|
@FindByJQuery(".bs-sidebar ul li:eq(0) a")
|
||||||
|
private WebElement accountLink;
|
||||||
|
|
||||||
|
@FindByJQuery(".bs-sidebar ul li:eq(1) a")
|
||||||
|
private WebElement passwordLink;
|
||||||
|
|
||||||
|
@FindByJQuery(".bs-sidebar ul li:eq(2) a")
|
||||||
|
private WebElement authenticatorLink;
|
||||||
|
|
||||||
|
@FindByJQuery(".bs-sidebar ul li:eq(3) a")
|
||||||
|
private WebElement sessionsLink;
|
||||||
|
|
||||||
|
|
||||||
|
public Account getAccount() {
|
||||||
|
return new Account(username.getAttribute("value"), email.getAttribute("value"), lastName.getAttribute("value"), firstName.getAttribute("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccount(Account account) {
|
||||||
|
email.clear();
|
||||||
|
email.sendKeys(account.getEmail());
|
||||||
|
lastName.clear();
|
||||||
|
lastName.sendKeys(account.getLastName());
|
||||||
|
firstName.clear();
|
||||||
|
firstName.sendKeys(account.getFirstName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
save.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void keycloakConsole() {
|
||||||
|
keyclockConsole.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void signOut() {
|
||||||
|
signOutLink.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void account() {
|
||||||
|
accountLink.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void password() {
|
||||||
|
passwordLink.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void authenticator() {
|
||||||
|
authenticatorLink.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sessions() {
|
||||||
|
sessionsLink.click();
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue