Blob Blame History Raw
From a5b1c5e3bb08f46938266b428f65d3b6d6bc1fa7 Mon Sep 17 00:00:00 2001
From: Marek Goldmann <mgoldman@redhat.com>
Date: Mon, 16 Apr 2012 18:23:15 +0200
Subject: [PATCH] Use properties in add-user AS7 module

---
 .../management/DomainManagementMessages.java       |  51 +-
 .../management/security/AddPropertiesUser.java     | 634 ++-------------------
 .../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 +++
 19 files changed, 1603 insertions(+), 615 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/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 c260e79..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
@@ -488,9 +488,54 @@ public interface DomainManagementMessages {
     @Message(id = 15251, value = "Invalid response. (Valid responses are A, a, B, or b)")
     String invalidChoiceResponse();
 
-    /*
-     * Logging IDs 15200 to 15299 are reserved for domain management, the file DomainManagementLogger also contains messages in
-     * this range commencing 15200.
+    /**
+     * 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 405c80c..f58a799 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,27 +22,19 @@
 
 package org.jboss.as.domain.management.security;
 
-import static org.jboss.as.domain.management.DomainManagementMessages.MESSAGES;
+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.BufferedWriter;
 import java.io.Closeable;
-import java.io.Console;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
-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;
 
 /**
  * A command line utility to add new users to the mgmt-users.properties files.
@@ -51,39 +43,49 @@ import org.jboss.sasl.util.UsernamePasswordHashUtil;
  */
 public class AddPropertiesUser {
 
-    private static final String[] BAD_USER_NAMES = {"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 char NEW_LINE_CHAR = '\n';
     private static final char CARRIAGE_RETURN_CHAR = '\r';
 
-    private static final String NEW_LINE = "\n";
-    private static final String SPACE = " ";
+    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;
 
-    private AddPropertiesUser() {
-        if (theConsole == null) {
+
+    protected State nextState;
+
+    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");
 
@@ -91,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) {
         }
     }
@@ -158,538 +160,6 @@ public class AddPropertiesUser {
         }
     }
 
-
-    private class PropertyFilePrompt implements State {
-
-        private static final int MANAGEMENT = 0;
-        private static final int APPLICATION = 1;
-        private static final int INVALID = 2;
-
-        @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 (convertResponse(temp)) {
-                        case MANAGEMENT:
-                            values.management = true;
-                            values.realm = DEFAULT_MANAGEMENT_REALM;
-                            return new PropertyFileFinder(values);
-                        case APPLICATION:
-                            values.management = false;
-                            values.realm = DEFAULT_APPLICATION_REALM;
-                            return new PropertyFileFinder(values);
-                        default:
-                            return new ErrorState(MESSAGES.invalidChoiceResponse(), this);
-                    }
-                } else {
-                    values.management = true;
-                    values.realm = DEFAULT_MANAGEMENT_REALM;
-                    return new PropertyFileFinder(values);
-                }
-            }
-        }
-
-        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;
-        }
-
-    }
-
-    /**
-     * The first state executed, responsible for searching for the relevant 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 : BAD_USER_NAMES) {
-                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 boolean additionalNewLineNeeded(final File file) throws IOException {
-            FileReader fr = null;
-
-            try {
-                fr = new FileReader(file);
-                char lastChar = 0x00;
-                char[] temp = new char[1024];
-
-                int read = -1;
-                while ((read = fr.read(temp)) > 0) {
-                    lastChar = temp[read - 1];
-                }
-                /*
-                 * It is possible that the final line will also have some whitespace - in that case we want
-                 * a new line otherwise the line we add could become indented.
-                 *
-                 * Depending on where the file was last written the character sequence for a new line can vary,
-                 * if we see either of the characters used for a new line as the last character of the last line
-                 * we assume a new line is already present in the file.
-                 */
-                return lastChar != NEW_LINE_CHAR && lastChar != CARRIAGE_RETURN_CHAR;
-            } finally {
-                safeClose(fr);
-            }
-        }
-
-        private void append(final String entry, final File toFile) throws IOException {
-            FileWriter fw = null;
-            BufferedWriter bw = null;
-
-            boolean additionalNewLineNeeded = additionalNewLineNeeded(toFile);
-
-            try {
-                fw = new FileWriter(toFile, true);
-                bw = new BufferedWriter(fw);
-
-                if (additionalNewLineNeeded) {
-                    bw.newLine();
-                }
-
-                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 {
@@ -699,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@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@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@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@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@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@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@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@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.8.3.1