keycloak-uncached
Changes
client-registration/cli/src/main/java/org/keycloak/client/registration/cli/ClientRegistrationCLI.java 2(+2 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.bat 73(+73 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.sh 72(+72 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/aesh/0.65/module.xml 37(+37 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml 2(+1 -1)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adduser/main/module.xml 15(+15 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml 4(+2 -2)
distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-eap6-server-subsystem/main/module.xml 2(+1 -1)
distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-eap6-server-subsystem/main/server-war/WEB-INF/jboss-deployment-structure.xml 0(+0 -0)
distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-eap6-server-subsystem/main/server-war/WEB-INF/web.xml 0(+0 -0)
distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml 2(+1 -1)
integration/as7-eap6/pom.xml 1(+0 -1)
integration/wildfly/pom.xml 2(+0 -2)
pom.xml 12(+9 -3)
testsuite/integration/pom.xml 4(+4 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/offlineconfig/AdminRecoveryTest.java 133(+0 -133)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java 4(+2 -2)
wildfly/adduser/pom.xml 54(+54 -0)
wildfly/extensions/pom.xml 3(+1 -2)
wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/ModuleProviderLoaderFactory.java 0(+0 -0)
wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/ModuleThemeProviderFactory.java 0(+0 -0)
wildfly/extensions/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory 0(+0 -0)
wildfly/extensions/src/main/resources/META-INF/services/org.keycloak.provider.ProviderLoaderFactory 0(+0 -0)
wildfly/pom.xml 22(+22 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakAdapterConfigService.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakExtension.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakServerDeploymentProcessor.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakSubsystemAdd.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakSubsystemDefinition.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakSubsystemParser.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakSubsystemRemoveHandler.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/KeycloakSubsystemWriteAttributeHandler.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/as7/ServerUtil.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakLogger.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakMessages.java 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/resources/org/keycloak/subsystem/server/as7/LocalDescriptions.properties 0(+0 -0)
wildfly/server-eap6-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml 0(+0 -0)
wildfly/server-eap6-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml 0(+0 -0)
wildfly/server-subsystem/pom.xml 13(+3 -10)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakServerDeploymentProcessor.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemRemoveHandler.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemWriteAttributeHandler.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/ServerUtil.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakLogger.java 0(+0 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/logging/KeycloakMessages.java 0(+0 -0)
wildfly/server-subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension 0(+0 -0)
wildfly/server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties 0(+0 -0)
Details
diff --git a/client-registration/cli/src/main/java/org/keycloak/client/registration/cli/ClientRegistrationCLI.java b/client-registration/cli/src/main/java/org/keycloak/client/registration/cli/ClientRegistrationCLI.java
index 986faac..e76648b 100644
--- a/client-registration/cli/src/main/java/org/keycloak/client/registration/cli/ClientRegistrationCLI.java
+++ b/client-registration/cli/src/main/java/org/keycloak/client/registration/cli/ClientRegistrationCLI.java
@@ -57,6 +57,8 @@ public class ClientRegistrationCLI {
.create();
aeshConsole.start();
+
+
/*
if (args.length > 0) {
CommandContainer command = registry.getCommand(args[0], null);
diff --git a/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
index 1e57dbc..6ad9715 100755
--- a/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
@@ -29,7 +29,7 @@ public class CredentialRepresentation {
private Integer period;
// only used when updating a credential. Might set required action
- protected boolean temporary;
+ protected Boolean temporary;
public String getType() {
return type;
@@ -79,11 +79,11 @@ public class CredentialRepresentation {
this.hashIterations = hashIterations;
}
- public boolean isTemporary() {
+ public Boolean isTemporary() {
return temporary;
}
- public void setTemporary(boolean temporary) {
+ public void setTemporary(Boolean temporary) {
this.temporary = temporary;
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 00785cf..9b76490 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -84,7 +84,6 @@ public class RealmRepresentation {
private List<IdentityProviderRepresentation> identityProviders;
private List<IdentityProviderMapperRepresentation> identityProviderMappers;
private List<ProtocolMapperRepresentation> protocolMappers;
- private Boolean identityFederationEnabled;
protected Boolean internationalizationEnabled;
protected Set<String> supportedLocales;
protected String defaultLocale;
@@ -613,10 +612,6 @@ public class RealmRepresentation {
identityProviders.add(identityProviderRepresentation);
}
- public boolean isIdentityFederationEnabled() {
- return identityProviders != null && !identityProviders.isEmpty();
- }
-
public List<ProtocolMapperRepresentation> getProtocolMappers() {
return protocolMappers;
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
index 8635014..0990a4e 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
@@ -17,9 +17,9 @@ public class UserRepresentation {
protected String id;
protected Long createdTimestamp;
protected String username;
- protected boolean enabled;
- protected boolean totp;
- protected boolean emailVerified;
+ protected Boolean enabled;
+ protected Boolean totp;
+ protected Boolean emailVerified;
protected String firstName;
protected String lastName;
protected String email;
@@ -98,27 +98,27 @@ public class UserRepresentation {
this.username = username;
}
- public boolean isEnabled() {
+ public Boolean isEnabled() {
return enabled;
}
- public void setEnabled(boolean enabled) {
+ public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
- public boolean isTotp() {
+ public Boolean isTotp() {
return totp;
}
- public void setTotp(boolean totp) {
+ public void setTotp(Boolean totp) {
this.totp = totp;
}
- public boolean isEmailVerified() {
+ public Boolean isEmailVerified() {
return emailVerified;
}
- public void setEmailVerified(boolean emailVerified) {
+ public void setEmailVerified(Boolean emailVerified) {
this.emailVerified = emailVerified;
}
diff --git a/core/src/main/java/org/keycloak/util/JsonSerialization.java b/core/src/main/java/org/keycloak/util/JsonSerialization.java
index a1a93ba..19df33f 100755
--- a/core/src/main/java/org/keycloak/util/JsonSerialization.java
+++ b/core/src/main/java/org/keycloak/util/JsonSerialization.java
@@ -3,6 +3,7 @@ package org.keycloak.util;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.type.TypeReference;
import java.io.IOException;
import java.io.InputStream;
@@ -27,7 +28,10 @@ public class JsonSerialization {
public static void writeValueToStream(OutputStream os, Object obj) throws IOException {
mapper.writeValue(os, obj);
+ }
+ public static void writeValuePrettyToStream(OutputStream os, Object obj) throws IOException {
+ prettyMapper.writeValue(os, obj);
}
public static String writeValueAsPrettyString(Object obj) throws IOException {
@@ -53,6 +57,10 @@ public class JsonSerialization {
return readValue(bytes, type, false);
}
+ public static <T> T readValue(InputStream bytes, TypeReference<T> type) throws IOException {
+ return mapper.readValue(bytes, type);
+ }
+
public static <T> T readValue(InputStream bytes, Class<T> type, boolean replaceSystemProperties) throws IOException {
if (replaceSystemProperties) {
return sysPropertiesAwareMapper.readValue(bytes, type);
diff --git a/distribution/feature-packs/server-feature-pack/pom.xml b/distribution/feature-packs/server-feature-pack/pom.xml
index 0f5dd37..6f05056 100644
--- a/distribution/feature-packs/server-feature-pack/pom.xml
+++ b/distribution/feature-packs/server-feature-pack/pom.xml
@@ -38,17 +38,25 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adduser</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-extensions</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-wf9-server-subsystem</artifactId>
+ <artifactId>keycloak-wildfly-server-subsystem</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-feature-pack</artifactId>
<type>zip</type>
</dependency>
+ <dependency>
+ <groupId>org.jboss.aesh</groupId>
+ <artifactId>aesh</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.bat b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.bat
new file mode 100644
index 0000000..dca1136
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.bat
@@ -0,0 +1,73 @@
+@echo off
+rem -------------------------------------------------------------------------
+rem Add User script for Windows
+rem -------------------------------------------------------------------------
+rem
+rem A simple utility for adding new users to the properties file used
+rem for domain management authentication out of the box.
+
+rem $Id$
+
+@if not "%ECHO%" == "" echo %ECHO%
+@if "%OS%" == "Windows_NT" setlocal
+
+if "%OS%" == "Windows_NT" (
+ set "DIRNAME=%~dp0%"
+) else (
+ set DIRNAME=.\
+)
+
+pushd "%DIRNAME%.."
+set "RESOLVED_JBOSS_HOME=%CD%"
+popd
+
+if "x%JBOSS_HOME%" == "x" (
+ set "JBOSS_HOME=%RESOLVED_JBOSS_HOME%"
+)
+
+pushd "%JBOSS_HOME%"
+set "SANITIZED_JBOSS_HOME=%CD%"
+popd
+
+if /i "%RESOLVED_JBOSS_HOME%" NEQ "%SANITIZED_JBOSS_HOME%" (
+ echo.
+ echo WARNING: The JBOSS_HOME ^("%SANITIZED_JBOSS_HOME%"^) that this script uses points to a different installation than the one that this script resides in ^("%RESOLVED_JBOSS_HOME%"^). Unpredictable results may occur.
+ echo.
+ echo JBOSS_HOME: "%JBOSS_HOME%"
+ echo.
+)
+
+rem Setup JBoss specific properties
+if "x%JAVA_HOME%" == "x" (
+ set JAVA=java
+ echo JAVA_HOME is not set. Unexpected results may occur.
+ echo Set JAVA_HOME to the directory of your local JDK to avoid this message.
+) else (
+ set "JAVA=%JAVA_HOME%\bin\java"
+)
+
+rem Find jboss-modules.jar, or we can't continue
+if exist "%JBOSS_HOME%\jboss-modules.jar" (
+ set "RUNJAR=%JBOSS_HOME%\jboss-modules.jar"
+) else (
+ echo Could not locate "%JBOSS_HOME%\jboss-modules.jar".
+ echo Please check that you are in the bin directory when running this script.
+ goto END
+)
+
+rem Set default module root paths
+if "x%JBOSS_MODULEPATH%" == "x" (
+ set "JBOSS_MODULEPATH=%JBOSS_HOME%\modules"
+)
+
+rem Uncomment to override standalone and domain user location
+rem set "JAVA_OPTS=%JAVA_OPTS% -Djboss.server.config.user.dir=..\standalone\configuration -Djboss.domain.config.user.dir=..\domain\configuration"
+
+"%JAVA%" %JAVA_OPTS% ^
+ -jar "%JBOSS_HOME%\jboss-modules.jar" ^
+ -mp "%JBOSS_MODULEPATH%" ^
+ org.keycloak.keycloak-wildfly-adduser ^
+ %*
+
+:END
+if "x%NOPAUSE%" == "x" pause
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.sh b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.sh
new file mode 100755
index 0000000..1f6dfff
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# Add User Utility
+#
+# A simple utility for adding new users to the properties file used
+# for domain management authentication out of the box.
+#
+
+DIRNAME=`dirname "$0"`
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false;
+if [ `uname|grep -i CYGWIN` ]; then
+ cygwin=true;
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$JBOSS_HOME" ] &&
+ JBOSS_HOME=`cygpath --unix "$JBOSS_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$JAVAC_JAR" ] &&
+ JAVAC_JAR=`cygpath --unix "$JAVAC_JAR"`
+fi
+
+# Setup JBOSS_HOME
+RESOLVED_JBOSS_HOME=`cd "$DIRNAME/.."; pwd`
+if [ "x$JBOSS_HOME" = "x" ]; then
+ # get the full path (without any relative bits)
+ JBOSS_HOME=$RESOLVED_JBOSS_HOME
+else
+ SANITIZED_JBOSS_HOME=`cd "$JBOSS_HOME"; pwd`
+ if [ "$RESOLVED_JBOSS_HOME" != "$SANITIZED_JBOSS_HOME" ]; then
+ echo "WARNING: The JBOSS_HOME ($SANITIZED_JBOSS_HOME) that this script uses points to a different installation than the one that this script resides in ($RESOLVED_JBOSS_HOME). Unpredictable results may occur."
+ echo ""
+ fi
+fi
+export JBOSS_HOME
+
+# Setup the JVM
+if [ "x$JAVA" = "x" ]; then
+ if [ "x$JAVA_HOME" != "x" ]; then
+ JAVA="$JAVA_HOME/bin/java"
+ else
+ JAVA="java"
+ fi
+fi
+
+if [ "x$JBOSS_MODULEPATH" = "x" ]; then
+ JBOSS_MODULEPATH="$JBOSS_HOME/modules"
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ JBOSS_HOME=`cygpath --path --windows "$JBOSS_HOME"`
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ JBOSS_MODULEPATH=`cygpath --path --windows "$JBOSS_MODULEPATH"`
+fi
+
+# Sample JPDA settings for remote socket debugging
+#JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=y"
+# Uncomment to override standalone and domain user location
+#JAVA_OPTS="$JAVA_OPTS -Djboss.server.config.user.dir=../standalone/configuration -Djboss.domain.config.user.dir=../domain/configuration"
+
+JAVA_OPTS="$JAVA_OPTS"
+
+eval \"$JAVA\" $JAVA_OPTS \
+ -jar \""$JBOSS_HOME"/jboss-modules.jar\" \
+ -mp \""${JBOSS_MODULEPATH}"\" \
+ org.keycloak.keycloak-wildfly-adduser \
+ '"$@"'
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/aesh/0.65/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/aesh/0.65/module.xml
new file mode 100644
index 0000000..4166dbd
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/jboss/aesh/0.65/module.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.jboss.aesh" slot="0.65">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.jboss.aesh:aesh}"/>
+ </resources>
+
+ <dependencies>
+ <module name="org.fusesource.jansi" />
+ </dependencies>
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
index d6e7d81..8002aa2 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
@@ -29,6 +29,6 @@
</resources>
<dependencies>
- <module name="org.keycloak.keycloak-wf9-server-subsystem" services="export" export="true"/>
+ <module name="org.keycloak.keycloak-wildfly-server-subsystem" services="export" export="true"/>
</dependencies>
</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adduser/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adduser/main/module.xml
new file mode 100755
index 0000000..d27499b
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-wildfly-adduser/main/module.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-wildfly-adduser">
+ <main-class name="org.keycloak.wildfly.adduser.AddUser"/>
+ <resources>
+ <artifact name="${org.keycloak:keycloak-wildfly-adduser}"/>
+ </resources>
+ <dependencies>
+ <module name="org.keycloak.keycloak-common"/>
+ <module name="org.keycloak.keycloak-core"/>
+ <module name="org.keycloak.keycloak-model-api"/>
+ <module name="org.jboss.aesh" slot="0.65"/>
+ <module name="org.jboss.as.domain-management"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ </dependencies>
+</module>
diff --git a/distribution/server-overlay/eap6/eap6-server-modules/build.xml b/distribution/server-overlay/eap6/eap6-server-modules/build.xml
index 9f60836..e8086dc 100755
--- a/distribution/server-overlay/eap6/eap6-server-modules/build.xml
+++ b/distribution/server-overlay/eap6/eap6-server-modules/build.xml
@@ -274,8 +274,8 @@
<!-- subsystems -->
- <module-def name="org.keycloak.keycloak-as7-server-subsystem">
- <maven-resource group="org.keycloak" artifact="keycloak-as7-server-subsystem"/>
+ <module-def name="org.keycloak.keycloak-eap6-server-subsystem">
+ <maven-resource group="org.keycloak" artifact="keycloak-eap6-server-subsystem"/>
</module-def>
<module-def name="org.keycloak.keycloak-server-subsystem"/>
diff --git a/distribution/server-overlay/eap6/eap6-server-modules/pom.xml b/distribution/server-overlay/eap6/eap6-server-modules/pom.xml
index 91b2969..b3225fd 100755
--- a/distribution/server-overlay/eap6/eap6-server-modules/pom.xml
+++ b/distribution/server-overlay/eap6/eap6-server-modules/pom.xml
@@ -32,7 +32,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-as7-server-subsystem</artifactId>
+ <artifactId>keycloak-eap6-server-subsystem</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
diff --git a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml
index 90939b0..4829258 100755
--- a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml
+++ b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml
@@ -30,6 +30,6 @@
</resources>
<dependencies>
- <module name="org.keycloak.keycloak-as7-server-subsystem" services="export" export="true"/>
+ <module name="org.keycloak.keycloak-eap6-server-subsystem" services="export" export="true"/>
</dependencies>
</module>
diff --git a/docbook/auth-server-docs/reference/en/en-US/master.xml b/docbook/auth-server-docs/reference/en/en-US/master.xml
index 16a8601..d6bf5ff 100755
--- a/docbook/auth-server-docs/reference/en/en-US/master.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/master.xml
@@ -37,7 +37,6 @@
<!ENTITY UserFederation SYSTEM "modules/user-federation.xml">
<!ENTITY Kerberos SYSTEM "modules/kerberos.xml">
<!ENTITY ExportImport SYSTEM "modules/export-import.xml">
- <!ENTITY AdminRecovery SYSTEM "modules/admin-recovery.xml">
<!ENTITY ServerCache SYSTEM "modules/cache.xml">
<!ENTITY SecurityVulnerabilities SYSTEM "modules/security-vulnerabilities.xml">
<!ENTITY Clustering SYSTEM "modules/clustering.xml">
diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
index 78d9a4b..01ad7e6 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
@@ -128,6 +128,25 @@ cd <WILDFLY_HOME>/bin
</itemizedlist>
</para>
<section>
+ <title>Admin User</title>
+ <para>
+ To access the admin console you need an account to login. Currently, there's a default account added
+ with the username <literal>admin</literal> and password <literal>admin</literal>. You will be required
+ to change the password on first login. We are planning on removing the built-in account soon and will
+ instead have an initial step to create the user.
+ </para>
+ <para>
+ You can also create a user with the <literal>add-user</literal> script found in <literal>bin</literal>.
+ This script will create a temporary file with the details of the user, which are imported at startup.
+ To add a user with this script run:
+<programlisting><![CDATA[
+bin/add-user.[sh|bat] -r master -u <username> -p <password>
+]]></programlisting>
+ Then restart the server.
+ </para>
+ </section>
+
+ <section>
<title>Relational Database Configuration</title>
<para>
You might want to use a better relational database for Keycloak like PostgreSQL or MySQL. You might also
integration/as7-eap6/pom.xml 1(+0 -1)
diff --git a/integration/as7-eap6/pom.xml b/integration/as7-eap6/pom.xml
index e1bca6a..52a1053 100755
--- a/integration/as7-eap6/pom.xml
+++ b/integration/as7-eap6/pom.xml
@@ -17,6 +17,5 @@
<module>as7-adapter-spi</module>
<module>as7-adapter</module>
<module>as7-subsystem</module>
- <module>as7-server-subsystem</module>
</modules>
</project>
\ No newline at end of file
integration/wildfly/pom.xml 2(+0 -2)
diff --git a/integration/wildfly/pom.xml b/integration/wildfly/pom.xml
index 141cd87..3afdcc6 100644
--- a/integration/wildfly/pom.xml
+++ b/integration/wildfly/pom.xml
@@ -15,9 +15,7 @@
<modules>
<module>wildfly-adapter</module>
- <module>wildfly-extensions</module>
<module>wf8-subsystem</module>
<module>wf9-subsystem</module>
- <module>wf9-server-subsystem</module>
</modules>
</project>
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 3916fd1..dd82098 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -996,14 +996,14 @@ public class RepresentationToModel {
// Import users just to user storage. Don't federate
UserModel user = session.userStorage().addUser(newRealm, userRep.getId(), userRep.getUsername(), false, false);
- user.setEnabled(userRep.isEnabled());
+ user.setEnabled(userRep.isEnabled() != null && userRep.isEnabled());
user.setCreatedTimestamp(userRep.getCreatedTimestamp());
user.setEmail(userRep.getEmail());
- user.setEmailVerified(userRep.isEmailVerified());
+ if (userRep.isEmailVerified() != null) user.setEmailVerified(userRep.isEmailVerified());
user.setFirstName(userRep.getFirstName());
user.setLastName(userRep.getLastName());
user.setFederationLink(userRep.getFederationLink());
- user.setOtpEnabled(userRep.isTotp());
+ if (userRep.isTotp() != null) user.setOtpEnabled(userRep.isTotp());
if (userRep.getAttributes() != null) {
for (Map.Entry<String, Object> entry : userRep.getAttributes().entrySet()) {
Object value = entry.getValue();
pom.xml 12(+9 -3)
diff --git a/pom.xml b/pom.xml
index c137e59..62ae25c 100755
--- a/pom.xml
+++ b/pom.xml
@@ -76,7 +76,7 @@
<log4j.version>1.2.17</log4j.version>
<greenmail.version>1.3.1b</greenmail.version>
<xmlsec.version>1.5.1</xmlsec.version>
- <aesh.version>0.66</aesh.version>
+ <aesh.version>0.65.1</aesh.version>
<enforcer.plugin.version>1.4</enforcer.plugin.version>
<jboss.as.plugin.version>7.5.Final</jboss.as.plugin.version>
@@ -154,6 +154,7 @@
<module>timer</module>
<module>export-import</module>
<module>util</module>
+ <module>wildfly</module>
</modules>
<dependencyManagement>
@@ -827,7 +828,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-as7-server-subsystem</artifactId>
+ <artifactId>keycloak-eap6-server-subsystem</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@@ -842,7 +843,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-wf9-server-subsystem</artifactId>
+ <artifactId>keycloak-wildfly-server-subsystem</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@@ -947,6 +948,11 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adduser</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-extensions</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java b/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
index 89dc097..cedcbdd 100644
--- a/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
+++ b/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
@@ -60,7 +60,8 @@ public class ExportImportManager {
// Check if master realm was exported. If it's not, then it needs to be created before other realms are imported
if (!importProvider.isMasterRealmExported()) {
- new ApplianceBootstrap().bootstrap(sessionFactory, contextPath);
+ ApplianceBootstrap.setupDefaultRealm(sessionFactory, contextPath);
+ ApplianceBootstrap.setupDefaultUser(sessionFactory);
}
importProvider.importModel(sessionFactory, strategy);
@@ -69,7 +70,8 @@ public class ExportImportManager {
if (!realmName.equals(Config.getAdminRealm())) {
// Check if master realm exists. If it's not, then it needs to be created before other realm is imported
- new ApplianceBootstrap().bootstrap(sessionFactory, contextPath);
+ ApplianceBootstrap.setupDefaultRealm(sessionFactory, contextPath);
+ ApplianceBootstrap.setupDefaultUser(sessionFactory);
}
importProvider.importRealm(sessionFactory, realmName, strategy);
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 5178cec..0fa1b92 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -23,62 +23,71 @@ public class ApplianceBootstrap {
private static final Logger logger = Logger.getLogger(ApplianceBootstrap.class);
- public void bootstrap(KeycloakSessionFactory sessionFactory, String contextPath) {
+ public static boolean setupDefaultRealm(KeycloakSessionFactory sessionFactory, String contextPath) {
KeycloakSession session = sessionFactory.create();
session.getTransaction().begin();
try {
- bootstrap(session, contextPath);
+ String adminRealmName = Config.getAdminRealm();
+ if (session.realms().getRealm(adminRealmName) != null) {
+ return false;
+ }
+
+ logger.info("Initializing " + adminRealmName + " realm");
+
+ RealmManager manager = new RealmManager(session);
+ manager.setContextPath(contextPath);
+ RealmModel realm = manager.createRealm(adminRealmName, adminRealmName);
+ realm.setName(adminRealmName);
+ realm.setEnabled(true);
+ realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
+ realm.setSsoSessionIdleTimeout(1800);
+ realm.setAccessTokenLifespan(60);
+ realm.setSsoSessionMaxLifespan(36000);
+ realm.setOfflineSessionIdleTimeout(Constants.DEFAULT_OFFLINE_SESSION_IDLE_TIMEOUT);
+ realm.setAccessCodeLifespan(60);
+ realm.setAccessCodeLifespanUserAction(300);
+ realm.setAccessCodeLifespanLogin(1800);
+ realm.setSslRequired(SslRequired.EXTERNAL);
+ realm.setRegistrationAllowed(false);
+ realm.setRegistrationEmailAsUsername(false);
+ KeycloakModelUtils.generateRealmKeys(realm);
+
session.getTransaction().commit();
+ return true;
} finally {
session.close();
}
}
- public void bootstrap(KeycloakSession session, String contextPath) {
- String adminRealmName = Config.getAdminRealm();
- if (session.realms().getRealm(adminRealmName) != null) {
- return;
- }
-
- logger.info("Initializing " + adminRealmName + " realm");
-
- RealmManager manager = new RealmManager(session);
- manager.setContextPath(contextPath);
- RealmModel realm = manager.createRealm(adminRealmName, adminRealmName);
- realm.setName(adminRealmName);
- realm.setEnabled(true);
- realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
- realm.setSsoSessionIdleTimeout(1800);
- realm.setAccessTokenLifespan(60);
- realm.setSsoSessionMaxLifespan(36000);
- realm.setOfflineSessionIdleTimeout(Constants.DEFAULT_OFFLINE_SESSION_IDLE_TIMEOUT);
- realm.setAccessCodeLifespan(60);
- realm.setAccessCodeLifespanUserAction(300);
- realm.setAccessCodeLifespanLogin(1800);
- realm.setSslRequired(SslRequired.EXTERNAL);
- realm.setRegistrationAllowed(false);
- realm.setRegistrationEmailAsUsername(false);
- KeycloakModelUtils.generateRealmKeys(realm);
+ public static boolean setupDefaultUser(KeycloakSessionFactory sessionFactory) {
+ KeycloakSession session = sessionFactory.create();
+ session.getTransaction().begin();
- UserModel adminUser = session.users().addUser(realm, "admin");
- setupAdminUser(session, realm, adminUser, "admin");
- }
+ try {
+ RealmModel realm = session.realms().getRealm(Config.getAdminRealm());
+ if (session.users().getUserByUsername("admin", realm) == null) {
+ UserModel adminUser = session.users().addUser(realm, "admin");
- public static void setupAdminUser(KeycloakSession session, RealmModel realm, UserModel adminUser, String password) {
- adminUser.setEnabled(true);
- UserCredentialModel usrCredModel = new UserCredentialModel();
- usrCredModel.setType(UserCredentialModel.PASSWORD);
- usrCredModel.setValue(password);
- session.users().updateCredential(realm, adminUser, usrCredModel);
- adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+ adminUser.setEnabled(true);
+ UserCredentialModel usrCredModel = new UserCredentialModel();
+ usrCredModel.setType(UserCredentialModel.PASSWORD);
+ usrCredModel.setValue("admin");
+ session.users().updateCredential(realm, adminUser, usrCredModel);
+ adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
- RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
- adminUser.grantRole(adminRole);
+ RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
+ adminUser.grantRole(adminRole);
- ClientModel accountApp = realm.getClientNameMap().get(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
- for (String r : accountApp.getDefaultRoles()) {
- adminUser.grantRole(accountApp.getRole(r));
+ ClientModel accountApp = realm.getClientNameMap().get(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
+ for (String r : accountApp.getDefaultRoles()) {
+ adminUser.grantRole(accountApp.getRole(r));
+ }
+ }
+ session.getTransaction().commit();
+ return true;
+ } finally {
+ session.close();
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index a85c9d2..2028610 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -148,7 +148,7 @@ public class UsersResource {
attrsToRemove = Collections.emptySet();
}
- if (rep.isEnabled()) {
+ if (rep.isEnabled() != null && rep.isEnabled()) {
UsernameLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, rep.getUsername());
if (failureModel != null) {
failureModel.clearFailures();
@@ -219,9 +219,9 @@ public class UsersResource {
user.setFirstName(rep.getFirstName());
user.setLastName(rep.getLastName());
- user.setEnabled(rep.isEnabled());
- user.setOtpEnabled(rep.isTotp());
- user.setEmailVerified(rep.isEmailVerified());
+ if (rep.isEnabled() != null) user.setEnabled(rep.isEnabled());
+ if (rep.isTotp() != null) user.setOtpEnabled(rep.isTotp());
+ if (rep.isEmailVerified() != null) user.setEmailVerified(rep.isEmailVerified());
List<String> reqActions = rep.getRequiredActions();
@@ -708,7 +708,7 @@ public class UsersResource {
} catch (ModelReadOnlyException mre) {
throw new BadRequestException("Can't reset password as account is read only");
}
- if (pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+ if (pass.isTemporary() != null && pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index a07999d..125b6ee 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -2,6 +2,7 @@ package org.keycloak.services.resources;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
import org.jboss.logging.Logger;
import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
@@ -11,9 +12,11 @@ import org.keycloak.migration.MigrationModelManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
import org.keycloak.models.utils.PostMigrationEvent;
-import org.keycloak.offlineconfig.AdminRecovery;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.DefaultKeycloakSessionFactory;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.BruteForceProtector;
@@ -36,10 +39,7 @@ import javax.ws.rs.core.UriInfo;
import java.io.*;
import java.net.URI;
import java.net.URL;
-import java.util.HashSet;
-import java.util.Properties;
-import java.util.Set;
-import java.util.StringTokenizer;
+import java.util.*;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -81,7 +81,7 @@ public class KeycloakApplication extends Application {
singletons.add(new ObjectMapperResolver(Boolean.parseBoolean(System.getProperty("keycloak.jsonPrettyPrint", "false"))));
- setupDefaultRealm(context.getContextPath());
+ boolean defaultRealmCreated = ApplianceBootstrap.setupDefaultRealm(sessionFactory, context.getContextPath());
migrateModel();
sessionFactory.publish(new PostMigrationEvent());
@@ -89,7 +89,11 @@ public class KeycloakApplication extends Application {
new ExportImportManager().checkExportImport(this.sessionFactory, context.getContextPath());
importRealms(context);
- AdminRecovery.recover(sessionFactory);
+ importAddUser();
+
+ if (defaultRealmCreated) {
+ ApplianceBootstrap.setupDefaultUser(sessionFactory);
+ }
setupScheduledTasks(sessionFactory);
}
@@ -153,10 +157,6 @@ public class KeycloakApplication extends Application {
}
}
- protected void setupDefaultRealm(String contextPath) {
- new ApplianceBootstrap().bootstrap(sessionFactory, contextPath);
- }
-
public static KeycloakSessionFactory createSessionFactory() {
DefaultKeycloakSessionFactory factory = new DefaultKeycloakSessionFactory();
factory.init();
@@ -254,6 +254,44 @@ public class KeycloakApplication extends Application {
}
}
+ public void importAddUser() {
+ String configDir = System.getProperty("jboss.server.config.dir");
+ if (configDir != null) {
+ File addUserFile = new File(configDir + File.separator + "keycloak-add-user.json");
+ if (addUserFile.isFile()) {
+ log.info("Importing users from '" + addUserFile + "'");
+
+ KeycloakSession session = sessionFactory.create();
+ try {
+ session.getTransaction().begin();
+
+ List<RealmRepresentation> realms = JsonSerialization.readValue(new FileInputStream(addUserFile), new TypeReference<List<RealmRepresentation>>() {});
+ for (RealmRepresentation r : realms) {
+ RealmModel realm = session.realms().getRealmByName(r.getRealm());
+ if (realm == null) {
+ throw new Exception("Realm '" + r.getRealm() + "' not found");
+ }
+
+ for (UserRepresentation u : r.getUsers()) {
+ RepresentationToModel.createUser(session, realm, u, realm.getClientNameMap());
+ }
+ }
+
+ session.getTransaction().commit();
+
+ if (!addUserFile.delete()) {
+ log.error("Failed to delete '" + addUserFile + "'");
+ }
+ } catch (Throwable t) {
+ session.getTransaction().rollback();
+ log.error("Failed to import users from '" + addUserFile + "'", t);
+ } finally {
+ session.close();
+ }
+ }
+ }
+ }
+
private static <T> T loadJson(InputStream is, Class<T> type) {
try {
return JsonSerialization.readValue(is, type);
testsuite/integration/pom.xml 4(+4 -0)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index a14a006..2865040 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -32,6 +32,10 @@
<artifactId>keycloak-admin-client</artifactId>
</dependency>
<dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adduser</artifactId>
+ </dependency>
+ <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
new file mode 100644
index 0000000..c3f68db
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
@@ -0,0 +1,64 @@
+package org.keycloak.testsuite.adduser;
+
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.models.Constants;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.KeycloakServer;
+import org.keycloak.wildfly.adduser.AddUser;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AddUserTest {
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ private File dir;
+
+ @Before
+ public void before() throws IOException {
+ dir = folder.newFolder();
+ System.setProperty("jboss.server.config.user.dir", dir.getAbsolutePath());
+ System.setProperty("jboss.server.config.dir", dir.getAbsolutePath());
+ }
+
+ @After
+ public void after() {
+ System.getProperties().remove("jboss.server.config.user.dir");
+ System.getProperties().remove("jboss.server.config.dir");
+ }
+
+ @Test
+ public void addUserTest() throws Throwable {
+ AddUser.main(new String[]{"-u", "addusertest-admin", "-p", "password"});
+ Assert.assertEquals(1, dir.listFiles().length);
+
+ KeycloakServer server = new KeycloakServer();
+ try {
+ server.start();
+
+ Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "addusertest-admin", "password", Constants.ADMIN_CONSOLE_CLIENT_ID);
+ keycloak.realms().findAll();
+
+ RealmRepresentation testRealm = new RealmRepresentation();
+ testRealm.setEnabled(true);
+ testRealm.setId("test");
+ testRealm.setRealm("test");
+
+ keycloak.realms().create(testRealm);
+
+ keycloak.close();
+
+ Assert.assertEquals(0, dir.listFiles().length);
+ } finally {
+ server.stop();
+ }
+ }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
index 74df6c8..8fc4cd6 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
@@ -22,6 +22,8 @@
package org.keycloak.testsuite.rule;
import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java
index 85b32e6..e508e71 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/users/UserAttributesForm.java
@@ -130,8 +130,8 @@ public class UserAttributesForm extends Form {
setEmail(user.getEmail());
setFirstName(user.getFirstName());
setLastName(user.getLastName());
- setEnabled(user.isEnabled());
- setEmailVerified(user.isEmailVerified());
+ if (user.isEnabled() != null) setEnabled(user.isEnabled());
+ if (user.isEmailVerified() != null) setEmailVerified(user.isEmailVerified());
setRequiredActions(user.getRequiredActions());
}
wildfly/adduser/pom.xml 54(+54 -0)
diff --git a/wildfly/adduser/pom.xml b/wildfly/adduser/pom.xml
new file mode 100755
index 0000000..8a2bc8b
--- /dev/null
+++ b/wildfly/adduser/pom.xml
@@ -0,0 +1,54 @@
+<?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-wildfly-parent</artifactId>
+ <version>1.7.0.Final-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>keycloak-wildfly-adduser</artifactId>
+ <name>Keycloak WildFly Add User Script</name>
+ <description/>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.wildfly.core</groupId>
+ <artifactId>wildfly-domain-management</artifactId>
+ <version>${wildfly.core.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.aesh</groupId>
+ <artifactId>aesh</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
new file mode 100644
index 0000000..7be53c6
--- /dev/null
+++ b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
@@ -0,0 +1,292 @@
+package org.keycloak.wildfly.adduser;
+
+import org.codehaus.jackson.type.TypeReference;
+import org.jboss.aesh.cl.CommandDefinition;
+import org.jboss.aesh.cl.Option;
+import org.jboss.aesh.cl.parser.ParserGenerator;
+import org.jboss.aesh.console.command.Command;
+import org.jboss.aesh.console.command.CommandNotFoundException;
+import org.jboss.aesh.console.command.CommandResult;
+import org.jboss.aesh.console.command.container.CommandContainer;
+import org.jboss.aesh.console.command.invocation.CommandInvocation;
+import org.jboss.aesh.console.command.registry.AeshCommandRegistryBuilder;
+import org.jboss.aesh.console.command.registry.CommandRegistry;
+import org.keycloak.common.util.Base64;
+import org.keycloak.models.Constants;
+import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AddUser {
+
+ private static final String COMMAND_NAME = "add-user";
+ private static final int DEFAULT_HASH_ITERATIONS = 100000;
+
+ public static void main(String[] args) throws Exception {
+ AddUserCommand command = new AddUserCommand();
+ try {
+ ParserGenerator.parseAndPopulate(command, COMMAND_NAME, args);
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(1);
+ }
+
+ if (command.isContainer()) {
+ List<String> l = new LinkedList<>(Arrays.asList(args));
+ l.remove("--container");
+ args = l.toArray(new String[l.size()]);
+
+ org.jboss.as.domain.management.security.adduser.AddUser.main(args);
+ } else if (command.isHelp()) {
+ printHelp(command);
+ } else {
+ try {
+ checkRequired(command, "user");
+ checkRequired(command, "password");
+
+ File addUserFile = getAddUserFile(command);
+
+ createUser(addUserFile, command.getRealm(), command.getUser(), command.getPassword(), command.getRoles(), command.getIterations());
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(1);
+ }
+ }
+ }
+
+ private static File getAddUserFile(AddUserCommand command) throws Exception {
+ File configDir;
+ if (command.isDomain()) {
+ if (command.getDc() != null) {
+ configDir = new File(command.getDc());
+ } else if (System.getProperty("jboss.domain.config.user.dir") != null) {
+ configDir = new File(System.getProperty("jboss.domain.config.user.dir"));
+ } else if (System.getenv("JBOSS_HOME") != null) {
+ configDir = new File(System.getenv("JBOSS_HOME") + File.separator + "domain" + File.separator + "configuration");
+ } else {
+ throw new Exception("Could not find domain configuration directory");
+ }
+ } else {
+ if (command.getSc() != null) {
+ configDir = new File(command.getSc());
+ } else if (System.getProperty("jboss.server.config.user.dir") != null) {
+ configDir = new File(System.getProperty("jboss.server.config.user.dir"));
+ } else if (System.getenv("JBOSS_HOME") != null) {
+ configDir = new File(System.getenv("JBOSS_HOME") + File.separator + "standalone" + File.separator + "configuration");
+ } else {
+ throw new Exception("Could not find standalone configuration directory");
+ }
+ }
+
+ if (!configDir.isDirectory()) {
+ throw new Exception("'" + configDir + "' does not exist or is not a directory");
+ }
+
+ File addUserFile = new File(configDir, "keycloak-add-user.json");
+ return addUserFile;
+ }
+
+ private static void createUser(File addUserFile, String realmName, String userName, String password, String rolesString, int iterations) throws Exception {
+ List<RealmRepresentation> realms;
+ if (addUserFile.isFile()) {
+ realms = JsonSerialization.readValue(new FileInputStream(addUserFile), new TypeReference<List<RealmRepresentation>>() {});
+ } else {
+ realms = new LinkedList<>();
+ }
+
+ if (realmName == null) {
+ realmName = "master";
+ }
+
+ RealmRepresentation realm = null;
+ for (RealmRepresentation r : realms) {
+ if (r.getRealm().equals(realmName)) {
+ realm = r;
+ }
+ }
+
+ if (realm == null) {
+ realm = new RealmRepresentation();
+ realm.setRealm(realmName);
+ realms.add(realm);
+ realm.setUsers(new LinkedList<UserRepresentation>());
+ }
+
+ for (UserRepresentation u : realm.getUsers()) {
+ if (u.getUsername().equals(userName)) {
+ throw new Exception("User with username '" + userName + "' already added to '" + addUserFile + "'");
+ }
+ }
+
+ UserRepresentation user = new UserRepresentation();
+ user.setEnabled(true);
+ user.setUsername(userName);
+ user.setCredentials(new LinkedList<CredentialRepresentation>());
+
+ byte[] salt = Pbkdf2PasswordEncoder.getSalt();
+ iterations = iterations > 0 ? iterations : DEFAULT_HASH_ITERATIONS;
+
+ CredentialRepresentation credentials = new CredentialRepresentation();
+ credentials.setType(CredentialRepresentation.PASSWORD);
+ credentials.setHashIterations(iterations);
+ credentials.setSalt(Base64.encodeBytes(salt));
+ credentials.setHashedSaltedValue(new Pbkdf2PasswordEncoder(salt).encode(password, iterations));
+
+ user.getCredentials().add(credentials);
+
+ String[] roles;
+ if (rolesString != null) {
+ roles = rolesString.split(",");
+ } else {
+ if (realmName.equals("master")) {
+ roles = new String[] { "admin" };
+ } else {
+ roles = new String[] { "realm-management/realm-admin" };
+ }
+ }
+
+ for (String r : roles) {
+ if (r.indexOf('/') != -1) {
+ String[] cr = r.split("/");
+ String client = cr[0];
+ String clientRole = cr[1];
+
+ if (user.getClientRoles() == null) {
+ user.setClientRoles(new HashMap<String, List<String>>());
+ }
+
+ if (user.getClientRoles().get(client) == null) {
+ user.getClientRoles().put(client, new LinkedList<String>());
+ }
+
+ user.getClientRoles().get(client).add(clientRole);
+ } else {
+ if (user.getRealmRoles() == null) {
+ user.setRealmRoles(new LinkedList<String>());
+ }
+ user.getRealmRoles().add(r);
+ }
+ }
+
+ realm.getUsers().add(user);
+
+ JsonSerialization.writeValuePrettyToStream(new FileOutputStream(addUserFile), realms);
+ System.out.println("Added '" + userName + "' to '" + addUserFile + "', restart server to load user");
+ }
+
+ private static void checkRequired(Command command, String field) throws Exception {
+ Method m = command.getClass().getMethod("get" + Character.toUpperCase(field.charAt(0)) + field.substring(1));
+ if (m.invoke(command) == null) {
+ Option option = command.getClass().getDeclaredField(field).getAnnotation(Option.class);
+ String optionName;
+ if (option != null && option.shortName() != '\u0000') {
+ optionName = "-" + option.shortName() + ", --" + field;
+ } else {
+ optionName = "--" + field;
+ }
+ throw new Exception("Option: " + optionName + " is required");
+ }
+ }
+
+ private static void printHelp(Command command) throws CommandNotFoundException {
+ CommandRegistry registry = new AeshCommandRegistryBuilder().command(command).create();
+ CommandContainer commandContainer = registry.getCommand(command.getClass().getAnnotation(CommandDefinition.class).name(), null);
+ String help = commandContainer.printHelp(null);
+ System.out.println(help);
+ }
+
+ @CommandDefinition(name= COMMAND_NAME, description = "[options...]")
+ public static class AddUserCommand implements Command {
+
+ @Option(shortName = 'r', hasValue = true, description = "Name of realm to add user to")
+ private String realm;
+
+ @Option(shortName = 'u', hasValue = true, description = "Name of the user")
+ private String user;
+
+ @Option(shortName = 'p', hasValue = true, description = "Password of the user")
+ private String password;
+
+ @Option(hasValue = true, description = "Roles to add to the user")
+ private String roles;
+
+ @Option(hasValue = true, description = "Hash iterations")
+ private int iterations;
+
+ @Option(hasValue = false, description = "Enable domain mode")
+ private boolean domain;
+
+ @Option(hasValue = false, description = "Add user to underlying container. For usage use '--container --help'")
+ private boolean container;
+
+ @Option(hasValue = true, description = "Define the location of the server config directory")
+ private String sc;
+
+ @Option(hasValue = true, description = "Define the location of the domain config directory")
+ private String dc;
+
+ @Option(shortName = 'h', hasValue = false, description = "Display this help and exit")
+ private boolean help;
+
+ @Override
+ public CommandResult execute(CommandInvocation commandInvocation) throws IOException, InterruptedException {
+ return CommandResult.SUCCESS;
+ }
+
+ public String getRealm() {
+ return realm;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public String getRoles() {
+ return roles;
+ }
+
+ public int getIterations() {
+ return iterations;
+ }
+
+ public boolean isDomain() {
+ return domain;
+ }
+
+ public boolean isContainer() {
+ return container;
+ }
+
+ public String getSc() {
+ return sc;
+ }
+
+ public String getDc() {
+ return dc;
+ }
+
+ public boolean isHelp() {
+ return help;
+ }
+ }
+
+}
\ No newline at end of file
wildfly/pom.xml 22(+22 -0)
diff --git a/wildfly/pom.xml b/wildfly/pom.xml
new file mode 100755
index 0000000..0d24ee8
--- /dev/null
+++ b/wildfly/pom.xml
@@ -0,0 +1,22 @@
+<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.7.0.Final-SNAPSHOT</version>
+ </parent>
+
+ <name>Keycloak WildFly Integration</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-wildfly-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>adduser</module>
+ <module>extensions</module>
+ <module>server-subsystem</module>
+ <module>server-eap6-subsystem</module>
+ </modules>
+</project>