[jboss-as] - Simplified systemd files - Added jboss-as-cli module - Make it possible to run as different user i
Marek Goldmann
goldmann at fedoraproject.org
Mon Apr 16 19:33:55 UTC 2012
commit f7ed32ec9b95161422e09e3ad840d1e252d80f7c
Author: Marek Goldmann <mgoldman at redhat.com>
Date: Mon Apr 16 21:21:26 2012 +0200
- Simplified systemd files
- Added jboss-as-cli module
- Make it possible to run as different user in different direcotry by changing JBOSS_BASE_DIR
- Fixed issues with using add-user.sh script
- Changed validation API jar to bean-validation
- Added jboss-as-cp script to be able to use JBoss AS from different dir as different user
- Removed activation AS7 module - it's already in JDK
- Make it possible to add a user also when JBoss AS is run from different directory
0045-Added-jboss-as-cli-module.patch | 135 ++
...OME-when-jboss-cli.sh-is-executed-through.patch | 31 +
0047-Simplified-systemd-files.patch | 121 +
...OSS_BASE_DIR-is-checked-in-standalone.sh-.patch | 33 +
0049-Added-domain-add-user-module.patch | 34 +
...s-from-systemd-service-we-don-t-need-dupl.patch | 121 +
...-systemd-config-file-location-we-want-to-.patch | 30 +
0052-Remove-activation-module.patch | 241 ++
0053-Use-properties-in-add-user-AS7-module.patch | 2539 ++++++++++++++++++++
jboss-as-cp.sh | 59 +
jboss-as.spec | 111 +-
11 files changed, 3424 insertions(+), 31 deletions(-)
---
diff --git a/0045-Added-jboss-as-cli-module.patch b/0045-Added-jboss-as-cli-module.patch
new file mode 100644
index 0000000..743e744
--- /dev/null
+++ b/0045-Added-jboss-as-cli-module.patch
@@ -0,0 +1,135 @@
+From 43fbef5e2027b413c956326582a297da57a8bed1 Mon Sep 17 00:00:00 2001
+From: Patryk Obara <dreamer.tan at gmail.com>
+Date: Thu, 5 Apr 2012 12:54:16 +0200
+Subject: [PATCH 45/47] Added-jboss-as-cli-module
+
+With jline as dependency.
+---
+ build/build.xml | 16 ++++++++--------
+ build/pom.xml | 20 ++++++++++----------
+ pom.xml | 2 +-
+ 3 files changed, 19 insertions(+), 19 deletions(-)
+
+diff --git a/build/build.xml b/build/build.xml
+index 529af0e..04c2e76 100644
+--- a/build/build.xml
++++ b/build/build.xml
+@@ -145,6 +145,10 @@
+ <maven-resource group="org.hibernate.javax.persistence" artifact="hibernate-jpa-2.0-api"/>
+ </module-def>
+
++ <module-def name="jline">
++ <maven-resource group="jline" artifact="jline"/>
++ </module-def>
++
+ <module-def name="org.infinispan">
+ <maven-resource group="org.infinispan" artifact="infinispan-core"/>
+ </module-def>
+@@ -299,6 +303,10 @@
+ <maven-resource group="org.jboss.ironjacamar" artifact="ironjacamar-jdbc"/>
+ </module-def>
+
++ <module-def name="org.jboss.as.cli">
++ <maven-resource group="org.jboss.as" artifact="jboss-as-cli"/>
++ </module-def>
++
+ <module-def name="org.jboss.as.clustering.api">
+ <maven-resource group="org.jboss.as" artifact="jboss-as-clustering-api"/>
+ </module-def>
+@@ -719,10 +727,6 @@
+ <maven-resource group="org.jboss.spec.javax.xml.ws" artifact="jboss-jaxws-api_2.2_spec"/>
+ </module-def>
+
+- <module-def name="jline">
+- <maven-resource group="jline" artifact="jline"/>
+- </module-def>
+-
+ <module-def name="net.sourceforge.cssparser">
+ <maven-resource group="net.sourceforge.cssparser" artifact="cssparser"/>
+ </module-def>
+@@ -898,10 +902,6 @@
+ <maven-resource-with-classifier group="org.jboss.as" artifact="jboss-as-console" classifier="resources"/>
+ </module-def>
+
+- <module-def name="org.jboss.as.cli">
+- <maven-resource group="org.jboss.as" artifact="jboss-as-cli"/>
+- </module-def>
+-
+ <module-def name="org.jboss.as.configadmin">
+ <maven-resource group="org.jboss.as" artifact="jboss-as-configadmin"/>
+ </module-def>
+diff --git a/build/pom.xml b/build/pom.xml
+index 499f542..bd882b7 100644
+--- a/build/pom.xml
++++ b/build/pom.xml
+@@ -180,6 +180,11 @@
+
+ <dependency>
+ <groupId>org.jboss.as</groupId>
++ <artifactId>jboss-as-cli</artifactId>
++ </dependency>
++
++ <dependency>
++ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-clustering-common</artifactId>
+ </dependency>
+
+@@ -589,6 +594,11 @@
+ </dependency>
+
+ <dependency>
++ <groupId>jline</groupId>
++ <artifactId>jline</artifactId>
++ </dependency>
++
++ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </dependency>
+@@ -745,11 +755,6 @@
+ </dependency>
+
+ <dependency>
+- <groupId>jline</groupId>
+- <artifactId>jline</artifactId>
+- </dependency>
+-
+- <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+@@ -1066,11 +1071,6 @@
+
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+- <artifactId>jboss-as-cli</artifactId>
+- </dependency>
+-
+- <dependency>
+- <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-client-all</artifactId>
+ <scope>provided</scope>
+ </dependency>
+diff --git a/pom.xml b/pom.xml
+index b9e503d..13ba795 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -265,6 +265,7 @@
+ <modules>
+ <module>build</module>
+ <module>build-config</module>
++ <module>cli</module>
+ <module>clustering</module>
+ <module>connector</module>
+ <module>controller</module>
+@@ -5921,7 +5922,6 @@
+ <module>build</module>
+ <module>build-config</module>
+ <module>arquillian</module>
+- <module>cli</module>
+ <module>client/ejb</module>
+ <module>client/jms</module>
+ <module>client/shade</module>
+--
+1.7.10
+
diff --git a/0046-Fix-JBOSS_HOME-when-jboss-cli.sh-is-executed-through.patch b/0046-Fix-JBOSS_HOME-when-jboss-cli.sh-is-executed-through.patch
new file mode 100644
index 0000000..3df4780
--- /dev/null
+++ b/0046-Fix-JBOSS_HOME-when-jboss-cli.sh-is-executed-through.patch
@@ -0,0 +1,31 @@
+From 65d80242031d8541935b9c924cc024357b5348fc Mon Sep 17 00:00:00 2001
+From: Patryk Obara <dreamer.tan at gmail.com>
+Date: Thu, 5 Apr 2012 18:42:05 +0200
+Subject: [PATCH 46/47] Fix JBOSS_HOME when jboss-cli.sh is executed through
+ symbolic link
+
+---
+ build/src/main/resources/bin/jboss-cli.sh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/build/src/main/resources/bin/jboss-cli.sh b/build/src/main/resources/bin/jboss-cli.sh
+index a9d1c5d..a1108f5 100755
+--- a/build/src/main/resources/bin/jboss-cli.sh
++++ b/build/src/main/resources/bin/jboss-cli.sh
+@@ -1,6 +1,12 @@
+ #!/bin/sh
+
+-DIRNAME=`dirname "$0"`
++# Set proper dirname if script is executed through symlink
++LINK=`readlink "$0"`
++if [ "x$LINK" = "x" ]; then
++ DIRNAME=`dirname "$0"`
++else
++ DIRNAME=`dirname "$LINK"`
++fi
+
+ # OS specific support (must be 'true' or 'false').
+ cygwin=false;
+--
+1.7.10
+
diff --git a/0047-Simplified-systemd-files.patch b/0047-Simplified-systemd-files.patch
new file mode 100644
index 0000000..695944e
--- /dev/null
+++ b/0047-Simplified-systemd-files.patch
@@ -0,0 +1,121 @@
+From 7cb54243b2b040a9da681762919741f4fdd3314a Mon Sep 17 00:00:00 2001
+From: Marek Goldmann <mgoldman at redhat.com>
+Date: Thu, 12 Apr 2012 13:28:41 +0200
+Subject: [PATCH 47/47] Simplified systemd files
+
+---
+ .../main/resources/bin/initscripts/jboss-as.conf | 22 --------------------
+ .../bin/initscripts/systemd/jboss-as.conf | 4 ++++
+ .../bin/initscripts/systemd/jboss-as.service | 9 +++++---
+ .../resources/bin/initscripts/sysv/jboss-as.conf | 22 ++++++++++++++++++++
+ build/src/main/resources/bin/standalone.sh | 4 ++++
+ 5 files changed, 36 insertions(+), 25 deletions(-)
+ delete mode 100644 build/src/main/resources/bin/initscripts/jboss-as.conf
+ create mode 100644 build/src/main/resources/bin/initscripts/systemd/jboss-as.conf
+ create mode 100644 build/src/main/resources/bin/initscripts/sysv/jboss-as.conf
+
+diff --git a/build/src/main/resources/bin/initscripts/jboss-as.conf b/build/src/main/resources/bin/initscripts/jboss-as.conf
+deleted file mode 100644
+index cbe4aa7..0000000
+--- a/build/src/main/resources/bin/initscripts/jboss-as.conf
++++ /dev/null
+@@ -1,22 +0,0 @@
+-# General configuration for the init.d scripts,
+-# not necessarily for JBoss AS itself.
+-
+-# The username who should own the process.
+-#
+-JBOSS_USER=jboss-as
+-
+-# The amount of time to wait for startup
+-#
+-# STARTUP_WAIT=30
+-
+-# The amount of time to wait for shutdown
+-#
+-# SHUTDOWN_WAIT=30
+-
+-# Location to keep the console log
+-#
+-# JBOSS_CONSOLE_LOG=/var/log/jboss-as/console.log
+-
+-# The configuration you want to run
+-#
+-JBOSS_CONFIG=standalone-web.xml
+diff --git a/build/src/main/resources/bin/initscripts/systemd/jboss-as.conf b/build/src/main/resources/bin/initscripts/systemd/jboss-as.conf
+new file mode 100644
+index 0000000..82699ad
+--- /dev/null
++++ b/build/src/main/resources/bin/initscripts/systemd/jboss-as.conf
+@@ -0,0 +1,4 @@
++# The configuration you want to run
++#
++JBOSS_CONFIG=standalone-web.xml
++
+diff --git a/build/src/main/resources/bin/initscripts/systemd/jboss-as.service b/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
+index b7a4a56..1542968 100644
+--- a/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
++++ b/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
+@@ -3,10 +3,13 @@ Description=The JBoss Application Server
+ After=syslog.target network.target
+
+ [Service]
+-Type=forking
++Environment=LAUNCH_JBOSS_IN_BACKGROUND=1
++EnvironmentFile=-/etc/jboss-as.conf
++User=jboss-as
++LimitNOFILE=102642
+ PIDFile=/var/run/jboss-as/jboss-as.pid
+-ExecStart=/usr/bin/jboss-as $OPTIONS start
+-ExecStop=/usr/bin/jboss-as stop
++ExecStart=/usr/share/jboss-as/bin/standalone.sh -c $JBOSS_CONFIG
+
+ [Install]
+ WantedBy=multi-user.target
++
+diff --git a/build/src/main/resources/bin/initscripts/sysv/jboss-as.conf b/build/src/main/resources/bin/initscripts/sysv/jboss-as.conf
+new file mode 100644
+index 0000000..d999aca
+--- /dev/null
++++ b/build/src/main/resources/bin/initscripts/sysv/jboss-as.conf
+@@ -0,0 +1,22 @@
++# General configuration for the init.d scripts,
++# not necessarily for JBoss AS itself.
++
++# The username who should own the process.
++#
++# JBOSS_USER=jboss-as
++
++# The amount of time to wait for startup
++#
++# STARTUP_WAIT=30
++
++# The amount of time to wait for shutdown
++#
++# SHUTDOWN_WAIT=30
++
++# Location to keep the console log
++#
++# JBOSS_CONSOLE_LOG=/var/log/jboss-as/console.log
++
++# The configuration you want to run
++#
++# JBOSS_CONFIG=standalone.xml
+diff --git a/build/src/main/resources/bin/standalone.sh b/build/src/main/resources/bin/standalone.sh
+index d7387f9..1e02120 100755
+--- a/build/src/main/resources/bin/standalone.sh
++++ b/build/src/main/resources/bin/standalone.sh
+@@ -147,6 +147,10 @@ fi
+ if [ "x$JBOSS_CONFIG_DIR" = "x" ]; then
+ JBOSS_CONFIG_DIR="$JBOSS_BASE_DIR/configuration"
+ fi
++# determine the default pid file location dir, if not set
++if [ "x$JBOSS_PIDFILE" = "x" ]; then
++ JBOSS_PIDFILE="/var/run/jboss-as/jboss-as.pid"
++fi
+
+ # For Cygwin, switch paths to Windows format before running java
+ if $cygwin; then
+--
+1.7.10
+
diff --git a/0048-AS7-3800-JBOSS_BASE_DIR-is-checked-in-standalone.sh-.patch b/0048-AS7-3800-JBOSS_BASE_DIR-is-checked-in-standalone.sh-.patch
new file mode 100644
index 0000000..2c98c6f
--- /dev/null
+++ b/0048-AS7-3800-JBOSS_BASE_DIR-is-checked-in-standalone.sh-.patch
@@ -0,0 +1,33 @@
+From d5a79ab1f7506a8e43c231b5c15447b468e4a3b7 Mon Sep 17 00:00:00 2001
+From: Marek Goldmann <mgoldman at redhat.com>
+Date: Thu, 5 Apr 2012 16:10:47 +0200
+Subject: [PATCH 48/48] [AS7-3800] JBOSS_BASE_DIR is checked in standalone.sh
+ but not used to set -Djboss.server.base.dir
+
+---
+ build/src/main/resources/bin/standalone.sh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/build/src/main/resources/bin/standalone.sh b/build/src/main/resources/bin/standalone.sh
+index 1e02120..7aee924 100755
+--- a/build/src/main/resources/bin/standalone.sh
++++ b/build/src/main/resources/bin/standalone.sh
+@@ -186,6 +186,7 @@ while true; do
+ -jaxpmodule "javax.xml.jaxp-provider" \
+ org.jboss.as.standalone \
+ -Djboss.home.dir=\"$JBOSS_HOME\" \
++ -Djboss.server.base.dir=\"$JBOSS_BASE_DIR\" \
+ "$@"
+ JBOSS_STATUS=$?
+ else
+@@ -198,6 +199,7 @@ while true; do
+ -jaxpmodule "javax.xml.jaxp-provider" \
+ org.jboss.as.standalone \
+ -Djboss.home.dir=\"$JBOSS_HOME\" \
++ -Djboss.server.base.dir=\"$JBOSS_BASE_DIR\" \
+ "$@" "&"
+ JBOSS_PID=$!
+ # Trap common signals and relay them to the jboss process
+--
+1.7.10
+
diff --git a/0049-Added-domain-add-user-module.patch b/0049-Added-domain-add-user-module.patch
new file mode 100644
index 0000000..70e4c8d
--- /dev/null
+++ b/0049-Added-domain-add-user-module.patch
@@ -0,0 +1,34 @@
+From be152c72271132cc0614e291b4c822b3c6593e6f Mon Sep 17 00:00:00 2001
+From: Marek Goldmann <mgoldman at redhat.com>
+Date: Fri, 13 Apr 2012 13:38:24 +0200
+Subject: [PATCH 49/49] Added domain-add-user module
+
+---
+ build/build.xml | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/build/build.xml b/build/build.xml
+index 04c2e76..636e2b5 100644
+--- a/build/build.xml
++++ b/build/build.xml
+@@ -371,6 +371,8 @@
+ <maven-resource group="org.jboss.as" artifact="jboss-as-deployment-scanner"/>
+ </module-def>
+
++ <module-def name="org.jboss.as.domain-add-user" />
++
+ <module-def name="org.jboss.as.domain-http-error-context">
+ <maven-resource group="org.jboss.as" artifact="jboss-as-domain-http-error-context"/>
+ </module-def>
+@@ -910,8 +912,6 @@
+ <maven-resource group="org.jboss.as" artifact="jboss-as-cmp"/>
+ </module-def>
+
+- <module-def name="org.jboss.as.domain-add-user" />
+-
+ <module-def name="org.jboss.as.host-controller">
+ <maven-resource group="org.jboss.as" artifact="jboss-as-host-controller"/>
+ </module-def>
+--
+1.7.10
+
diff --git a/0050-Discard-logs-from-systemd-service-we-don-t-need-dupl.patch b/0050-Discard-logs-from-systemd-service-we-don-t-need-dupl.patch
new file mode 100644
index 0000000..48c32f9
--- /dev/null
+++ b/0050-Discard-logs-from-systemd-service-we-don-t-need-dupl.patch
@@ -0,0 +1,121 @@
+From 54fd06a9919fd5bd40a6a5ebc7cf212edffc90d2 Mon Sep 17 00:00:00 2001
+From: Marek Goldmann <mgoldman at redhat.com>
+Date: Fri, 13 Apr 2012 16:37:06 +0200
+Subject: [PATCH 50/50] Discard logs from systemd service, we don't need
+ duplication
+
+---
+ .../bin/initscripts/systemd/jboss-as.service | 1 +
+ .../resources/bin/initscripts/systemd/jboss-as.sh | 88 --------------------
+ 2 files changed, 1 insertion(+), 88 deletions(-)
+ delete mode 100755 build/src/main/resources/bin/initscripts/systemd/jboss-as.sh
+
+diff --git a/build/src/main/resources/bin/initscripts/systemd/jboss-as.service b/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
+index 1542968..41e54e6 100644
+--- a/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
++++ b/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
+@@ -9,6 +9,7 @@ User=jboss-as
+ LimitNOFILE=102642
+ PIDFile=/var/run/jboss-as/jboss-as.pid
+ ExecStart=/usr/share/jboss-as/bin/standalone.sh -c $JBOSS_CONFIG
++StandardOutput=null
+
+ [Install]
+ WantedBy=multi-user.target
+diff --git a/build/src/main/resources/bin/initscripts/systemd/jboss-as.sh b/build/src/main/resources/bin/initscripts/systemd/jboss-as.sh
+deleted file mode 100755
+index da57af6..0000000
+--- a/build/src/main/resources/bin/initscripts/systemd/jboss-as.sh
++++ /dev/null
+@@ -1,88 +0,0 @@
+-#!/bin/sh
+-
+-# Load Java configuration.
+-[ -r /etc/java/java.conf ] && . /etc/java/java.conf
+-
+-export JAVA_HOME
+-
+-# Load JBoss AS configuration.
+-if [ -z "$JBOSS_CONF" ]; then
+- JBOSS_CONF="/etc/sysconfig/jboss-as"
+-fi
+-
+-[ -r "$JBOSS_CONF" ] && . "${JBOSS_CONF}"
+-
+-if [ -z "$JBOSS_HOME" ]; then
+- JBOSS_HOME=/usr/share/jboss-as
+-fi
+-
+-export JBOSS_HOME
+-
+-if [ -z "$JBOSS_PIDFILE" ]; then
+- JBOSS_PIDFILE=/var/run/jboss-as/jboss-as.pid
+-fi
+-
+-if [ -z "$JBOSS_CONSOLE_LOG" ]; then
+- JBOSS_CONSOLE_LOG=/var/log/jboss-as/console.log
+-fi
+-
+-if [ -z "$JBOSS_CONFIG" ]; then
+- JBOSS_CONFIG=standalone.xml
+-fi
+-
+-if [ -z "$JBOSS_SCRIPT" ]; then
+- JBOSS_SCRIPT=$JBOSS_HOME/bin/standalone.sh
+-fi
+-
+-# For SELinux we need to use 'runuser' not 'su'
+-if [ -x "/sbin/runuser" ]; then
+- SU="/sbin/runuser -s /bin/sh"
+-else
+- SU="/bin/su -s /bin/sh"
+-fi
+-
+-start() {
+- if [ -f $JBOSS_PIDFILE ]; then
+- read ppid < $JBOSS_PIDFILE
+- if [ `ps --pid $ppid 2> /dev/null | grep -c $ppid 2> /dev/null` -eq '1' ]; then
+- failure
+- echo
+- return 1
+- else
+- rm -f $JBOSS_PIDFILE
+- fi
+- fi
+- mkdir -p $(dirname $JBOSS_CONSOLE_LOG)
+- cat /dev/null > $JBOSS_CONSOLE_LOG
+-
+- mkdir -p $(dirname $JBOSS_PIDFILE)
+- chown $JBOSS_USER $(dirname $JBOSS_PIDFILE) || true
+-
+- $SU - $JBOSS_USER -c "LAUNCH_JBOSS_IN_BACKGROUND=1 JBOSS_PIDFILE=$JBOSS_PIDFILE $JBOSS_SCRIPT -c $JBOSS_CONFIG" 2>&1 > $JBOSS_CONSOLE_LOG &
+-}
+-
+-stop() {
+- if [ -f $JBOSS_PIDFILE ]; then
+- read kpid < $JBOSS_PIDFILE
+- kill -15 $kpid
+- rm -f $JBOSS_PIDFILE
+- fi
+-}
+-
+-case "$1" in
+- start)
+- start
+- ;;
+- stop)
+- stop
+- ;;
+- restart)
+- $0 stop
+- $0 start
+- ;;
+- *)
+- echo "Usage: $0 {start|stop|restart}"
+- exit 1
+- ;;
+-esac
+-
+--
+1.7.10
+
diff --git a/0051-Changed-the-systemd-config-file-location-we-want-to-.patch b/0051-Changed-the-systemd-config-file-location-we-want-to-.patch
new file mode 100644
index 0000000..36f798b
--- /dev/null
+++ b/0051-Changed-the-systemd-config-file-location-we-want-to-.patch
@@ -0,0 +1,30 @@
+From e098d57c28c63922e1f6a78c741f2a8cea5cd86a Mon Sep 17 00:00:00 2001
+From: Marek Goldmann <mgoldman at redhat.com>
+Date: Mon, 16 Apr 2012 15:39:32 +0200
+Subject: [PATCH 51/51] Changed the systemd config file location + we want to
+ start JBoss AS before httpd
+
+---
+ build/src/main/resources/bin/initscripts/systemd/jboss-as.service | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/build/src/main/resources/bin/initscripts/systemd/jboss-as.service b/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
+index 41e54e6..32c1c10 100644
+--- a/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
++++ b/build/src/main/resources/bin/initscripts/systemd/jboss-as.service
+@@ -1,10 +1,11 @@
+ [Unit]
+ Description=The JBoss Application Server
+ After=syslog.target network.target
++Before=httpd.service
+
+ [Service]
+ Environment=LAUNCH_JBOSS_IN_BACKGROUND=1
+-EnvironmentFile=-/etc/jboss-as.conf
++EnvironmentFile=-/etc/jboss-as/jboss-as.conf
+ User=jboss-as
+ LimitNOFILE=102642
+ PIDFile=/var/run/jboss-as/jboss-as.pid
+--
+1.7.10
+
diff --git a/0052-Remove-activation-module.patch b/0052-Remove-activation-module.patch
new file mode 100644
index 0000000..4a407f9
--- /dev/null
+++ b/0052-Remove-activation-module.patch
@@ -0,0 +1,241 @@
+From ab566f0fdf0ecbba2435e1e981a6df53eca6c8c2 Mon Sep 17 00:00:00 2001
+From: Marek Goldmann <mgoldman at redhat.com>
+Date: Mon, 16 Apr 2012 17:45:12 +0200
+Subject: [PATCH 52/52] Remove activation module
+
+---
+ build/build.xml | 4 --
+ build/pom.xml | 5 ---
+ build/src/license/licenses.xml | 16 --------
+ .../resources/modules/javaee/api/main/module.xml | 1 -
+ .../modules/javax/activation/api/main/module.xml | 39 --------------------
+ .../resources/modules/javax/api/main/module.xml | 1 +
+ .../modules/javax/mail/api/main/module.xml | 1 -
+ .../modules/javax/xml/bind/api/main/module.xml | 1 -
+ .../modules/javax/xml/registry/api/main/module.xml | 2 +-
+ .../codehaus/jackson/jackson-xc/main/module.xml | 3 +-
+ .../jboss/resteasy/resteasy-jaxrs/main/module.xml | 1 -
+ pom.xml | 7 ----
+ 12 files changed, 3 insertions(+), 78 deletions(-)
+ delete mode 100644 build/src/main/resources/modules/javax/activation/api/main/module.xml
+
+diff --git a/build/build.xml b/build/build.xml
+index 636e2b5..77fc784 100644
+--- a/build/build.xml
++++ b/build/build.xml
+@@ -699,10 +699,6 @@
+ <maven-resource group="gnu-getopt" artifact="getopt" />
+ </module-def>
+
+- <module-def name="javax.activation.api">
+- <maven-resource group="javax.activation" artifact="activation"/>
+- </module-def>
+-
+ <module-def name="javax.faces.api" slot="1.2">
+ <maven-resource group="javax.faces" artifact="jsf-api"/>
+ </module-def>
+diff --git a/build/pom.xml b/build/pom.xml
+index bd882b7..365d2fc 100644
+--- a/build/pom.xml
++++ b/build/pom.xml
+@@ -720,11 +720,6 @@
+ -->
+
+ <dependency>
+- <groupId>javax.activation</groupId>
+- <artifactId>activation</artifactId>
+- </dependency>
+-
+- <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ </dependency>
+diff --git a/build/src/license/licenses.xml b/build/src/license/licenses.xml
+index 3e5dbc2..dc4ea97 100644
+--- a/build/src/license/licenses.xml
++++ b/build/src/license/licenses.xml
+@@ -241,22 +241,6 @@
+ </licenses>
+ </dependency>
+ <dependency>
+- <groupId>javax.activation</groupId>
+- <artifactId>activation</artifactId>
+- <licenses>
+- <license>
+- <name>Common Development and Distribution License</name>
+- <url>http://repository.jboss.org/licenses/cddl.txt</url>
+- <distribution>repo</distribution>
+- </license>
+- <license>
+- <name>GNU General Public License, Version 2 with the Classpath Exception</name>
+- <url>http://repository.jboss.org/licenses/gpl-2.0-ce.txt</url>
+- <distribution>repo</distribution>
+- </license>
+- </licenses>
+- </dependency>
+- <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ <licenses>
+diff --git a/build/src/main/resources/modules/javaee/api/main/module.xml b/build/src/main/resources/modules/javaee/api/main/module.xml
+index 40c62e4..fb439ce 100644
+--- a/build/src/main/resources/modules/javaee/api/main/module.xml
++++ b/build/src/main/resources/modules/javaee/api/main/module.xml
+@@ -28,7 +28,6 @@
+ </resources>
+
+ <dependencies>
+- <!-- <module name="javax.activation.api" export="true"/> is in JDK -->
+ <module name="javax.annotation.api" export="true"/>
+ <module name="javax.ejb.api" export="true"/>
+ <module name="javax.el.api" export="true"/>
+diff --git a/build/src/main/resources/modules/javax/activation/api/main/module.xml b/build/src/main/resources/modules/javax/activation/api/main/module.xml
+deleted file mode 100644
+index 7b73e1f..0000000
+--- a/build/src/main/resources/modules/javax/activation/api/main/module.xml
++++ /dev/null
+@@ -1,39 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-
+-<!--
+- ~ JBoss, Home of Professional Open Source.
+- ~ Copyright 2010, Red Hat, Inc., and individual contributors
+- ~ as indicated by the @author tags. See the copyright.txt file in the
+- ~ distribution for a full listing of individual contributors.
+- ~
+- ~ This is free software; you can redistribute it and/or modify it
+- ~ under the terms of the GNU Lesser General Public License as
+- ~ published by the Free Software Foundation; either version 2.1 of
+- ~ the License, or (at your option) any later version.
+- ~
+- ~ This software is distributed in the hope that it will be useful,
+- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- ~ Lesser General Public License for more details.
+- ~
+- ~ You should have received a copy of the GNU Lesser General Public
+- ~ License along with this software; if not, write to the Free
+- ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+- ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+- -->
+-
+-<module xmlns="urn:jboss:module:1.1" name="javax.activation.api">
+- <dependencies>
+- <module name="javax.api" />
+- <module name="javax.mail.api">
+- <imports><include path="META-INF"/></imports>
+- </module>
+- <module name="com.sun.xml.messaging.saaj"/>
+- <module name="org.jboss.ws.native.jbossws-native-core"/>
+- <module name="org.apache.cxf" optional="true"/>
+- </dependencies>
+-
+- <resources>
+- <!-- Insert resources here -->
+- </resources>
+-</module>
+diff --git a/build/src/main/resources/modules/javax/api/main/module.xml b/build/src/main/resources/modules/javax/api/main/module.xml
+index 5470de4..3206521 100644
+--- a/build/src/main/resources/modules/javax/api/main/module.xml
++++ b/build/src/main/resources/modules/javax/api/main/module.xml
+@@ -27,6 +27,7 @@
+ <paths>
+ <path name="javax/accessibility"/>
+ <path name="javax/activity"/>
++ <path name="javax/activation"/>
+ <path name="javax/crypto"/>
+ <path name="javax/crypto/interfaces"/>
+ <path name="javax/crypto/spec"/>
+diff --git a/build/src/main/resources/modules/javax/mail/api/main/module.xml b/build/src/main/resources/modules/javax/mail/api/main/module.xml
+index 1b60ac1..59b2f5a 100644
+--- a/build/src/main/resources/modules/javax/mail/api/main/module.xml
++++ b/build/src/main/resources/modules/javax/mail/api/main/module.xml
+@@ -24,7 +24,6 @@
+
+ <module xmlns="urn:jboss:module:1.1" name="javax.mail.api">
+ <dependencies>
+- <module name="javax.activation.api" optional="true"/>
+ <module name="javax.api"/>
+ </dependencies>
+
+diff --git a/build/src/main/resources/modules/javax/xml/bind/api/main/module.xml b/build/src/main/resources/modules/javax/xml/bind/api/main/module.xml
+index 6376d6f..d68235c 100644
+--- a/build/src/main/resources/modules/javax/xml/bind/api/main/module.xml
++++ b/build/src/main/resources/modules/javax/xml/bind/api/main/module.xml
+@@ -26,7 +26,6 @@
+
+
+ <dependencies>
+- <!-- <module name="javax.activation.api" export="true"/> is in JDK -->
+ <module name="javax.xml.stream.api"/>
+ <module name="com.sun.xml.bind" services="import"/>
+ <module name="javax.api"/>
+diff --git a/build/src/main/resources/modules/javax/xml/registry/api/main/module.xml b/build/src/main/resources/modules/javax/xml/registry/api/main/module.xml
+index 0b4a509..c49fde8 100644
+--- a/build/src/main/resources/modules/javax/xml/registry/api/main/module.xml
++++ b/build/src/main/resources/modules/javax/xml/registry/api/main/module.xml
+@@ -24,7 +24,7 @@
+
+ <module xmlns="urn:jboss:module:1.1" name="javax.xml.registry.api">
+ <dependencies>
+- <module name="javax.activation.api" export="true"/>
++ <module name="javax.api" export="true"/>
+ </dependencies>
+
+ <resources>
+diff --git a/build/src/main/resources/modules/org/codehaus/jackson/jackson-xc/main/module.xml b/build/src/main/resources/modules/org/codehaus/jackson/jackson-xc/main/module.xml
+index 2c5b473..3a9ea01 100644
+--- a/build/src/main/resources/modules/org/codehaus/jackson/jackson-xc/main/module.xml
++++ b/build/src/main/resources/modules/org/codehaus/jackson/jackson-xc/main/module.xml
+@@ -32,9 +32,8 @@
+
+ <dependencies>
+ <module name="javax.api"/>
+- <module name="javax.activation.api"/>
+ <module name="javax.xml.bind.api"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ </dependencies>
+-</module>
+\ No newline at end of file
++</module>
+diff --git a/build/src/main/resources/modules/org/jboss/resteasy/resteasy-jaxrs/main/module.xml b/build/src/main/resources/modules/org/jboss/resteasy/resteasy-jaxrs/main/module.xml
+index 0c06cc0..4f821ff 100644
+--- a/build/src/main/resources/modules/org/jboss/resteasy/resteasy-jaxrs/main/module.xml
++++ b/build/src/main/resources/modules/org/jboss/resteasy/resteasy-jaxrs/main/module.xml
+@@ -34,7 +34,6 @@
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="javax.annotation.api"/>
+- <module name="javax.activation.api"/>
+ <module name="javax.ws.rs.api"/>
+ <module name="org.apache.commons.codec" />
+ <module name="org.apache.httpcomponents" />
+diff --git a/pom.xml b/pom.xml
+index 13ba795..56c7d43 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -89,7 +89,6 @@
+ <version.dom4j>1.6.1</version.dom4j>
+ <version.gnu.getopt>1.0.13</version.gnu.getopt>
+ <version.jacorb>2.3.1.jbossorg-1</version.jacorb>
+- <version.javax.activation>1.1.1</version.javax.activation>
+ <version.javax.enterprise>1.0-SP4</version.javax.enterprise>
+ <version.javax.faces.jsf-api.1.2>1.2_15-jbossorg-2</version.javax.faces.jsf-api.1.2>
+ <version.javax.faces.jsf-impl>2.1.5-jbossorg-1</version.javax.faces.jsf-impl>
+@@ -1279,12 +1278,6 @@
+ </dependency>
+
+ <dependency>
+- <groupId>javax.activation</groupId>
+- <artifactId>activation</artifactId>
+- <version>${version.javax.activation}</version>
+- </dependency>
+-
+- <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ <version>${version.javax.enterprise}</version>
+--
+1.7.10
+
diff --git a/0053-Use-properties-in-add-user-AS7-module.patch b/0053-Use-properties-in-add-user-AS7-module.patch
new file mode 100644
index 0000000..75170e8
--- /dev/null
+++ b/0053-Use-properties-in-add-user-AS7-module.patch
@@ -0,0 +1,2539 @@
+From 5e20ac99edbb5b858716d6a139d3b59113eefdcb Mon Sep 17 00:00:00 2001
+From: Marek Goldmann <mgoldman at redhat.com>
+Date: Mon, 16 Apr 2012 18:23:15 +0200
+Subject: [PATCH 53/53] Use properties in add-user AS7 module
+
+---
+ build/src/main/resources/bin/add-user.sh | 11 +
+ .../management/DomainManagementMessages.java | 66 ++-
+ .../management/security/AddPropertiesUser.java | 584 ++------------------
+ .../domain/management/security/ConsoleWrapper.java | 85 +++
+ .../as/domain/management/security/JavaConsole.java | 66 +++
+ .../management/security/PropertiesFileLoader.java | 60 +-
+ .../domain/management/security/state/AddUser.java | 88 +++
+ .../security/state/ConfirmationChoice.java | 95 ++++
+ .../security/state/DuplicateUserCheckState.java | 68 +++
+ .../management/security/state/ErrorState.java | 74 +++
+ .../security/state/PromptNewUserState.java | 114 ++++
+ .../security/state/PromptPasswordState.java | 86 +++
+ .../security/state/PropertyFileFinder.java | 190 +++++++
+ .../security/state/PropertyFilePrompt.java | 104 ++++
+ .../as/domain/management/security/state/State.java | 34 ++
+ .../management/security/state/StateValues.java | 142 +++++
+ .../security/state/UpdatePropertiesHandler.java | 111 ++++
+ .../management/security/state/UpdateUser.java | 88 +++
+ .../security/state/UserPropertiesFileHandler.java | 38 ++
+ .../management/security/state/WeakCheckState.java | 90 +++
+ 20 files changed, 1631 insertions(+), 563 deletions(-)
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/ConsoleWrapper.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/JavaConsole.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/AddUser.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/ConfirmationChoice.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/DuplicateUserCheckState.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/ErrorState.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptNewUserState.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptPasswordState.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFileFinder.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFilePrompt.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/State.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/StateValues.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdatePropertiesHandler.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdateUser.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/UserPropertiesFileHandler.java
+ create mode 100644 domain-management/src/main/java/org/jboss/as/domain/management/security/state/WeakCheckState.java
+
+diff --git a/build/src/main/resources/bin/add-user.sh b/build/src/main/resources/bin/add-user.sh
+index dfb0c8b..eeb6ccc 100755
+--- a/build/src/main/resources/bin/add-user.sh
++++ b/build/src/main/resources/bin/add-user.sh
+@@ -51,6 +51,15 @@ if [ "x$JBOSS_MODULEPATH" = "x" ]; then
+ JBOSS_MODULEPATH="$JBOSS_HOME/modules"
+ fi
+
++# determine the default base dir, if not set
++if [ "x$JBOSS_BASE_DIR" = "x" ]; then
++ JBOSS_BASE_DIR="$JBOSS_HOME/standalone"
++fi
++# determine the default base dir for domain mode, if not set
++if [ "x$JBOSS_DOMAIN_BASE_DIR" = "x" ]; then
++ JBOSS_DOMAIN_BASE_DIR="$JBOSS_HOME/domain"
++fi
++
+ # For Cygwin, switch paths to Windows format before running java
+ if $cygwin; then
+ JBOSS_HOME=`cygpath --path --windows "$JBOSS_HOME"`
+@@ -64,6 +73,8 @@ fi
+ #JAVA_OPTS="$JAVA_OPTS -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y"
+
+ eval \"$JAVA\" $JAVA_OPTS \
++ -Djboss.server.base.dir=\"$JBOSS_BASE_DIR\" \
++ -Djboss.domain.base.dir=\"$JBOSS_DOMAIN_BASE_DIR\" \
+ -jar \"$JBOSS_HOME/jboss-modules.jar\" \
+ -mp \"${JBOSS_MODULEPATH}\" \
+ org.jboss.as.domain-add-user \
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/DomainManagementMessages.java b/domain-management/src/main/java/org/jboss/as/domain/management/DomainManagementMessages.java
+index 283a985..c9be048 100644
+--- a/domain-management/src/main/java/org/jboss/as/domain/management/DomainManagementMessages.java
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/DomainManagementMessages.java
+@@ -185,7 +185,7 @@ public interface DomainManagementMessages {
+ String jbossHomeNotSet();
+
+ /**
+- * A message indicating no mgmt-users.properties have been foun.
++ * A message indicating no mgmt-users.properties have been found.
+ *
+ * @return a {@link String} for the message.
+ */
+@@ -430,7 +430,7 @@ public interface DomainManagementMessages {
+ /**
+ * Creates an IllegalArgumentException indicating that a value can not be null.
+ *
+- * @param name - The name of the paramter that can not be null.
++ * @param name - The name of the parameter that can not be null.
+ * @return an {@link IllegalArgumentException} for the error.
+ */
+ @Message(id = 15248, value = "'%s' can not be null.")
+@@ -459,7 +459,7 @@ public interface DomainManagementMessages {
+ String filePrompt();
+
+ /**
+- * Propmpt the user for the roles to add the user to
++ * Prompt the user for the roles to add the user to
+ * @return
+ */
+ @Message(value = "What roles do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)")
+@@ -478,4 +478,64 @@ public interface DomainManagementMessages {
+ @Message(value = "Added user '%s' with roles %s to file '%s'")
+ String addedRoles(String username, String roles, String fileName);
+
++ /**
++ * The error message if the choice response is invalid.
++ *
++ * TODO - On translation we will need support for checking the possible responses.
++ *
++ * @return a {@link String} for the message.
++ */
++ @Message(id = 15251, value = "Invalid response. (Valid responses are A, a, B, or b)")
++ String invalidChoiceResponse();
++
++ /**
++ * Confirmation if the current user password and roles is about to be updated.
++ *
++ * @param user - The name of the user.
++ *
++ * @return a {@link String} for the message.
++ */
++ @Message(value = "User '%s' already exits, would you like to update the existing user password and roles")
++ String aboutToUpdateUser(String user);
++
++ /**
++ * Message to inform user that the user has been updated to the file identified.
++ *
++ * @param username - The new username.
++ * @param fileName - The file the user has been added to.
++ *
++ * @return a {@link String} for the message.
++ */
++ @Message(value = "Updated user '%s' to file '%s'")
++ String updateUser(String userName, String canonicalPath);
++
++
++
++ /**
++ * The error message if updating user to the file fails.
++ *
++ * @param file - The name of the file the add failed for.
++ * @param error - The failure message.
++ *
++ * @return a {@link String} for the message.
++ */
++ @Message(id = 15254, value = "Unable to update user to %s due to error %s")
++ String unableToUpdateUser(String absolutePath, String message);
++
++ /**
++ * Message to inform user that the user has been updated to the roles file identified.
++ *
++ * @param username - The new username.
++ * @param roles - The new roles.
++ * @param fileName - The file the user has been added to.
++ *
++ * @return a {@link String} for the message.
++ */
++ @Message(value = "Updated user '%s' with roles %s to file '%s'")
++ String updatedRoles(String username, String roles, String fileName);
++
++ /*
++ * Logging IDs 15200 to 15299 are reserved for domain management, the file DomainManagementLogger also contains messages in
++ * this range commencing 15200.
++ */
+ }
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/AddPropertiesUser.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/AddPropertiesUser.java
+index a52f501..b27c7dd 100644
+--- a/domain-management/src/main/java/org/jboss/as/domain/management/security/AddPropertiesUser.java
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/AddPropertiesUser.java
+@@ -22,24 +22,17 @@
+
+ package org.jboss.as.domain.management.security;
+
+-import java.io.BufferedWriter;
++import org.jboss.as.domain.management.security.state.PropertyFileFinder;
++import org.jboss.as.domain.management.security.state.PropertyFilePrompt;
++import org.jboss.as.domain.management.security.state.State;
++import org.jboss.as.domain.management.security.state.StateValues;
++
+ import java.io.Closeable;
+-import java.io.Console;
+-import java.io.File;
+-import java.io.FileInputStream;
+-import java.io.FileWriter;
+ import java.io.IOException;
+ import java.io.StringReader;
+-import java.security.NoSuchAlgorithmException;
+-import java.util.ArrayList;
+-import java.util.Arrays;
+-import java.util.HashSet;
+ import java.util.LinkedList;
+ import java.util.List;
+ import java.util.Properties;
+-import java.util.Set;
+-
+-import org.jboss.sasl.util.UsernamePasswordHashUtil;
+
+ import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
+
+@@ -50,36 +43,49 @@ import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
+ */
+ public class AddPropertiesUser {
+
+- private static final String[] badUsernames = {"admin", "administrator", "root"};
++ public static final String[] BAD_USER_NAMES = {"admin", "administrator", "root"};
+
+- private static final String DEFAULT_MANAGEMENT_REALM = "ManagementRealm";
+- private static final String DEFAULT_APPLICATION_REALM = "ApplicationRealm";
++ public static final String SERVER_BASE_DIR = "jboss.server.base.dir";
++ public static final String SERVER_CONFIG_DIR = "jboss.server.config.dir";
++ public static final String DOMAIN_BASE_DIR = "jboss.domain.base.dir";
++ public static final String DOMAIN_CONFIG_DIR = "jboss.domain.config.dir";
++
++ public static final String DEFAULT_MANAGEMENT_REALM = "ManagementRealm";
++ public static final String DEFAULT_APPLICATION_REALM = "ApplicationRealm";
+ public static final String MGMT_USERS_PROPERTIES = "mgmt-users.properties";
+ public static final String APPLICATION_USERS_PROPERTIES = "application-users.properties";
+ public static final String APPLICATION_ROLES_PROPERTIES = "application-roles.properties";
+ public static final String APPLICATION_USERS_SWITCH = "-a";
+
+- private static final String NEW_LINE = "\n";
+- private static final String SPACE = " ";
++
++ private static final char CARRIAGE_RETURN_CHAR = '\r';
++
++ public static final String NEW_LINE = "\n";
++ public static final String SPACE = " ";
+ private static final Properties argsCliProps = new Properties();
+
+- private final Console theConsole = System.console();
+
+- private List<File> propertiesFiles;
+- private List<File> roleFiles;
+- private Set<String> knownUsers;
+- private State nextState;
++ private ConsoleWrapper theConsole;
++
++
++ protected State nextState;
+
+- private AddPropertiesUser() {
+- if (theConsole == null) {
++ protected AddPropertiesUser() {
++ theConsole = new JavaConsole();
++ if (theConsole.getConsole() == null) {
+ throw MESSAGES.noConsoleAvailable();
+ }
+- nextState = new PropertyFilePrompt();
++ nextState = new PropertyFilePrompt(theConsole);
++ }
++
++ protected AddPropertiesUser(ConsoleWrapper console) {
++ this.theConsole = console;
++ nextState = new PropertyFilePrompt(theConsole);
+ }
+
+ private AddPropertiesUser(final boolean management, final String user, final char[] password, final String realm) {
+ boolean silent = false;
+- Values values = new Values();
++ StateValues stateValues = new StateValues();
+
+ String valueSilent = argsCliProps.getProperty("silent");
+
+@@ -87,27 +93,27 @@ public class AddPropertiesUser {
+ silent = Boolean.valueOf(valueSilent);
+ }
+ if (silent) {
+- values.howInteractive = Interactiveness.SILENT;
++ stateValues.setHowInteractive(Interactiveness.SILENT);
+ } else {
+- values.howInteractive = Interactiveness.NON_INTERACTIVE;
++ stateValues.setHowInteractive(Interactiveness.NON_INTERACTIVE);
+ }
+
+- if ((theConsole == null) && (values.isSilent() == false)) {
++ if ((theConsole == null) && (stateValues.isSilent() == false)) {
+ throw MESSAGES.noConsoleAvailable();
+ }
+- values.userName = user;
+- values.password = password;
+- values.realm = realm;
+- values.management = management;
++ stateValues.setUserName(user);
++ stateValues.setPassword(password);
++ stateValues.setRealm(realm);
++ stateValues.setManagement(management);
+
+- nextState = new PropertyFileFinder(values);
++ nextState = new PropertyFileFinder(theConsole, stateValues);
+ }
+
+ private AddPropertiesUser(boolean management, final String user, final char[] password) {
+ this(management, user, password, management ? DEFAULT_MANAGEMENT_REALM : DEFAULT_APPLICATION_REALM);
+ }
+
+- private void run() {
++ protected void run() {
+ while ((nextState = nextState.execute()) != null) {
+ }
+ }
+@@ -154,488 +160,6 @@ public class AddPropertiesUser {
+ }
+ }
+
+-
+- private class PropertyFilePrompt implements State {
+-
+- @Override
+- public State execute() {
+-
+- Values values = new Values();
+- theConsole.printf(NEW_LINE);
+- theConsole.printf(MESSAGES.filePrompt());
+- theConsole.printf(NEW_LINE);
+-
+- while (true) {
+- String temp = theConsole.readLine("(a): ");
+- if (temp == null) {
+- /*
+- * This will return user to the command prompt so add a new line to
+- * ensure the command prompt is on the next line.
+- */
+- theConsole.printf(NEW_LINE);
+- return null;
+- }
+- if (temp.length() > 0) {
+- switch (temp.charAt(0)) {
+- case 'a':
+- case 'A':
+- values.management = true;
+- values.realm = DEFAULT_MANAGEMENT_REALM;
+- return new PropertyFileFinder(values);
+- case 'b':
+- case 'B':
+- values.management = false;
+- values.realm = DEFAULT_APPLICATION_REALM;
+- return new PropertyFileFinder(values);
+- }
+- } else {
+- values.management = true;
+- values.realm = DEFAULT_MANAGEMENT_REALM;
+- return new PropertyFileFinder(values);
+- }
+- }
+- }
+- }
+-
+- /**
+- * The first state executed, responsible for searching for the relevent properties files.
+- */
+- private class PropertyFileFinder implements State {
+-
+- private final Values values;
+-
+- private PropertyFileFinder(final Values values) {
+- this.values = values;
+- }
+-
+- @Override
+- public State execute() {
+- String jbossHome = System.getenv("JBOSS_HOME");
+- if (jbossHome == null) {
+- return new ErrorState(MESSAGES.jbossHomeNotSet(), null, values);
+- }
+-
+- List<File> foundFiles = new ArrayList<File>(2);
+- final String fileName = values.management ? MGMT_USERS_PROPERTIES : APPLICATION_USERS_PROPERTIES;
+- if (!findFiles(jbossHome, foundFiles, fileName)) {
+- return new ErrorState(MESSAGES.propertiesFileNotFound(fileName), null, values);
+- }
+- if(!values.management) {
+- List<File> foundRoleFiles = new ArrayList<File>(2);
+- if (!findFiles(jbossHome, foundRoleFiles, APPLICATION_ROLES_PROPERTIES)) {
+- return new ErrorState(MESSAGES.propertiesFileNotFound(APPLICATION_ROLES_PROPERTIES), null, values);
+- }
+- roleFiles = foundRoleFiles;
+- }
+-
+- propertiesFiles = foundFiles;
+-
+- Set<String> foundUsers = new HashSet<String>();
+- for (File current : propertiesFiles) {
+- try {
+- foundUsers.addAll(loadUserNames(current));
+- } catch (IOException e) {
+- return new ErrorState(MESSAGES.unableToLoadUsers(current.getAbsolutePath(), e.getMessage()), null, values);
+- }
+- }
+- knownUsers = foundUsers;
+-
+- if (values == null) {
+- return new PromptNewUserState();
+- } else {
+- return new PromptNewUserState(values);
+- }
+- }
+-
+- private boolean findFiles(final String jbossHome, final List<File> foundFiles, final String fileName) {
+- File standaloneProps = new File(jbossHome + "/standalone/configuration/" + fileName);
+- if (standaloneProps.exists()) {
+- foundFiles.add(standaloneProps);
+- }
+- File domainProps = new File(jbossHome + "/domain/configuration/" + fileName);
+- if (domainProps.exists()) {
+- foundFiles.add(domainProps);
+- }
+-
+- if (foundFiles.size() == 0) {
+- return false;
+- }
+- return true;
+- }
+-
+- private Set<String> loadUserNames(final File file) throws IOException {
+-
+- FileInputStream fis = null;
+- try {
+- fis = new FileInputStream(file);
+- Properties tempProps = new Properties();
+- tempProps.load(fis);
+-
+- return tempProps.stringPropertyNames();
+- } finally {
+- safeClose(fis);
+- }
+-
+- }
+-
+- }
+-
+- /**
+- * State to prompt the user for the realm, username and password to use, this State can be called back to so allows for a
+- * pre-defined realm and username to be used.
+- */
+- private class PromptNewUserState implements State {
+- private final Values values;
+-
+- PromptNewUserState() {
+- values = new Values();
+- values.realm = DEFAULT_MANAGEMENT_REALM;
+- }
+-
+- PromptNewUserState(final Values values) {
+- this.values = values;
+- }
+-
+- @Override
+- public State execute() {
+- if (values.isSilentOrNonInteractive() == false) {
+- theConsole.printf(NEW_LINE);
+- theConsole.printf(MESSAGES.enterNewUserDetails());
+- theConsole.printf(NEW_LINE);
+- values.password = null; // If interactive we want to be sure to capture this.
+-
+- /*
+- * Prompt for realm.
+- */
+- theConsole.printf(MESSAGES.realmPrompt(values.realm));
+- String temp = theConsole.readLine(" : ");
+- if (temp == null) {
+- /*
+- * This will return user to the command prompt so add a new line to
+- * ensure the command prompt is on the next line.
+- */
+- theConsole.printf(NEW_LINE);
+- return null;
+- }
+- if (temp.length() > 0) {
+- values.realm = temp;
+- }
+-
+- /*
+- * Prompt for username.
+- */
+- String existingUsername = values.userName;
+- String usernamePrompt = existingUsername == null ? MESSAGES.usernamePrompt() :
+- MESSAGES.usernamePrompt(existingUsername);
+- theConsole.printf(usernamePrompt);
+- temp = theConsole.readLine(" : ");
+- if (temp != null && temp.length() > 0) {
+- existingUsername = temp;
+- }
+- // The user could have pressed Ctrl-D, in which case we do not use the default value.
+- if (temp == null || existingUsername == null || existingUsername.length() == 0) {
+- return new ErrorState(MESSAGES.noUsernameExiting());
+- }
+- values.userName = existingUsername;
+-
+- /*
+- * Prompt for password.
+- */
+- theConsole.printf(MESSAGES.passwordPrompt());
+- char[] tempChar = theConsole.readPassword(" : ");
+- if (tempChar == null || tempChar.length == 0) {
+- return new ErrorState(MESSAGES.noPasswordExiting());
+- }
+-
+- theConsole.printf(MESSAGES.passwordConfirmationPrompt());
+- char[] secondTempChar = theConsole.readPassword(" : ");
+- if (secondTempChar == null) {
+- secondTempChar = new char[0]; // If re-entry missed allow fall through to comparison.
+- }
+-
+- if (Arrays.equals(tempChar, secondTempChar) == false) {
+- return new ErrorState(MESSAGES.passwordMisMatch(), this);
+- }
+- values.password = tempChar;
+-
+- if(!values.management) {
+- theConsole.printf(MESSAGES.rolesPrompt());
+- values.roles = theConsole.readLine(" : ");
+- }
+- }
+-
+- return new WeakCheckState(values);
+- }
+-
+- }
+-
+- /**
+- * State to check the strength of the values selected.
+- * <p/>
+- * TODO - Currently only very basic checks are performed, this could be updated to perform additional password strength
+- * checks.
+- */
+- private class WeakCheckState implements State {
+-
+- private Values values;
+-
+- private WeakCheckState(Values values) {
+- this.values = values;
+- }
+-
+- @Override
+- public State execute() {
+- State retryState = values.isSilentOrNonInteractive() ? null : new PromptNewUserState(values);
+-
+- if (Arrays.equals(values.userName.toCharArray(), values.password)) {
+- return new ErrorState(MESSAGES.usernamePasswordMatch(), retryState);
+- }
+-
+- for (char currentChar : values.userName.toCharArray()) {
+- if ((Character.isLetter(currentChar) || Character.isDigit(currentChar)) == false) {
+- return new ErrorState(MESSAGES.usernameNotAlphaNumeric(), retryState);
+- }
+- }
+-
+- boolean weakUserName = false;
+- for (String current : badUsernames) {
+- if (current.equals(values.userName.toLowerCase())) {
+- weakUserName = true;
+- break;
+- }
+- }
+-
+- State continuingState = new DuplicateUserCheckState(values);
+- if (weakUserName && values.isSilentOrNonInteractive() == false) {
+- String message = MESSAGES.usernameEasyToGuess(values.userName);
+- String prompt = MESSAGES.sureToAddUser(values.userName);
+- State noState = new PromptNewUserState(values);
+-
+- return new ConfirmationChoice(message, prompt, continuingState, noState);
+- }
+-
+- return continuingState;
+- }
+-
+- }
+-
+- /**
+- * State to check that the user is not already defined in any of the resolved
+- * properties files.
+- */
+- private class DuplicateUserCheckState implements State {
+-
+- private Values values;
+-
+- private DuplicateUserCheckState(final Values values) {
+- this.values = values;
+- }
+-
+- @Override
+- public State execute() {
+- if (knownUsers.contains(values.userName)) {
+- State continuing = values.isSilentOrNonInteractive() ? null : new PromptNewUserState(values);
+-
+- return new ErrorState(MESSAGES.duplicateUser(values.userName), continuing, values);
+- }
+-
+- State addState = new AddUser(values);
+- final State continuingState;
+- if (values.isSilentOrNonInteractive()) {
+- continuingState = addState;
+- } else {
+- String message = MESSAGES.aboutToAddUser(values.userName, values.realm);
+- String prompt = MESSAGES.isCorrectPrompt();
+-
+- continuingState = new ConfirmationChoice(message, prompt, addState, new PromptNewUserState(values));
+- }
+-
+- return continuingState;
+- }
+-
+-
+- }
+-
+- /**
+- * State to display a message to the user with option to confirm a choice.
+- * <p/>
+- * This state handles either a yes or no outcome and will loop with an error
+- * on invalid input.
+- */
+- private class ConfirmationChoice implements State {
+-
+- private final String message;
+- private final String prompt;
+- private final State yesState;
+- private final State noState;
+-
+- private static final int YES = 0;
+- private static final int NO = 1;
+- private static final int INVALID = 2;
+-
+- private ConfirmationChoice(final String message, final String prompt, final State yesState, final State noState) {
+- this.message = message;
+- this.prompt = prompt;
+- this.yesState = yesState;
+- this.noState = noState;
+- }
+-
+- @Override
+- public State execute() {
+- if (message != null) {
+- theConsole.printf(message);
+- theConsole.printf(NEW_LINE);
+- }
+-
+- theConsole.printf(prompt);
+- String temp = theConsole.readLine(SPACE);
+-
+- switch (convertResponse(temp)) {
+- case YES:
+- return yesState;
+- case NO:
+- return noState;
+- default:
+- return new ErrorState(MESSAGES.invalidConfirmationResponse(), this);
+- }
+- }
+-
+- private int convertResponse(final String response) {
+- if (response != null) {
+- String temp = response.toLowerCase();
+- if ("yes".equals(temp) || "y".equals(temp)) {
+- return YES;
+- }
+-
+- if ("no".equals(temp) || "n".equals(temp)) {
+- return NO;
+- }
+- }
+-
+- return INVALID;
+- }
+-
+- }
+-
+- /**
+- * State to perform the actual addition to the discovered properties files.
+- * <p/>
+- * By this time ALL validation should be complete, this State will only fail for IOExceptions encountered
+- * performing the actual writes.
+- */
+- private class AddUser implements State {
+-
+- private final Values values;
+-
+- private AddUser(final Values values) {
+- this.values = values;
+- }
+-
+- @Override
+- public State execute() {
+- String entry;
+-
+- try {
+- String hash = new UsernamePasswordHashUtil().generateHashedHexURP(values.userName, values.realm,
+- values.password);
+- entry = values.userName + "=" + hash;
+- } catch (NoSuchAlgorithmException e) {
+- return new ErrorState(e.getMessage(), null, values);
+- }
+-
+- for (File current : propertiesFiles) {
+- try {
+- append(entry, current);
+- if (values.isSilent() == false) {
+- theConsole.printf(MESSAGES.addedUser(values.userName, current.getCanonicalPath()));
+- theConsole.printf(NEW_LINE);
+- }
+- } catch (IOException e) {
+- return new ErrorState(MESSAGES.unableToAddUser(current.getAbsolutePath(), e.getMessage()), null, values);
+- }
+- }
+-
+- if(!values.management && values.roles != null && values.roles.length() > 0) {
+- for (final File current : roleFiles) {
+- String role = values.userName + "=" + values.roles;
+- try {
+- append(role, current);
+- if (values.isSilent() == false) {
+- theConsole.printf(MESSAGES.addedRoles(values.userName, values.roles, current.getCanonicalPath()));
+- theConsole.printf(NEW_LINE);
+- }
+- } catch (IOException e) {
+- return new ErrorState(MESSAGES.unableToAddUser(current.getAbsolutePath(), e.getMessage()), null, values);
+- }
+- }
+- }
+-
+- /*
+- * At this point the files have been written and confirmation passed back so nothing else to do.
+- */
+- return null;
+- }
+-
+- private void append(final String entry, final File toFile) throws IOException {
+- FileWriter fw = null;
+- BufferedWriter bw = null;
+-
+- try {
+- fw = new FileWriter(toFile, true);
+- bw = new BufferedWriter(fw);
+-
+- bw.append(entry);
+- bw.newLine();
+- } finally {
+- safeClose(bw);
+- safeClose(fw);
+- }
+-
+- }
+- }
+-
+- /**
+- * State to report an error to the user, optionally a nextState can be supplied so the process can continue even though an
+- * error has been reported.
+- */
+- private class ErrorState implements State {
+-
+- private final State nextState;
+- private final String errorMessage;
+- private final Values values;
+-
+- private ErrorState(String errorMessage) {
+- this(errorMessage, null, null);
+- }
+-
+- private ErrorState(String errorMessage, State nextState) {
+- this(errorMessage, nextState, null);
+- }
+-
+- private ErrorState(String errorMessage, State nextState, Values values) {
+- this.errorMessage = errorMessage;
+- this.nextState = nextState;
+- this.values = values;
+- }
+-
+- @Override
+- public State execute() {
+- if ((values == null) || (values != null) && (values.isSilent() == false)) {
+- theConsole.printf(NEW_LINE);
+- theConsole.printf(" * ");
+- theConsole.printf(MESSAGES.errorHeader());
+- theConsole.printf(" * ");
+- theConsole.printf(NEW_LINE);
+-
+- theConsole.printf(errorMessage);
+- theConsole.printf(NEW_LINE);
+- theConsole.printf(NEW_LINE);
+- }
+- return nextState;
+- }
+-
+- }
+-
+ private static void safeClose(Closeable c) {
+ if (c != null) {
+ try {
+@@ -645,31 +169,7 @@ public class AddPropertiesUser {
+ }
+ }
+
+- private class Values {
+- private Interactiveness howInteractive = Interactiveness.INTERACTIVE;
+- private String realm;
+- private String userName;
+- private char[] password;
+- private boolean management;
+- private String roles;
+-
+- private boolean isSilentOrNonInteractive() {
+- return (howInteractive == Interactiveness.NON_INTERACTIVE) || isSilent();
+- }
+-
+- private boolean isSilent() {
+- return (howInteractive == Interactiveness.SILENT);
+- }
+- }
+-
+- private enum Interactiveness {
++ public enum Interactiveness {
+ SILENT, NON_INTERACTIVE, INTERACTIVE
+ }
+-
+- private interface State {
+-
+- State execute();
+-
+- }
+-
+ }
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/ConsoleWrapper.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/ConsoleWrapper.java
+new file mode 100644
+index 0000000..b4458fa
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/ConsoleWrapper.java
+@@ -0,0 +1,85 @@
++/*
++ * 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.
++ */
++
++package org.jboss.as.domain.management.security;
++
++import java.io.IOError;
++import java.util.IllegalFormatException;
++
++/**
++ * Wrap the console commands
++ *
++ * @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++ */
++public interface ConsoleWrapper<T> {
++
++ /**
++ * Writes a formatted string to this console's output stream using
++ * the specified format string and arguments.
++ * see <a href="../util/Formatter.html#syntax">Format string syntax</a>
++ * @param fmt
++ * @param args
++ */
++ T format(String fmt, Object ...args) throws IllegalFormatException;
++
++ /**
++ * A convenience method to write a formatted string to this console's
++ * output stream using the specified format string and arguments.
++ *
++ * @param format
++ * @param args
++ * @throws IllegalStateException
++ */
++ void printf(String format, Object ... args) throws IllegalFormatException;
++
++ /**
++ * Provides a formatted prompt, then reads a single line of text from the
++ * console.
++ *
++ * @param fmt
++ * @param args
++ * @return A string containing the line read from the console, not
++ * including any line-termination characters, or <tt>null</tt>
++ * if an end of stream has been reached.
++ * @throws IOError
++ */
++ String readLine(String fmt, Object ... args) throws IOError;
++
++ /**
++ * Provides a formatted prompt, then reads a password or passphrase from
++ * the console with echoing disabled.
++ *
++ * @param fmt
++ * @param args
++ * @return A character array containing the password or passphrase read
++ * from the console.
++ * @throws IOError
++ */
++ char[] readPassword(String fmt, Object ... args) throws IllegalFormatException, IOError;
++
++ /**
++ * Return the console object
++ *
++ * @return Return the console object
++ */
++ T getConsole();
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/JavaConsole.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/JavaConsole.java
+new file mode 100644
+index 0000000..964a26a
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/JavaConsole.java
+@@ -0,0 +1,66 @@
++/*
++ *
++ * * JBoss, Home of Professional Open Source.
++ * * Copyright 2011, Red Hat, Inc., and individual contributors
++ * * as indicated by the @author tags. See the copyright.txt file in the
++ * * distribution for a full listing of individual contributors.
++ * *
++ * * This is free software; you can redistribute it and/or modify it
++ * * under the terms of the GNU Lesser General Public License as
++ * * published by the Free Software Foundation; either version 2.1 of
++ * * the License, or (at your option) any later version.
++ * *
++ * * This software is distributed in the hope that it will be useful,
++ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * * Lesser General Public License for more details.
++ * *
++ * * You should have received a copy of the GNU Lesser General Public
++ * * License along with this software; if not, write to the Free
++ * * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ *
++ */
++
++package org.jboss.as.domain.management.security;
++
++import java.io.Console;
++import java.io.IOError;
++import java.util.IllegalFormatException;
++
++/**
++ * Describe the purpose
++ *
++ * @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++ */
++public class JavaConsole implements ConsoleWrapper<Console> {
++
++ private Console theConsole = System.console();
++
++ public void JavaConsole() {}
++
++ @Override
++ public Console format(String fmt, Object... args) throws IllegalFormatException {
++ return theConsole.format(fmt,args);
++ }
++
++ @Override
++ public void printf(String format, Object... args) throws IllegalFormatException {
++ theConsole.printf(format,args);
++ }
++
++ @Override
++ public String readLine(String fmt, Object... args) throws IOError {
++ return theConsole.readLine(fmt,args);
++ }
++
++ @Override
++ public char[] readPassword(String fmt, Object... args) throws IllegalFormatException, IOError {
++ return theConsole.readPassword(fmt,args);
++ }
++
++ @Override
++ public Console getConsole() {
++ return theConsole;
++ }
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/PropertiesFileLoader.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/PropertiesFileLoader.java
+index 97ca458..38737cb 100644
+--- a/domain-management/src/main/java/org/jboss/as/domain/management/security/PropertiesFileLoader.java
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/PropertiesFileLoader.java
+@@ -22,24 +22,27 @@
+
+ package org.jboss.as.domain.management.security;
+
+-import static org.jboss.as.domain.management.DomainManagementLogger.ROOT_LOGGER;
+-import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++import org.jboss.msc.service.StartContext;
++import org.jboss.msc.service.StartException;
++import org.jboss.msc.service.StopContext;
++import org.jboss.msc.value.InjectedValue;
+
+ import java.io.BufferedReader;
+ import java.io.BufferedWriter;
+ import java.io.Closeable;
+ import java.io.File;
+ import java.io.FileInputStream;
++import java.io.FileOutputStream;
+ import java.io.FileReader;
+-import java.io.FileWriter;
+ import java.io.IOException;
+-import java.io.InputStream;
++import java.io.InputStreamReader;
++import java.io.OutputStreamWriter;
++import java.nio.charset.Charset;
++import java.util.Arrays;
+ import java.util.Properties;
+
+-import org.jboss.msc.service.StartContext;
+-import org.jboss.msc.service.StartException;
+-import org.jboss.msc.service.StopContext;
+-import org.jboss.msc.value.InjectedValue;
++import static org.jboss.as.domain.management.DomainManagementLogger.ROOT_LOGGER;
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
+
+ /**
+ * The base class for services depending on loading a properties file, loads the properties on
+@@ -49,6 +52,7 @@ import org.jboss.msc.value.InjectedValue;
+ */
+ public abstract class PropertiesFileLoader {
+
++ public static final char[] ESCAPE_ARRAY = new char[]{'='};
+ private final String path;
+ private final InjectedValue<String> relativeTo = new InjectedValue<String>();
+
+@@ -82,7 +86,7 @@ public abstract class PropertiesFileLoader {
+ propertiesFile = null;
+ }
+
+- protected Properties getProperties() throws IOException {
++ public Properties getProperties() throws IOException {
+ /*
+ * This method does attempt to minimise the effect of race conditions, however this is not overly critical as if you
+ * have users attempting to authenticate at the exact point their details are added to the file there is also a chance
+@@ -99,7 +103,7 @@ public abstract class PropertiesFileLoader {
+ if (loadReallyRequired) {
+ ROOT_LOGGER.debugf("Reloading properties file '%s'", propertiesFile.getAbsolutePath());
+ Properties props = new Properties();
+- InputStream is = new FileInputStream(propertiesFile);
++ InputStreamReader is = new InputStreamReader(new FileInputStream(propertiesFile), Charset.forName("UTF-8"));
+ try {
+ props.load(is);
+ } finally {
+@@ -118,7 +122,7 @@ public abstract class PropertiesFileLoader {
+ return properties;
+ }
+
+- private synchronized void persistProperties() throws IOException {
++ public synchronized void persistProperties() throws IOException {
+ Properties toSave = (Properties) properties.clone();
+
+ File backup = new File(propertiesFile.getCanonicalPath() + ".bak");
+@@ -135,8 +139,7 @@ public abstract class PropertiesFileLoader {
+ FileReader fr = new FileReader(backup);
+ BufferedReader br = new BufferedReader(fr);
+
+- FileWriter fw = new FileWriter(propertiesFile);
+- BufferedWriter bw = new BufferedWriter(fw);
++ BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(propertiesFile),"UTF8"));
+
+ try {
+ String line;
+@@ -151,8 +154,9 @@ public abstract class PropertiesFileLoader {
+ int equals = trimmed.indexOf('=');
+ if (equals > 0) {
+ String userName = trimmed.substring(0, equals);
+- if (toSave.contains(userName)) {
+- bw.append(userName + "=" + toSave.getProperty(userName));
++ if (toSave.containsKey(userName)) {
++ String escapedUserName = escapeString(userName, ESCAPE_ARRAY);
++ bw.append(escapedUserName + "=" + toSave.getProperty(userName));
+ bw.newLine();
+ toSave.remove(userName);
+ }
+@@ -162,18 +166,38 @@ public abstract class PropertiesFileLoader {
+
+ // Append any additional users to the end of the file.
+ for (Object currentKey : toSave.keySet()) {
+- bw.append(currentKey + "=" + toSave.getProperty((String) currentKey));
++ String escapedUserName = escapeString((String) currentKey, ESCAPE_ARRAY);
++ bw.append(escapedUserName + "=" + toSave.getProperty((String) currentKey));
+ bw.newLine();
+ }
+- bw.newLine();
+ } finally {
+ safeClose(bw);
+- safeClose(fw);
+ safeClose(br);
+ safeClose(fr);
+ }
+ }
+
++
++ public static String escapeString(String name, char[] escapeArray) {
++ Arrays.sort(escapeArray);
++ for(int i = 0; i < name.length(); ++i) {
++ char ch = name.charAt(i);
++ if(Arrays.binarySearch(escapeArray,ch) >=0 ) {
++ StringBuilder builder = new StringBuilder();
++ builder.append(name, 0, i);
++ builder.append('\\').append(ch);
++ for(int j = i + 1; j < name.length(); ++j) {
++ ch = name.charAt(j);
++ if(Arrays.binarySearch(escapeArray,ch)>0) {
++ builder.append('\\');
++ }
++ builder.append(ch);
++ }
++ return builder.toString();
++ }
++ }
++ return name;
++ }
+ private void safeClose(final Closeable c) {
+ try {
+ c.close();
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/AddUser.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/AddUser.java
+new file mode 100644
+index 0000000..58e92ed
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/AddUser.java
+@@ -0,0 +1,88 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++import org.jboss.msc.service.StartException;
++
++import java.io.File;
++import java.io.IOException;
++import java.util.Properties;
++
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * State to perform the actual addition to the discovered properties files.
++ * <p/>
++ * By this time ALL validation should be complete, this State will only fail for IOExceptions encountered
++ * performing the actual writes.
++ */
++public class AddUser extends UpdatePropertiesHandler implements State {
++
++ private final StateValues stateValues;
++
++ public AddUser(ConsoleWrapper theConsole, final StateValues stateValues) {
++ super(theConsole);
++ this.stateValues = stateValues;
++ }
++
++ @Override
++ public State execute() {
++ /*
++ * At this point the files have been written and confirmation passed back so nothing else to do.
++ */
++ return update(stateValues);
++ }
++
++ @Override
++ void persist(String[] entry, File file) throws IOException {
++ UserPropertiesFileHandler propertiesHandler = new UserPropertiesFileHandler(file.getAbsolutePath());
++ try {
++ propertiesHandler.start(null);
++ Properties prob = propertiesHandler.getProperties();
++ prob.setProperty(entry[0], entry[1]);
++ propertiesHandler.persistProperties();
++ } catch (StartException e) {
++ throw new IllegalStateException(MESSAGES.unableToAddUser(file.getAbsolutePath(), e.getMessage()));
++ } finally {
++ propertiesHandler.stop(null);
++ }
++
++ }
++
++ @Override
++ String consoleUserMessage(String filePath) {
++ return MESSAGES.addedUser(stateValues.getUserName(), filePath);
++ }
++
++ @Override
++ String consoleRolesMessage(String filePath) {
++ return MESSAGES.addedRoles(stateValues.getUserName(), stateValues.getRoles(), filePath);
++ }
++
++ @Override
++ String errorMessage(String filePath, Throwable e) {
++ return MESSAGES.unableToAddUser(filePath, e.getMessage());
++ }
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/ConfirmationChoice.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/ConfirmationChoice.java
+new file mode 100644
+index 0000000..fffa6cf
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/ConfirmationChoice.java
+@@ -0,0 +1,95 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.NEW_LINE;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.SPACE;
++
++/**
++ * State to display a message to the user with option to confirm a choice.
++ * <p/>
++ * This state handles either a yes or no outcome and will loop with an error
++ * on invalid input.
++ */
++public class ConfirmationChoice implements State {
++
++ private ConsoleWrapper theConsole;
++ private final String message;
++ private final String prompt;
++ private final State yesState;
++ private final State noState;
++
++ private static final int YES = 0;
++ private static final int NO = 1;
++ private static final int INVALID = 2;
++
++ public ConfirmationChoice(ConsoleWrapper theConsole,final String message, final String prompt, final State yesState, final State noState) {
++ this.theConsole = theConsole;
++ this.message = message;
++ this.prompt = prompt;
++ this.yesState = yesState;
++ this.noState = noState;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ @Override
++ public State execute() {
++ if (message != null) {
++ theConsole.printf(message);
++ theConsole.printf(NEW_LINE);
++ }
++
++ theConsole.printf(prompt);
++ String temp = theConsole.readLine(SPACE);
++
++ switch (convertResponse(temp)) {
++ case YES:
++ return yesState;
++ case NO:
++ return noState;
++ default:
++ return new ErrorState(theConsole, MESSAGES.invalidConfirmationResponse(), this);
++ }
++ }
++
++ private int convertResponse(final String response) {
++ if (response != null) {
++ String temp = response.toLowerCase();
++ if ("yes".equals(temp) || "y".equals(temp)) {
++ return YES;
++ }
++
++ if ("no".equals(temp) || "n".equals(temp)) {
++ return NO;
++ }
++ }
++
++ return INVALID;
++ }
++
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/DuplicateUserCheckState.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/DuplicateUserCheckState.java
+new file mode 100644
+index 0000000..a222e15
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/DuplicateUserCheckState.java
+@@ -0,0 +1,68 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * State to check that the user is not already defined in any of the resolved
++ * properties files.
++ */
++public class DuplicateUserCheckState implements State {
++
++ private final ConsoleWrapper theConsole;
++ private StateValues stateValues;
++
++ public DuplicateUserCheckState(final ConsoleWrapper theConsole,final StateValues stateValues) {
++ this.theConsole = theConsole;
++ this.stateValues = stateValues;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ @Override
++ public State execute() {
++ final State continuingState;
++ if (stateValues.isExistingUser()) {
++ continuingState = new UpdateUser(theConsole, stateValues);
++ } else {
++ State addState = new AddUser(theConsole, stateValues);
++
++ if (stateValues.isSilentOrNonInteractive()) {
++ continuingState = addState;
++ } else {
++ String message = MESSAGES.aboutToAddUser(stateValues.getUserName(), stateValues.getRealm());
++ String prompt = MESSAGES.isCorrectPrompt();
++
++ continuingState = new ConfirmationChoice(theConsole,message, prompt, addState, new PromptNewUserState(theConsole, stateValues));
++ }
++ }
++
++ return continuingState;
++ }
++
++
++}
++
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/ErrorState.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/ErrorState.java
+new file mode 100644
+index 0000000..6f875bc
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/ErrorState.java
+@@ -0,0 +1,74 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.NEW_LINE;
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * State to report an error to the user, optionally a nextState can be supplied so the process can continue even though an
++ * error has been reported.
++ */
++public class ErrorState implements State {
++
++ private final State nextState;
++ private final String errorMessage;
++ private final StateValues stateValues;
++ private ConsoleWrapper theConsole;
++
++ public ErrorState(ConsoleWrapper theConsole, String errorMessage) {
++ this(theConsole, errorMessage, null, null);
++ }
++
++ public ErrorState(ConsoleWrapper theConsole, String errorMessage, State nextState) {
++ this(theConsole, errorMessage, nextState, null);
++ }
++
++ public ErrorState(ConsoleWrapper theConsole, String errorMessage, State nextState, StateValues stateValues) {
++ this.errorMessage = errorMessage;
++ this.nextState = nextState;
++ this.stateValues = stateValues;
++ this.theConsole = theConsole;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ @Override
++ public State execute() {
++ if ((stateValues == null) || (stateValues != null) && (stateValues.isSilent() == false)) {
++ theConsole.printf(NEW_LINE);
++ theConsole.printf(" * ");
++ theConsole.printf(MESSAGES.errorHeader());
++ theConsole.printf(" * ");
++ theConsole.printf(NEW_LINE);
++
++ theConsole.printf(errorMessage);
++ theConsole.printf(NEW_LINE);
++ theConsole.printf(NEW_LINE);
++ }
++ return nextState;
++ }
++
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptNewUserState.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptNewUserState.java
+new file mode 100644
+index 0000000..f0b157a
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptNewUserState.java
+@@ -0,0 +1,114 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++
++import static org.jboss.as.domain.management.security.AddPropertiesUser.DEFAULT_MANAGEMENT_REALM;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.NEW_LINE;
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * State to prompt the user for the realm, username and password to use, this State can be called back to so allows for a
++ * pre-defined realm and username to be used.
++ */
++public class PromptNewUserState implements State {
++ private final StateValues stateValues;
++ private ConsoleWrapper theConsole;
++
++ public PromptNewUserState(ConsoleWrapper theConsole) {
++ this.theConsole = theConsole;
++ stateValues = new StateValues();
++ stateValues.setRealm(DEFAULT_MANAGEMENT_REALM);
++ }
++
++ public PromptNewUserState(ConsoleWrapper theConsole, final StateValues stateValues) {
++ this.theConsole = theConsole;
++ this.stateValues = stateValues;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ @Override
++ public State execute() {
++ State continuingState = new PromptPasswordState(theConsole, stateValues);
++ if (stateValues.isSilentOrNonInteractive() == false) {
++ theConsole.printf(NEW_LINE);
++ theConsole.printf(MESSAGES.enterNewUserDetails());
++ theConsole.printf(NEW_LINE);
++ stateValues.setPassword(null); // If interactive we want to be sure to capture this.
++
++ /*
++ * Prompt for realm.
++ */
++ theConsole.printf(MESSAGES.realmPrompt(stateValues.getRealm()));
++ String temp = theConsole.readLine(" : ");
++ if (temp == null) {
++ /*
++ * This will return user to the command prompt so add a new line to
++ * ensure the command prompt is on the next line.
++ */
++ theConsole.printf(NEW_LINE);
++ return null;
++ }
++ if (temp.length() > 0) {
++ stateValues.setRealm(temp);
++ }
++
++ /*
++ * Prompt for username.
++ */
++ String existingUsername = stateValues.getUserName();
++ String usernamePrompt = existingUsername == null ? MESSAGES.usernamePrompt() :
++ MESSAGES.usernamePrompt(existingUsername);
++ theConsole.printf(usernamePrompt);
++ temp = theConsole.readLine(" : ");
++ if (temp != null && temp.length() > 0) {
++ existingUsername = temp;
++ }
++ // The user could have pressed Ctrl-D, in which case we do not use the default value.
++ if (temp == null || existingUsername == null || existingUsername.length() == 0) {
++ return new ErrorState(theConsole,MESSAGES.noUsernameExiting());
++ }
++ stateValues.setUserName(existingUsername);
++
++ if (stateValues.getKnownUsers().contains(stateValues.getUserName())) {
++ State duplicateContinuing = stateValues.isSilentOrNonInteractive() ? null : new PromptNewUserState(theConsole, stateValues);
++ if (stateValues.isSilentOrNonInteractive()) {
++ continuingState = new ErrorState(theConsole, MESSAGES.duplicateUser(stateValues.getUserName()), duplicateContinuing, stateValues);
++ } else {
++ String message = MESSAGES.aboutToUpdateUser(stateValues.getUserName());
++ String prompt = MESSAGES.isCorrectPrompt();
++
++ stateValues.setExistingUser(true);
++ continuingState = new ConfirmationChoice(theConsole,message, prompt, continuingState, duplicateContinuing);
++ }
++ }
++ }
++
++ return continuingState;
++ }
++
++}
+\ No newline at end of file
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptPasswordState.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptPasswordState.java
+new file mode 100644
+index 0000000..91ab15a
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PromptPasswordState.java
+@@ -0,0 +1,86 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++
++import java.util.Arrays;
++
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * State to prompt the user for a password
++ * <p/>
++ * This state handles password validation by let the user re-enter the password
++ * in case of the password mismatch the user will be present for an error
++ * and will re-enter the PromptPasswordState again
++ */
++public class PromptPasswordState implements State {
++
++ private ConsoleWrapper theConsole;
++ private StateValues stateValues;
++
++ public PromptPasswordState(ConsoleWrapper theConsole, StateValues stateValues) {
++ this.theConsole = theConsole;
++ this.stateValues = stateValues;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ @Override
++ public State execute() {
++ State continuingState = new WeakCheckState(theConsole, stateValues);
++ if (stateValues.isSilentOrNonInteractive() == false) {
++ /*
++ * Prompt for password.
++ */
++ theConsole.printf(MESSAGES.passwordPrompt());
++ char[] tempChar = theConsole.readPassword(" : ");
++ if (tempChar == null || tempChar.length == 0) {
++ return new ErrorState(theConsole,MESSAGES.noPasswordExiting());
++ }
++
++ theConsole.printf(MESSAGES.passwordConfirmationPrompt());
++ char[] secondTempChar = theConsole.readPassword(" : ");
++ if (secondTempChar == null) {
++ secondTempChar = new char[0]; // If re-entry missed allow fall through to comparison.
++ }
++
++ if (Arrays.equals(tempChar, secondTempChar) == false) {
++ return new ErrorState(theConsole, MESSAGES.passwordMisMatch(), this);
++ }
++ stateValues.setPassword(tempChar);
++
++ if (!stateValues.isManagement()) {
++ theConsole.printf(MESSAGES.rolesPrompt());
++ String userRoles = stateValues.getKnownRoles().get(stateValues.getUserName());
++ stateValues.setRoles(theConsole.readLine("[%1$2s]: ", (userRoles == null?"":userRoles)));
++ }
++ }
++
++ return continuingState;
++
++ }
++}
++
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFileFinder.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFileFinder.java
+new file mode 100644
+index 0000000..22f57f3
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFileFinder.java
+@@ -0,0 +1,190 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++/**
++ * Describe the purpose
++ *
++ * @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++ */
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++import org.jboss.as.domain.management.security.PropertiesFileLoader;
++import org.jboss.msc.service.StartException;
++
++import java.io.Closeable;
++import java.io.File;
++import java.io.FileInputStream;
++import java.io.IOException;
++import java.io.InputStreamReader;
++import java.nio.charset.Charset;
++import java.util.ArrayList;
++import java.util.HashMap;
++import java.util.HashSet;
++import java.util.List;
++import java.util.Map;
++import java.util.Properties;
++import java.util.Set;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.MGMT_USERS_PROPERTIES;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.APPLICATION_USERS_PROPERTIES;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.APPLICATION_ROLES_PROPERTIES;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.SERVER_CONFIG_DIR;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.SERVER_BASE_DIR;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.DOMAIN_BASE_DIR;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.DOMAIN_CONFIG_DIR;
++
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * The first state executed, responsible for searching for the relevant properties files.
++ */
++public class PropertyFileFinder implements State {
++
++ private ConsoleWrapper theConsole;
++ private final StateValues stateValues;
++
++ public PropertyFileFinder(ConsoleWrapper theConsole,final StateValues stateValues) {
++ this.theConsole = theConsole;
++ this.stateValues = stateValues;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ @Override
++ public State execute() {
++ stateValues.setKnownRoles(new HashMap<String, String>());
++ String jbossHome = System.getenv("JBOSS_HOME");
++ if (jbossHome == null) {
++ return new ErrorState(theConsole, MESSAGES.jbossHomeNotSet(), null, stateValues);
++ }
++
++ List<File> foundFiles = new ArrayList<File>(2);
++ final String fileName = stateValues.isManagement() ? MGMT_USERS_PROPERTIES : APPLICATION_USERS_PROPERTIES;
++ if (!findFiles(jbossHome, foundFiles, fileName)) {
++ return new ErrorState(theConsole, MESSAGES.propertiesFileNotFound(fileName), null, stateValues);
++ }
++ if (!stateValues.isManagement()) {
++ List<File> foundRoleFiles = new ArrayList<File>(2);
++ if (!findFiles(jbossHome, foundRoleFiles, APPLICATION_ROLES_PROPERTIES)) {
++ return new ErrorState(theConsole, MESSAGES.propertiesFileNotFound(APPLICATION_ROLES_PROPERTIES), null, stateValues);
++ }
++ stateValues.setRoleFiles(foundRoleFiles);
++ try {
++ stateValues.setKnownRoles(loadAllRoles(foundRoleFiles));
++ } catch (Exception e) {
++ return new ErrorState(theConsole, MESSAGES.propertiesFileNotFound(APPLICATION_ROLES_PROPERTIES), null, stateValues);
++ }
++ }
++
++ stateValues.setPropertiesFiles(foundFiles);
++
++ Set<String> foundUsers = new HashSet<String>();
++ for (File current : stateValues.getPropertiesFiles()) {
++ try {
++ foundUsers.addAll(loadUserNames(current));
++ } catch (IOException e) {
++ return new ErrorState(theConsole, MESSAGES.unableToLoadUsers(current.getAbsolutePath(), e.getMessage()), null, stateValues);
++ }
++ }
++ stateValues.setKnownUsers(foundUsers);
++
++ if (stateValues == null) {
++ return new PromptNewUserState(theConsole);
++ } else {
++ return new PromptNewUserState(theConsole, stateValues);
++ }
++ }
++
++ private Map<String,String> loadAllRoles(List<File> foundRoleFiles) throws StartException, IOException {
++ Map<String, String> loadedRoles = new HashMap<String, String>();
++ for (File file : foundRoleFiles) {
++ PropertiesFileLoader propertiesLoad = null;
++ try {
++ propertiesLoad = new UserPropertiesFileHandler(file.getCanonicalPath());
++ propertiesLoad.start(null);
++ loadedRoles.putAll((Map) propertiesLoad.getProperties());
++ } finally {
++ if (propertiesLoad!=null) {
++ propertiesLoad.stop(null);
++ }
++ }
++ }
++ return loadedRoles;
++ }
++
++ private boolean findFiles(final String jbossHome, final List<File> foundFiles, final String fileName) {
++
++ File standaloneProps = buildFilePath(jbossHome, SERVER_CONFIG_DIR, SERVER_BASE_DIR, "standalone", fileName);
++ if (standaloneProps.exists()) {
++ foundFiles.add(standaloneProps);
++ }
++ File domainProps = buildFilePath(jbossHome, DOMAIN_CONFIG_DIR, DOMAIN_BASE_DIR, "domain", fileName);
++ if (domainProps.exists()) {
++ foundFiles.add(domainProps);
++ }
++
++ if (foundFiles.size() == 0) {
++ return false;
++ }
++ return true;
++ }
++
++ private File buildFilePath(final String jbossHome, final String serverConfigDirPropertyName,
++ final String serverBaseDirPropertyName, final String defaultBaseDir, final String fileName) {
++
++ String configDirConfiguredPath = System.getProperty(serverConfigDirPropertyName);
++ File configDir = configDirConfiguredPath != null ? new File(configDirConfiguredPath) : null;
++ if(configDir == null) {
++ String baseDirConfiguredPath = System.getProperty(serverBaseDirPropertyName);
++ File baseDir = baseDirConfiguredPath != null ? new File(baseDirConfiguredPath) : new File(jbossHome, defaultBaseDir);
++ configDir = new File(baseDir, "configuration");
++ }
++ return new File(configDir, fileName);
++ }
++
++ private Set<String> loadUserNames(final File file) throws IOException {
++
++ InputStreamReader fis = null;
++ try {
++ fis = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
++ Properties tempProps = new Properties();
++ tempProps.load(fis);
++
++ return tempProps.stringPropertyNames();
++ } finally {
++ safeClose(fis);
++ }
++
++ }
++
++ private static void safeClose(Closeable c) {
++ if (c != null) {
++ try {
++ c.close();
++ } catch (IOException e) {
++ }
++ }
++ }
++
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFilePrompt.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFilePrompt.java
+new file mode 100644
+index 0000000..df3bbed
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/PropertyFilePrompt.java
+@@ -0,0 +1,104 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.AddPropertiesUser;
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.DEFAULT_MANAGEMENT_REALM;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.DEFAULT_APPLICATION_REALM;
++
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++* Describe the purpose
++*
++* @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++*/
++public class PropertyFilePrompt implements State {
++
++ private static final int MANAGEMENT = 0;
++ private static final int APPLICATION = 1;
++ private static final int INVALID = 2;
++
++ private ConsoleWrapper theConsole;
++
++ public PropertyFilePrompt(ConsoleWrapper theConsole) {
++ this.theConsole = theConsole;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ @Override
++ public State execute() {
++ StateValues stateValues = new StateValues();
++
++ theConsole.printf(AddPropertiesUser.NEW_LINE);
++ theConsole.printf(MESSAGES.filePrompt());
++ theConsole.printf(AddPropertiesUser.NEW_LINE);
++
++ while (true) {
++ String temp = theConsole.readLine("(a): ");
++ if (temp == null) {
++ /*
++ * This will return user to the command prompt so add a new line to ensure the command prompt is on the next
++ * line.
++ */
++ theConsole.printf(AddPropertiesUser.NEW_LINE);
++ return null;
++ }
++
++ if (temp.length() > 0) {
++ switch (convertResponse(temp)) {
++ case MANAGEMENT:
++ stateValues.setManagement(true);
++ stateValues.setRealm(DEFAULT_MANAGEMENT_REALM);
++ return new PropertyFileFinder(theConsole, stateValues);
++ case APPLICATION:
++ stateValues.setManagement(false);
++ stateValues.setRealm(DEFAULT_APPLICATION_REALM);
++ return new PropertyFileFinder(theConsole, stateValues);
++ default:
++ return new ErrorState(theConsole, MESSAGES.invalidChoiceResponse(), this);
++ }
++ } else {
++ stateValues.setManagement(true);
++ stateValues.setRealm(DEFAULT_MANAGEMENT_REALM);
++ return new PropertyFileFinder(theConsole, stateValues);
++ }
++ }
++ }
++
++ private int convertResponse(final String response) {
++ String temp = response.toLowerCase();
++ if ("A".equals(temp) || "a".equals(temp)) {
++ return MANAGEMENT;
++ }
++
++ if ("B".equals(temp) || "b".equals(temp)) {
++ return APPLICATION;
++ }
++
++ return INVALID;
++ }
++
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/State.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/State.java
+new file mode 100644
+index 0000000..5095ab3
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/State.java
+@@ -0,0 +1,34 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++/**
++ * Describe the purpose
++ *
++ * @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++ */
++public interface State {
++
++ State execute();
++
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/StateValues.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/StateValues.java
+new file mode 100644
+index 0000000..27cfdff
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/StateValues.java
+@@ -0,0 +1,142 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.AddPropertiesUser;
++
++import java.io.File;
++import java.util.List;
++import java.util.Map;
++import java.util.Set;
++
++/**
++* Place holder object to pass between the state
++*
++* @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++*/
++public class StateValues {
++ private AddPropertiesUser.Interactiveness howInteractive = AddPropertiesUser.Interactiveness.INTERACTIVE;
++ private String realm;
++ private String userName;
++ private char[] password;
++ private boolean management;
++ private String roles;
++ private boolean existingUser = false;
++ private List<File> propertiesFiles;
++ private List<File> roleFiles;
++ private Set<String> knownUsers;
++ private Map<String,String> knownRoles;
++
++ public boolean isSilentOrNonInteractive() {
++ return (howInteractive == AddPropertiesUser.Interactiveness.NON_INTERACTIVE) || isSilent();
++ }
++
++ public void setHowInteractive(AddPropertiesUser.Interactiveness howInteractive) {
++ this.howInteractive = howInteractive;
++ }
++
++
++ public boolean isSilent() {
++ return (howInteractive == AddPropertiesUser.Interactiveness.SILENT);
++ }
++
++ public boolean isExistingUser() {
++ return existingUser;
++ }
++
++ public void setExistingUser(boolean existingUser) {
++ this.existingUser = existingUser;
++ }
++
++ public String getRealm() {
++ return realm;
++ }
++
++ public void setRealm(String realm) {
++ this.realm = realm;
++ }
++
++ public String getUserName() {
++ return userName;
++ }
++
++ public void setUserName(String userName) {
++ this.userName = userName;
++ }
++
++ public char[] getPassword() {
++ return password;
++ }
++
++ public void setPassword(char[] password) {
++ this.password = password;
++ }
++
++ public boolean isManagement() {
++ return management;
++ }
++
++ public void setManagement(boolean management) {
++ this.management = management;
++ }
++
++ public String getRoles() {
++ return roles;
++ }
++
++ public void setRoles(String roles) {
++ this.roles = roles;
++ }
++
++ public List<File> getPropertiesFiles() {
++ return propertiesFiles;
++ }
++
++ public void setPropertiesFiles(List<File> propertiesFiles) {
++ this.propertiesFiles = propertiesFiles;
++ }
++
++ public List<File> getRoleFiles() {
++ return roleFiles;
++ }
++
++ public void setRoleFiles(List<File> roleFiles) {
++ this.roleFiles = roleFiles;
++ }
++
++ public Set<String> getKnownUsers() {
++ return knownUsers;
++ }
++
++ public void setKnownUsers(Set<String> knownUsers) {
++ this.knownUsers = knownUsers;
++ }
++
++ public Map<String, String> getKnownRoles() {
++ return knownRoles;
++ }
++
++ public void setKnownRoles(Map<String, String> knownRoles) {
++ this.knownRoles = knownRoles;
++ }
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdatePropertiesHandler.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdatePropertiesHandler.java
+new file mode 100644
+index 0000000..bbe8bb0
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdatePropertiesHandler.java
+@@ -0,0 +1,111 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++import org.jboss.sasl.util.UsernamePasswordHashUtil;
++
++import java.io.File;
++import java.io.IOException;
++import java.security.NoSuchAlgorithmException;
++
++import static org.jboss.as.domain.management.security.AddPropertiesUser.NEW_LINE;
++
++public abstract class UpdatePropertiesHandler {
++
++ private ConsoleWrapper theConsole;
++
++ public UpdatePropertiesHandler(ConsoleWrapper theConsole) {
++ this.theConsole = theConsole;
++ }
++
++ /**
++ * Implement the persistence handler for storing the properties
++ */
++ abstract void persist(String[] entry, File file) throws IOException;
++
++ /**
++ * Customize message for update or add users
++ * @param fileName - the filename of the updated property file;
++ * @return the console message that should be present to the user
++ */
++ abstract String consoleUserMessage(String fileName);
++
++ /**
++ * Customize message for update or add roles
++ * @param fileName - the filename of the updated property file;
++ * @return the console message that should be present to the user
++ */
++ abstract String consoleRolesMessage(String fileName);
++
++ /**
++ * Customize error message for update or add users roles / properties
++ * @param fileName - the filename of the updated property file;
++ * @return the console message that should be present to the user
++ */
++ abstract String errorMessage(String fileName, Throwable e);
++
++ State update(StateValues stateValues) {
++ String[] entry = new String[2];
++
++ try {
++ String hash = new UsernamePasswordHashUtil().generateHashedHexURP(stateValues.getUserName(), stateValues.getRealm(),
++ stateValues.getPassword());
++ entry[0] = stateValues.getUserName();
++ entry[1] = hash;
++ } catch (NoSuchAlgorithmException e) {
++ return new ErrorState(theConsole, e.getMessage(), null, stateValues);
++ }
++
++ for (File current : stateValues.getPropertiesFiles()) {
++ try {
++ persist(entry, current);
++ if (stateValues.isSilent() == false) {
++ theConsole.printf(consoleUserMessage(current.getCanonicalPath()));
++ theConsole.printf(NEW_LINE);
++ }
++ } catch (Exception e) {
++ return new ErrorState(theConsole, errorMessage(current.getAbsolutePath(), e), null, stateValues);
++ }
++ }
++
++ if (!stateValues.isManagement() && stateValues.getRoles() != null) {
++ for (final File current : stateValues.getRoleFiles()) {
++ String[] role = {stateValues.getUserName(), stateValues.getRoles()};
++ try {
++ persist(role, current);
++ if (stateValues.isSilent() == false) {
++ theConsole.printf(consoleRolesMessage(current.getCanonicalPath()));
++ theConsole.printf(NEW_LINE);
++ }
++ } catch (IOException e) {
++ return new ErrorState(theConsole, errorMessage(current.getAbsolutePath(), e), null, stateValues);
++ }
++ }
++ }
++
++ return null;
++ }
++
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdateUser.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdateUser.java
+new file mode 100644
+index 0000000..d652995
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UpdateUser.java
+@@ -0,0 +1,88 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++import org.jboss.msc.service.StartException;
++
++import java.io.File;
++import java.io.IOException;
++import java.util.Properties;
++
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * Describe the purpose
++ *
++ * @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++ */
++public class UpdateUser extends UpdatePropertiesHandler implements State {
++
++ private final StateValues stateValues;
++
++ public UpdateUser(ConsoleWrapper theConsole,final StateValues stateValues) {
++ super(theConsole);
++ this.stateValues = stateValues;
++ }
++
++ @Override
++ public State execute() {
++ /*
++ * At this point the files have been written and confirmation passed back so nothing else to do.
++ */
++ return update(stateValues);
++ }
++
++ @Override
++ void persist(String[] entry, File file) throws IOException {
++ UserPropertiesFileHandler propertiesHandler = new UserPropertiesFileHandler(file.getAbsolutePath());
++ try {
++ propertiesHandler.start(null);
++ Properties prob = propertiesHandler.getProperties();
++ prob.setProperty(entry[0], entry[1]);
++ propertiesHandler.persistProperties();
++ } catch (StartException e) {
++ throw new IllegalStateException(MESSAGES.unableToUpdateUser(file.getAbsolutePath(), e.getMessage()));
++ } finally {
++ propertiesHandler.stop(null);
++ }
++
++ }
++
++ @Override
++ String consoleUserMessage(String fileName) {
++ return MESSAGES.updateUser(stateValues.getUserName(), fileName);
++ }
++
++ @Override
++ String consoleRolesMessage(String fileName) {
++ return MESSAGES.updatedRoles(stateValues.getUserName(), stateValues.getRoles(), fileName);
++ }
++
++ @Override
++ String errorMessage(String fileName, Throwable e) {
++ return MESSAGES.unableToUpdateUser(fileName, e.getMessage());
++ }
++}
++
++
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UserPropertiesFileHandler.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UserPropertiesFileHandler.java
+new file mode 100644
+index 0000000..a3fb0ca
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/UserPropertiesFileHandler.java
+@@ -0,0 +1,38 @@
++/*
++ * 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.
++ */
++
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.PropertiesFileLoader;
++
++/**
++* Property file handler for user properties and roles
++*
++* @author <a href="mailto:flemming.harms at gmail.com">Flemming Harms</a>
++*/
++class UserPropertiesFileHandler extends PropertiesFileLoader {
++
++ UserPropertiesFileHandler(final String path) {
++ super(path);
++ }
++}
+diff --git a/domain-management/src/main/java/org/jboss/as/domain/management/security/state/WeakCheckState.java b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/WeakCheckState.java
+new file mode 100644
+index 0000000..4c7d094
+--- /dev/null
++++ b/domain-management/src/main/java/org/jboss/as/domain/management/security/state/WeakCheckState.java
+@@ -0,0 +1,90 @@
++/*
++ * JBoss, Home of Professional Open Source.
++ * Copyright 2011, Red Hat, Inc., and individual contributors
++ * as indicated by the @author tags. See the copyright.txt file in the
++ * distribution for a full listing of individual contributors.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++
++package org.jboss.as.domain.management.security.state;
++
++import org.jboss.as.domain.management.security.ConsoleWrapper;
++
++import java.util.Arrays;
++import static org.jboss.as.domain.management.security.AddPropertiesUser.BAD_USER_NAMES;
++import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
++
++/**
++ * State to check the strength of the stateValues selected.
++ * <p/>
++ * TODO - Currently only very basic checks are performed, this could be updated to perform additional password strength
++ * checks.
++ */
++public class WeakCheckState implements State {
++
++ private ConsoleWrapper theConsole;
++ private StateValues stateValues;
++ private static char[] VALID_PUNCTUATION = {'.', '@', '\\', '=', ',','/'};
++
++ public WeakCheckState(ConsoleWrapper theConsole,StateValues stateValues) {
++ this.theConsole = theConsole;
++ this.stateValues = stateValues;
++ if (theConsole.getConsole() == null) {
++ throw MESSAGES.noConsoleAvailable();
++ }
++ }
++
++ private boolean isValidPunctuation(char currentChar) {
++ Arrays.sort(VALID_PUNCTUATION);
++ return (Arrays.binarySearch(VALID_PUNCTUATION,currentChar) >= 0);
++ }
++
++ @Override
++ public State execute() {
++ State retryState = stateValues.isSilentOrNonInteractive() ? null : new PromptNewUserState(theConsole, stateValues);
++
++ if (Arrays.equals(stateValues.getUserName().toCharArray(), stateValues.getPassword())) {
++ return new ErrorState(theConsole, MESSAGES.usernamePasswordMatch(), retryState);
++ }
++
++ for (char currentChar : stateValues.getUserName().toCharArray()) {
++ if ((!isValidPunctuation(currentChar)) && (Character.isLetter(currentChar) || Character.isDigit(currentChar)) == false) {
++ return new ErrorState(theConsole, MESSAGES.usernameNotAlphaNumeric(), retryState);
++ }
++ }
++
++ boolean weakUserName = false;
++ for (String current : BAD_USER_NAMES) {
++ if (current.equals(stateValues.getUserName().toLowerCase())) {
++ weakUserName = true;
++ break;
++ }
++ }
++
++ State continuingState = new DuplicateUserCheckState(theConsole, stateValues);
++ if (weakUserName && stateValues.isSilentOrNonInteractive() == false) {
++ String message = MESSAGES.usernameEasyToGuess(stateValues.getUserName());
++ String prompt = MESSAGES.sureToAddUser(stateValues.getUserName());
++ State noState = new PromptNewUserState(theConsole, stateValues);
++
++ return new ConfirmationChoice(theConsole,message, prompt, continuingState, noState);
++ }
++
++ return continuingState;
++ }
++
++}
+\ No newline at end of file
+--
+1.7.10
+
diff --git a/jboss-as-cp.sh b/jboss-as-cp.sh
new file mode 100755
index 0000000..c8d1e18
--- /dev/null
+++ b/jboss-as-cp.sh
@@ -0,0 +1,59 @@
+#/bin/sh
+
+usage()
+{
+cat << EOF
+usage: $0 options
+
+Makes possible to run JBoss AS in different directory by creating the structure and copying required configuration files.
+
+OPTIONS:
+ -h Show this message
+ -c JBoss AS configuration xml file (see \$JBOSS_HOME/docs/examples/configs/), default: standalone-web.xml
+ -l Location where the directory structure should be created (required)
+EOF
+}
+
+STANDALONE_XML="standalone-web.xml"
+
+while getopts “hcl:” OPTION
+do
+ case $OPTION in
+ h)
+ usage
+ exit 1
+ ;;
+ c)
+ STANDALONE_XML=$OPTARG
+ ;;
+ l)
+ LOCATION=$OPTARG
+ ;;
+ ?)
+ usage
+ exit
+ ;;
+ esac
+done
+
+if [[ -z $LOCATION ]]
+then
+ usage
+ exit 1
+fi
+
+if [ "x$JBOSS_HOME" = "x" ]; then
+ JBOSS_HOME="/usr/share/jboss-as"
+fi
+
+mkdir -p ${LOCATION}/{data,deployments,log,tmp,configuration}
+
+cp $JBOSS_HOME/docs/examples/configs/$STANDALONE_XML ${LOCATION}/configuration/
+cp $JBOSS_HOME/docs/examples/properties/logging.properties ${LOCATION}/configuration/
+cp $JBOSS_HOME/docs/examples/properties/mgmt-users.properties ${LOCATION}/configuration/
+
+# Make sure the mgmt-users.properties file has correct permissions!
+chmod 600 ${LOCATION}/configuration/mgmt-users.properties
+
+echo -e "Directory ${LOCATION} ws prepared to launch JBoss AS!\n\nYou can now boot your server: JBOSS_BASE_DIR=${LOCATION} ${JBOSS_HOME}/bin/standalone.sh -c ${STANDALONE_XML}"
+
diff --git a/jboss-as.spec b/jboss-as.spec
index 6c40efe..14768c4 100644
--- a/jboss-as.spec
+++ b/jboss-as.spec
@@ -2,6 +2,8 @@
%global namedversion %{version}%{?namedreltag}
%global cachedir %{_var}/cache/%{name}
+%global libdir %{_var}/lib/%{name}
+%global rundir %{_var}/run/%{name}
%global homedir %{_datadir}/%{name}
%global bindir %{homedir}/bin
%global logdir %{_var}/log/%{name}
@@ -9,11 +11,11 @@
%global jbuid 185
-%global modules connector controller-client controller deployment-repository deployment-scanner domain-management ee ejb3 embedded jmx logging naming network platform-mbean process-controller protocol remoting security server threads transactions web weld
+%global modules cli connector controller-client controller deployment-repository deployment-scanner domain-management ee ejb3 embedded jmx logging naming network platform-mbean process-controller protocol remoting security server threads transactions web weld
Name: jboss-as
Version: 7.1.0
-Release: 2%{?dist}
+Release: 3%{?dist}
Summary: JBoss Application Server
Group: System Environment/Daemons
License: LGPLv2 and ASL 2.0
@@ -25,6 +27,9 @@ URL: http://www.jboss.org/jbossas
# tar -cJf jboss-as-7.1.0.Final-CLEAN.tar.xz jboss-as-7.1.0.Final
Source0: jboss-as-%{namedversion}-CLEAN.tar.xz
+# Makes possible to run JBoss AS in different directory by creating the structure and copying required configuration files
+Source1: jboss-as-cp.sh
+
Patch0: 0001-Disable-checkstyle.patch
Patch1: 0002-Fix-initd-script.patch
Patch2: 0003-Build-additional-modules.patch
@@ -70,6 +75,15 @@ Patch40: 0041-AS7-3921-Upgrade-to-Remoting-JMX-1.0.2-including-swi.patc
Patch41: 0042-Added-standalone-web.xml-example-configuration.-Use-.patch
Patch42: 0043-Add-systemd-files-re-arrange-directory-with-init-scr.patch
Patch43: 0044-Fixed-systemd-service-file.patch
+Patch44: 0045-Added-jboss-as-cli-module.patch
+Patch45: 0046-Fix-JBOSS_HOME-when-jboss-cli.sh-is-executed-through.patch
+Patch46: 0047-Simplified-systemd-files.patch
+Patch47: 0048-AS7-3800-JBOSS_BASE_DIR-is-checked-in-standalone.sh-.patch
+Patch48: 0049-Added-domain-add-user-module.patch
+Patch49: 0050-Discard-logs-from-systemd-service-we-don-t-need-dupl.patch
+Patch50: 0051-Changed-the-systemd-config-file-location-we-want-to-.patch
+Patch51: 0052-Remove-activation-module.patch
+Patch52: 0053-Use-properties-in-add-user-AS7-module.patch
BuildArch: noarch
@@ -86,7 +100,6 @@ BuildRequires: cdi-api
BuildRequires: dom4j
# TODO: ecj dependency tree is big and ugly...
BuildRequires: ecj
-BuildRequires: geronimo-annotation
BuildRequires: guava
BuildRequires: h2
BuildRequires: hibernate-jpa-2.0-api >= 1.0.1-5
@@ -181,7 +194,6 @@ Requires: dom4j
# TODO: ecj dependency tree is big and ugly...
Requires: ecj
Requires: guava
-Requires: geronimo-annotation
Requires: h2
Requires: hibernate-jpa-2.0-api >= 1.0.1-5
Requires: hibernate-validator >= 4.2.0
@@ -318,6 +330,15 @@ This package contains the API documentation for %{name}.
%patch41 -p1
%patch42 -p1
%patch43 -p1
+%patch44 -p1
+%patch45 -p1
+%patch46 -p1
+%patch47 -p1
+%patch48 -p1
+%patch49 -p1
+%patch50 -p1
+%patch51 -p1
+%patch52 -p1
%build
# We don't have packaged all test dependencies (jboss-test for example)
@@ -329,16 +350,16 @@ install -d -m 755 $RPM_BUILD_ROOT%{_javadir}/%{name}
install -d -m 755 $RPM_BUILD_ROOT%{_javadocdir}/%{name}
install -d -m 755 $RPM_BUILD_ROOT%{homedir}
install -d -m 755 $RPM_BUILD_ROOT%{confdir}
+install -d -m 755 $RPM_BUILD_ROOT%{rundir}
install -d -m 770 $RPM_BUILD_ROOT%{cachedir}/auth
install -d -m 755 $RPM_BUILD_ROOT%{_mavenpomdir}
install -d -m 755 $RPM_BUILD_ROOT%{_unitdir}
-install -d -m 755 $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig
install -d -m 755 $RPM_BUILD_ROOT%{_bindir}
for mode in standalone domain; do
install -d -m 755 $RPM_BUILD_ROOT%{homedir}/${mode}
- install -d -m 755 $RPM_BUILD_ROOT%{cachedir}/${mode}/data
- install -d -m 755 $RPM_BUILD_ROOT%{cachedir}/${mode}/tmp
+ install -d -m 775 $RPM_BUILD_ROOT%{libdir}/${mode}/data
+ install -d -m 755 $RPM_BUILD_ROOT%{cachedir}/${mode}
install -d -m 775 $RPM_BUILD_ROOT%{logdir}/${mode}
done
@@ -399,22 +420,33 @@ pushd build/target/jboss-as-%{namedversion}
find bin/ -type f -name "*.bat" -delete
# Install systemd files
- mv bin/initscripts/jboss-as.conf $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/%{name}
+ mv bin/initscripts/systemd/jboss-as.conf $RPM_BUILD_ROOT%{confdir}/%{name}.conf
mv bin/initscripts/systemd/jboss-as.service $RPM_BUILD_ROOT%{_unitdir}/%{name}.service
- mv bin/initscripts/systemd/jboss-as.sh $RPM_BUILD_ROOT%{_bindir}/%{name}
# We don't need legacy init scripts
rm -rf bin/initscripts
+ # Prepare directory for properties files
+ mkdir docs/examples/properties
+
+ # Copy logging.properties and mgmt-users.properties so we can reuse it later in jboss-as-cp script
+ cp standalone/configuration/logging.properties docs/examples/properties/
+ cp standalone/configuration/mgmt-users.properties docs/examples/properties/
+ # Lower a bit the permissions, so ordinary user can copy it. It's an example file!
+ chmod 644 docs/examples/properties/mgmt-users.properties
+
# standalone
mv standalone/configuration $RPM_BUILD_ROOT%{confdir}/standalone
- mv standalone/deployments $RPM_BUILD_ROOT%{cachedir}/standalone
+ mv standalone/deployments $RPM_BUILD_ROOT%{libdir}/standalone/deployments
+ mv standalone/lib $RPM_BUILD_ROOT%{libdir}/standalone/lib
+ mv standalone/tmp $RPM_BUILD_ROOT%{cachedir}/standalone/tmp
# Install standalone-web.xml
cp docs/examples/configs/standalone-web.xml $RPM_BUILD_ROOT%{confdir}/standalone/standalone-web.xml
# domain
mv domain/configuration $RPM_BUILD_ROOT%{confdir}/domain
+ mv domain/tmp $RPM_BUILD_ROOT%{cachedir}/domain/tmp
# Remove all jars from modules directory - we need to symlink them
# TODO temporary with verbose, use -delete afterwards
@@ -426,30 +458,27 @@ pushd build/target/jboss-as-%{namedversion}
mv copyright.txt README.txt LICENSE.txt welcome-content docs bin appclient modules $RPM_BUILD_ROOT%{homedir}
popd
+chmod 775 $RPM_BUILD_ROOT%{libdir}/standalone/deployments
+
pushd $RPM_BUILD_ROOT%{homedir}
# Standalone
- ln -s %{cachedir}/standalone/deployments standalone/deployments
ln -s %{confdir}/standalone standalone/configuration
+ ln -s %{libdir}/standalone/deployments standalone/deployments
+ ln -s %{libdir}/standalone/data standalone/data
+ ln -s %{libdir}/standalone/lib standalone/lib
+ ln -s %{logdir}/standalone standalone/log
+ ln -s %{cachedir}/standalone/tmp standalone/tmp
# Domain
ln -s %{confdir}/domain domain/configuration
+ ln -s %{libdir}/domain/data domain/data
+ ln -s %{logdir}/domain domain/log
+ ln -s %{cachedir}/domain/tmp domain/tmp
# Symlink jboss-modules
ln -s $(build-classpath jboss-modules) jboss-modules.jar
- # Symlinks to log dirs
- ln -s %{logdir}/standalone standalone/log
- ln -s %{logdir}/domain domain/log
-
- # temp dir
- ln -s %{cachedir}/standalone/tmp standalone/tmp
- ln -s %{cachedir}/domain/tmp domain/tmp
-
- # data dir
- ln -s %{cachedir}/standalone/data standalone/data
- ln -s %{cachedir}/domain/data domain/data
-
# auth dir
ln -s %{cachedir}/auth auth
@@ -489,7 +518,8 @@ pushd $RPM_BUILD_ROOT%{homedir}
ln -s $(build-classpath cdi-api) javax/enterprise/api/main/cdi-api.jar
ln -s $(build-classpath ecj) org/jboss/as/web/main/ecj.jar
ln -s $(build-classpath guava) com/google/guava/main/guava.jar
- ln -s $(build-classpath geronimo-validation) javax/validation/api/main/geronimo-validation.jar
+ # TODO this is an UGLY hack, think about removing it at some point!
+ ln -s $(build-classpath bean-validation-api) javax/validation/api/main/geronimo-validation.jar
ln -s $(build-classpath hibernate-validator) org/hibernate/validator/main/hibernate-validator.jar
ln -s $(build-classpath hibernate-jpa-2.0-api) javax/persistence/api/main/hibernate-jpa-2.0-api.jar
@@ -537,7 +567,6 @@ pushd $RPM_BUILD_ROOT%{homedir}
ln -s $(build-classpath jboss-jstl-1.2-api) javax/servlet/jstl/api/main/jboss-jstl-1.2-api.jar
ln -s $(build-classpath jboss-jts/jbossjta) org/jboss/jts/main/jbossjta.jar
ln -s $(build-classpath jboss-jts/jbossjta-integration) org/jboss/jts/integration/main/jbossjta-integration.jar
- ln -s $(build-classpath log4j) org/apache/log4j/main/log4j.jar
ln -s $(build-classpath jboss-logging) org/jboss/logging/main/jboss-logging.jar
ln -s $(build-classpath jboss-logmanager) org/jboss/logmanager/main/jboss-logmanager.jar
ln -s $(build-classpath jboss-logmanager-log4j) org/jboss/logmanager/log4j/main/jboss-logmanager-log4j.jar
@@ -570,7 +599,9 @@ pushd $RPM_BUILD_ROOT%{homedir}
ln -s $(build-classpath jboss-vfs) org/jboss/vfs/main/jboss-vfs.jar
ln -s $(build-classpath jboss-web) org/jboss/as/web/main/jboss-web.jar
ln -s $(build-classpath jgroups) org/jgroups/main/jgroups.jar
+ ln -s $(build-classpath jline) jline/main/jline.jar
ln -s $(build-classpath joda-time) org/joda/time/main/joda-time.jar
+ ln -s $(build-classpath log4j) org/apache/log4j/main/log4j.jar
ln -s $(build-classpath mojarra/jsf-impl) com/sun/jsf-impl/main/jsf-impl.jar
ln -s $(build-classpath picketbox/picketbox) org/picketbox/main/picketbox.jar
ln -s $(build-classpath picketbox/infinispan) org/picketbox/main/infinispan.jar
@@ -591,39 +622,47 @@ pushd $RPM_BUILD_ROOT%{homedir}
popd
popd
+pushd $RPM_BUILD_ROOT%{_bindir}
+ # jboss-cli
+ ln -s %{bindir}/jboss-cli.sh jboss-cli
+
+ install -m 755 %{SOURCE1} jboss-as-cp
+popd
+
%pre
# Add jboss-as user and group
getent group %{name} >/dev/null || groupadd -r %{name}
getent passwd %{name} >/dev/null || \
useradd -c "JBoss AS" -u %{jbuid} -g %{name} -s /bin/nologin -r -d %{homedir} %{name}
+exit 0
%files
%{homedir}/appclient
%dir %{bindir}
%{bindir}/*.conf
%{bindir}/*.sh
-%{_bindir}/%{name}
+%{_bindir}
%{homedir}/auth
%{homedir}/domain
%{homedir}/standalone
%{homedir}/modules
%{homedir}/welcome-content
%{homedir}/jboss-modules.jar
-%{cachedir}/standalone/deployments/README.txt
-%attr(0775,root,jboss-as) %dir %{cachedir}/standalone/data
+%attr(-,root,jboss-as) %{libdir}/standalone
+%attr(-,root,jboss-as) %{libdir}/domain
+%attr(0775,root,jboss-as) %dir %{rundir}
%attr(0775,root,jboss-as) %dir %{cachedir}/standalone/tmp
-%attr(0775,root,jboss-as) %dir %{cachedir}/domain/data
%attr(0775,root,jboss-as) %dir %{cachedir}/domain/tmp
-%attr(0700,jboss-as,jboss-as) %dir %{cachedir}/auth
%attr(0770,root,jboss-as) %dir %{logdir}/standalone
%attr(0770,root,jboss-as) %dir %{logdir}/domain
%attr(0775,root,jboss-as) %dir %{confdir}/standalone
%attr(0775,root,jboss-as) %dir %{confdir}/domain
+%attr(0700,jboss-as,jboss-as) %dir %{cachedir}/auth
%attr(0664,jboss-as,jboss-as) %config(noreplace) %{confdir}/standalone/*.properties
%attr(0664,jboss-as,jboss-as) %config(noreplace) %{confdir}/standalone/*.xml
%attr(0664,jboss-as,jboss-as) %config(noreplace) %{confdir}/domain/*.properties
%attr(0664,jboss-as,jboss-as) %config(noreplace) %{confdir}/domain/*.xml
-%config(noreplace) %{_sysconfdir}/sysconfig/%{name}
+%config(noreplace) %{confdir}/%{name}.conf
%{_unitdir}/%{name}.service
%doc %{homedir}/docs
%doc %{homedir}/copyright.txt
@@ -639,6 +678,16 @@ getent passwd %{name} >/dev/null || \
%doc %{homedir}/LICENSE.txt
%changelog
+* Mon Apr 16 2012 Marek Goldmann <mgoldman at redhat.com> 7.1.0-3
+- Simplified systemd files
+- Added jboss-as-cli module
+- Make it possible to run as different user in different direcotry by changing JBOSS_BASE_DIR
+- Fixed issues with using add-user.sh script
+- Changed validation API jar to bean-validation
+- Added jboss-as-cp script to be able to use JBoss AS from different dir as different user
+- Removed activation AS7 module - it's already in JDK
+- Make it possible to add a user also when JBoss AS is run from different directory
+
* Wed Apr 04 2012 Marek Goldmann <mgoldman at redhat.com> 7.1.0-2
- Fixed rpmlint issues
- Fixed license
More information about the scm-commits
mailing list