You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by hu...@apache.org on 2012/10/30 13:02:54 UTC

git commit: Summary: Make the authenticator responsible for encoding the password and add a SHA256 salted authenticator

Updated Branches:
  refs/heads/master 07d555db3 -> bd58ceccd


Summary: Make the authenticator responsible for encoding the password and add a SHA256 salted authenticator

The authenticators now have an encode function that cloudstack will use to encode the user supplied password before storing it in the database. This makes it easier to add other authenticators with other hashing algorithms. The requires a two step approach to creating the admin account at first start as the authenticators are only present in the management-server component locator.

The SHA256 salted authenticator make use of this new system and adds a hashing algorithm based on SHA256 with a salt. This type of hash is far less susceptible to rainbow table attacks.

To make use of these new features the users password will be sent over the wire just as he typed it and it will be transformed into a hash on the server and compared with the stored password. This means that the hash will not go over the wire anymore.

The default authenticator in components.xml is still set to md5 for backwards compatibility. For new installations the sha256 could be enabled.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/bd58cecc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/bd58cecc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/bd58cecc

Branch: refs/heads/master
Commit: bd58ceccd8d08a2484384a7eef6ef3c681a1e188
Parents: 07d555d
Author: Hugo Trippaers <ht...@schubergphilis.com>
Authored: Mon Oct 29 18:02:34 2012 +0100
Committer: Hugo Trippaers <ht...@schubergphilis.com>
Committed: Tue Oct 30 12:56:56 2012 +0100

----------------------------------------------------------------------
 client/pom.xml                                     |    5 +
 client/tomcatconf/components.xml.in                |    1 +
 plugins/pom.xml                                    |    1 +
 .../cloud/server/auth/LDAPUserAuthenticator.java   |   17 ++
 .../cloud/server/auth/MD5UserAuthenticator.java    |   51 +++---
 .../server/auth/PlainTextUserAuthenticator.java    |    6 +
 plugins/user-authenticators/sha256salted/pom.xml   |   29 ++++
 .../server/auth/SHA256SaltedUserAuthenticator.java |  122 +++++++++++++++
 .../cloud/server/auth/test/AuthenticatorTest.java  |   46 ++++++
 .../com/cloud/server/ConfigurationServerImpl.java  |   30 +---
 server/src/com/cloud/server/ManagementServer.java  |    2 +
 .../src/com/cloud/server/ManagementServerImpl.java |   33 ++++
 .../com/cloud/server/auth/UserAuthenticator.java   |    6 +
 .../src/com/cloud/servlet/CloudStartupServlet.java |    1 +
 server/src/com/cloud/user/AccountManagerImpl.java  |   28 +++-
 ui/scripts/sharedFunctions.js                      |    4 +-
 16 files changed, 331 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index c3a0486..6e13cc7 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -42,6 +42,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-plugin-user-authenticator-sha256salted</artifactId>
+      <version>${project.version}</version>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
       <artifactId>cloud-plugin-network-nvp</artifactId>
       <version>${project.version}</version>
     </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/client/tomcatconf/components.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in
index 2953eb7..5957b61 100755
--- a/client/tomcatconf/components.xml.in
+++ b/client/tomcatconf/components.xml.in
@@ -109,6 +109,7 @@ under the License.
             <adapter name="Basic" class="com.cloud.network.ExteralIpAddressAllocator"/>
         </adapters>
         <adapters key="com.cloud.server.auth.UserAuthenticator">
+            <!-- <adapter name="SHA256SALT" class="com.cloud.server.auth.SHA256SaltedUserAuthenticator"/> -->
             <adapter name="MD5" class="com.cloud.server.auth.MD5UserAuthenticator"/>
             <adapter name="LDAP" class="com.cloud.server.auth.LDAPUserAuthenticator"/>
         </adapters>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index dbdea24..2009302 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -45,6 +45,7 @@
     <module>user-authenticators/ldap</module>
     <module>user-authenticators/md5</module>
     <module>user-authenticators/plain-text</module>
+    <module>user-authenticators/sha256salted</module>
   </modules>
 
   <dependencies>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java
index 7c6e52f..43874f6 100644
--- a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java
+++ b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java
@@ -15,6 +15,8 @@
 //
 package com.cloud.server.auth;
 
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
@@ -31,6 +33,7 @@ import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 
 import org.apache.log4j.Logger;
+import org.bouncycastle.util.encoders.Base64;
 
 import com.cloud.api.ApiConstants.LDAPParams;
 import com.cloud.configuration.Config;
@@ -40,6 +43,7 @@ import com.cloud.user.UserAccount;
 import com.cloud.user.dao.UserAccountDao;
 import com.cloud.utils.component.ComponentLocator;
 import com.cloud.utils.crypt.DBEncryptionUtil;
+import com.cloud.utils.exception.CloudRuntimeException;
 
 
 @Local(value={UserAuthenticator.class})
@@ -159,4 +163,17 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator {
         _userAccountDao = locator.getDao(UserAccountDao.class);
         return true;
     }
+
+	@Override
+	public String encode(String password) {
+		// Password is not used, so set to a random string
+		try {
+			SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
+			byte bytes[] = new byte[20];
+			randomGen.nextBytes(bytes);
+			return Base64.encode(bytes).toString();
+		} catch (NoSuchAlgorithmException e) {
+			throw new CloudRuntimeException("Failed to generate random password",e);
+		}	
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
index f4b6f02..b0cf0b0 100644
--- a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
+++ b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
@@ -15,6 +15,9 @@
 
 package com.cloud.server.auth;
 
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.Map;
 
 import javax.ejb.Local;
@@ -26,6 +29,7 @@ import com.cloud.server.ManagementServer;
 import com.cloud.user.UserAccount;
 import com.cloud.user.dao.UserAccountDao;
 import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.exception.CloudRuntimeException;
 
 /**
  * Simple UserAuthenticator that performs a MD5 hash of the password before 
@@ -49,31 +53,7 @@ public class MD5UserAuthenticator extends DefaultUserAuthenticator {
             return false;
         }
         
-        /**
-        MessageDigest md5;
-        try {
-            md5 = MessageDigest.getInstance("MD5");
-        } catch (NoSuchAlgorithmException e) {
-            throw new CloudRuntimeException("Error", e);
-        }
-        md5.reset();
-        BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
-
-        // make sure our MD5 hash value is 32 digits long...
-        StringBuffer sb = new StringBuffer();
-        String pwStr = pwInt.toString(16);
-        int padding = 32 - pwStr.length();
-        for (int i = 0; i < padding; i++) {
-            sb.append('0');
-        }
-        sb.append(pwStr);
-        **/
-        
-        // Will: The MD5Authenticator is now a straight pass-through comparison of the
-        // the passwords because we will not assume that the password passed in has
-        // already been MD5 hashed.  I am keeping the above code in case this requirement changes
-        // or people need examples of how to MD5 hash passwords in java.
-        if (!user.getPassword().equals(password)) {
+        if (!user.getPassword().equals(encode(password))) {
             s_logger.debug("Password does not match");
             return false;
         }
@@ -87,4 +67,25 @@ public class MD5UserAuthenticator extends DefaultUserAuthenticator {
 		_userAccountDao = locator.getDao(UserAccountDao.class);
 		return true;
 	}
+
+	@Override
+	public String encode(String password) {
+		MessageDigest md5 = null;
+		try {
+			md5 = MessageDigest.getInstance("MD5");
+		} catch (NoSuchAlgorithmException e) {
+			throw new CloudRuntimeException("Unable to hash password", e);
+		}
+
+		md5.reset();
+		BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
+		String pwStr = pwInt.toString(16);
+		int padding = 32 - pwStr.length();
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0; i < padding; i++) {
+		    sb.append('0'); // make sure the MD5 password is 32 digits long
+		}
+		sb.append(pwStr);
+		return sb.toString();
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
index 006daf9..59e12e5 100644
--- a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
+++ b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
@@ -87,4 +87,10 @@ public class PlainTextUserAuthenticator extends DefaultUserAuthenticator {
 		_userAccountDao = locator.getDao(UserAccountDao.class);
 		return true;
 	}
+
+	@Override
+	public String encode(String password) {
+		// Plaintext so no encoding at all
+		return password; 
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/plugins/user-authenticators/sha256salted/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml
new file mode 100644
index 0000000..3f530f7
--- /dev/null
+++ b/plugins/user-authenticators/sha256salted/pom.xml
@@ -0,0 +1,29 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cloud-plugin-user-authenticator-sha256salted</artifactId>
+  <name>Apache CloudStack Plugin - User Authenticator SHA256 Salted</name>
+  <parent>
+    <groupId>org.apache.cloudstack</groupId>
+    <artifactId>cloudstack-plugins</artifactId>
+    <version>4.1.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
new file mode 100644
index 0000000..26c33a5
--- /dev/null
+++ b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
@@ -0,0 +1,122 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.server.auth;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+import org.bouncycastle.util.encoders.Base64;
+
+import com.cloud.server.ManagementServer;
+import com.cloud.servlet.CloudStartupServlet;
+import com.cloud.user.UserAccount;
+import com.cloud.user.dao.UserAccountDao;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Local(value={UserAuthenticator.class})
+public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator {
+	public static final Logger s_logger = Logger.getLogger(SHA256SaltedUserAuthenticator.class);
+	
+	@Inject
+	private UserAccountDao _userAccountDao;
+	private static int s_saltlen = 20;
+
+	public boolean configure(String name, Map<String, Object> params)
+			throws ConfigurationException {
+		super.configure(name, params);
+		return true;
+	}
+	
+	/* (non-Javadoc)
+	 * @see com.cloud.server.auth.UserAuthenticator#authenticate(java.lang.String, java.lang.String, java.lang.Long, java.util.Map)
+	 */
+	@Override
+	public boolean authenticate(String username, String password,
+			Long domainId, Map<String, Object[]> requestParameters) {
+		if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Retrieving user: " + username);
+        }
+        UserAccount user = _userAccountDao.getUserAccount(username, domainId);
+        if (user == null) {
+            s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
+            return false;
+        }
+        
+        try {
+	        String storedPassword[] = user.getPassword().split(":");
+	        if (storedPassword.length != 2) {
+	        	s_logger.warn("The stored password for " + username + " isn't in the right format for this authenticator");
+	        	return false;
+	        }
+	        byte salt[] = Base64.decode(storedPassword[0]);
+	        String hashedPassword = encode(password, salt);
+	        return storedPassword[1].equals(hashedPassword);
+		} catch (NoSuchAlgorithmException e) {
+			throw new CloudRuntimeException("Unable to hash password", e);
+		} catch (UnsupportedEncodingException e) {
+			throw new CloudRuntimeException("Unable to hash password", e);
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see com.cloud.server.auth.UserAuthenticator#encode(java.lang.String)
+	 */
+	@Override
+	public String encode(String password) {
+		// 1. Generate the salt
+		SecureRandom randomGen;
+		try {
+			randomGen = SecureRandom.getInstance("SHA1PRNG");
+		
+			byte salt[] = new byte[s_saltlen];
+			randomGen.nextBytes(salt);
+			
+			String saltString = new String(Base64.encode(salt));
+			String hashString = encode(password, salt);
+			
+			// 3. concatenate the two and return
+			return saltString + ":" + hashString;
+		} catch (NoSuchAlgorithmException e) {
+			throw new CloudRuntimeException("Unable to hash password", e);
+		} catch (UnsupportedEncodingException e) {
+			throw new CloudRuntimeException("Unable to hash password", e);
+		}
+	}
+
+	public String encode(String password, byte[] salt) throws UnsupportedEncodingException, NoSuchAlgorithmException {
+		byte[] passwordBytes = password.getBytes("UTF-8");
+		byte[] hashSource = new byte[passwordBytes.length + s_saltlen];
+		System.arraycopy(passwordBytes, 0, hashSource, 0, passwordBytes.length);
+		System.arraycopy(salt, 0, hashSource, passwordBytes.length, s_saltlen);
+		
+		// 2. Hash the password with the salt
+		MessageDigest md = MessageDigest.getInstance("SHA-256");
+		md.update(hashSource);
+		byte[] digest = md.digest();
+		
+		return new String(Base64.encode(digest));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java b/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
new file mode 100644
index 0000000..cf99024
--- /dev/null
+++ b/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
@@ -0,0 +1,46 @@
+package src.com.cloud.server.auth.test;
+
+import static org.junit.Assert.*;
+
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+
+import javax.naming.ConfigurationException;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.cloud.server.auth.SHA256SaltedUserAuthenticator;
+
+public class AuthenticatorTest {
+
+	@Before
+	public void setUp() throws Exception {
+	}
+
+	@Test
+	public void testEncode() throws UnsupportedEncodingException, NoSuchAlgorithmException {
+		SHA256SaltedUserAuthenticator authenticator = 
+				new SHA256SaltedUserAuthenticator();
+
+		try {
+			authenticator.configure("SHA256", Collections.<String,Object>emptyMap());
+		} catch (ConfigurationException e) {
+			fail(e.toString());
+		}
+		
+		String encodedPassword = authenticator.encode("password");
+        
+		String storedPassword[] = encodedPassword.split(":");
+        assertEquals ("hash must consist of two components", storedPassword.length, 2);
+
+        byte salt[] = Base64.decode(storedPassword[0]);
+        String hashedPassword = authenticator.encode("password", salt);
+        
+        assertEquals("compare hashes", storedPassword[1], hashedPassword);
+
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/server/src/com/cloud/server/ConfigurationServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java
index 3368c9b..904e8c5 100755
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -32,6 +32,7 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -85,6 +86,7 @@ import com.cloud.offerings.NetworkOfferingServiceMapVO;
 import com.cloud.offerings.NetworkOfferingVO;
 import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
+import com.cloud.server.auth.UserAuthenticator;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
@@ -96,6 +98,7 @@ import com.cloud.user.User;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.PasswordGenerator;
 import com.cloud.utils.PropertiesUtil;
+import com.cloud.utils.component.Adapters;
 import com.cloud.utils.component.ComponentLocator;
 import com.cloud.utils.crypt.DBEncryptionUtil;
 import com.cloud.utils.db.DB;
@@ -342,30 +345,13 @@ public class ConfigurationServerImpl implements ConfigurationServer {
         } catch (SQLException ex) {
         }
 
-        // insert admin user
+        // insert admin user, but leave the account disabled until we set a
+        // password with the user authenticator
         long id = 2;
         String username = "admin";
         String firstname = "admin";
         String lastname = "cloud";
-        String password = "password";
-
-        MessageDigest md5 = null;
-        try {
-            md5 = MessageDigest.getInstance("MD5");
-        } catch (NoSuchAlgorithmException e) {
-            return;
-        }
-
-        md5.reset();
-        BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
-        String pwStr = pwInt.toString(16);
-        int padding = 32 - pwStr.length();
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0; i < padding; i++) {
-            sb.append('0'); // make sure the MD5 password is 32 digits long
-        }
-        sb.append(pwStr);
-
+        
         // create an account for the admin user first
         insertSql = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (" + id + ", '" + username + "', '1', '1')";
         txn = Transaction.currentTxn();
@@ -376,8 +362,8 @@ public class ConfigurationServerImpl implements ConfigurationServer {
         }
 
         // now insert the user
-        insertSql = "INSERT INTO `cloud`.`user` (id, username, password, account_id, firstname, lastname, created) " +
-                "VALUES (" + id + ",'" + username + "','" + sb.toString() + "', 2, '" + firstname + "','" + lastname + "',now())";
+        insertSql = "INSERT INTO `cloud`.`user` (id, username, account_id, firstname, lastname, created, state) " +
+                "VALUES (" + id + ",'" + username + "', 2, '" + firstname + "','" + lastname + "',now(), 'disabled')";
 
         txn = Transaction.currentTxn();
         try {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/server/src/com/cloud/server/ManagementServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java
index 473b0ee..91f82f8 100755
--- a/server/src/com/cloud/server/ManagementServer.java
+++ b/server/src/com/cloud/server/ManagementServer.java
@@ -95,4 +95,6 @@ public interface ManagementServer extends ManagementService {
     Pair<List<StoragePoolVO>, Integer> searchForStoragePools(Criteria c);
 
     String getHashKey();
+    
+    public void enableAdminUser(String password);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index a916eb6..117be57 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -177,6 +177,7 @@ import com.cloud.projects.Project.ListProjectResourcesCriteria;
 import com.cloud.projects.ProjectManager;
 import com.cloud.resource.ResourceManager;
 import com.cloud.server.ResourceTag.TaggedResourceType;
+import com.cloud.server.auth.UserAuthenticator;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
@@ -215,7 +216,9 @@ import com.cloud.user.AccountVO;
 import com.cloud.user.SSHKeyPair;
 import com.cloud.user.SSHKeyPairVO;
 import com.cloud.user.User;
+import com.cloud.user.UserAccount;
 import com.cloud.user.UserContext;
+import com.cloud.user.UserVO;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.user.dao.SSHKeyPairDao;
 import com.cloud.user.dao.UserDao;
@@ -338,6 +341,8 @@ public class ManagementServerImpl implements ManagementServer {
     private final StatsCollector _statsCollector;
 
     private final Map<String, Boolean> _availableIdsMap;
+    
+    private Adapters<UserAuthenticator> _userAuthenticators;
 
     private String _hashKey = null;
 
@@ -417,6 +422,11 @@ public class ManagementServerImpl implements ManagementServer {
         for (String id : availableIds) {
             _availableIdsMap.put(id, true);
         }
+        
+        _userAuthenticators = locator.getAdapters(UserAuthenticator.class);
+        if (_userAuthenticators == null || !_userAuthenticators.isSet()) {
+            s_logger.error("Unable to find an user authenticator.");
+        }
     }
 
     protected Map<String, String> getConfigs() {
@@ -3587,5 +3597,28 @@ public class ManagementServerImpl implements ManagementServer {
         }
 
     }
+    
+    public void enableAdminUser(String password) {
+        String encodedPassword = null;
+        
+        UserVO adminUser = _userDao.getUser(2);
+        if (adminUser.getState() == Account.State.disabled) {
+        	// This means its a new account, set the password using the authenticator
+        
+	        for (Enumeration<UserAuthenticator> en = _userAuthenticators.enumeration(); en.hasMoreElements();) {
+	            UserAuthenticator authenticator = en.nextElement();
+	            encodedPassword = authenticator.encode(password);
+	            if (encodedPassword != null) {
+	                break;
+	            }
+	        }
+	        
+	        adminUser.setPassword(encodedPassword);
+	        adminUser.setState(Account.State.enabled);
+	        _userDao.persist(adminUser);
+	        s_logger.info("Admin user enabled");
+        }
+
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/server/src/com/cloud/server/auth/UserAuthenticator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/auth/UserAuthenticator.java b/server/src/com/cloud/server/auth/UserAuthenticator.java
index 725516c..95c4f0e 100644
--- a/server/src/com/cloud/server/auth/UserAuthenticator.java
+++ b/server/src/com/cloud/server/auth/UserAuthenticator.java
@@ -34,4 +34,10 @@ public interface UserAuthenticator extends Adapter {
 	 * @return true if the user has been successfully authenticated, false otherwise
 	 */
 	public boolean authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters);
+	
+	/**
+	 * @param password
+	 * @return the encoded password
+	 */
+	public String encode(String password);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/server/src/com/cloud/servlet/CloudStartupServlet.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/servlet/CloudStartupServlet.java b/server/src/com/cloud/servlet/CloudStartupServlet.java
index c3e5a82..9efb4ea 100755
--- a/server/src/com/cloud/servlet/CloudStartupServlet.java
+++ b/server/src/com/cloud/servlet/CloudStartupServlet.java
@@ -47,6 +47,7 @@ public class CloudStartupServlet extends HttpServlet implements ServletContextLi
 	    	c.persistDefaultValues();
 	    	s_locator = ComponentLocator.getLocator(ManagementServer.Name);
 		    ManagementServer ms = (ManagementServer)ComponentLocator.getComponent(ManagementServer.Name);
+		    ms.enableAdminUser("password");
 		    ApiServer.initApiServer(ms.getApiConfig());
 	    } catch (InvalidParameterValueException ipve) {
 	    	s_logger.error("Exception starting management server ", ipve);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/server/src/com/cloud/user/AccountManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index f1e606e..0def008 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -921,7 +921,18 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
         }
         
         if (password != null) {
-            user.setPassword(password);
+            String encodedPassword = null;
+            for (Enumeration<UserAuthenticator> en = _userAuthenticators.enumeration(); en.hasMoreElements();) {
+                UserAuthenticator authenticator = en.nextElement();
+                encodedPassword = authenticator.encode(password);
+                if (encodedPassword != null) {
+                    break;
+                }
+            }
+            if (encodedPassword == null) {
+            	throw new CloudRuntimeException("Failed to encode password");
+            }
+            user.setPassword(encodedPassword);
         }
         if (email != null) {
             user.setEmail(email);
@@ -1670,7 +1681,20 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
         if (s_logger.isDebugEnabled()) {
             s_logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone);
         }
-        UserVO user = _userDao.persist(new UserVO(accountId, userName, password, firstName, lastName, email, timezone));
+        
+        String encodedPassword = null;
+        for (Enumeration<UserAuthenticator> en = _userAuthenticators.enumeration(); en.hasMoreElements();) {
+            UserAuthenticator authenticator = en.nextElement();
+            encodedPassword = authenticator.encode(password);
+            if (encodedPassword != null) {
+                break;
+            }
+        }
+        if (encodedPassword == null) {
+        	throw new CloudRuntimeException("Failed to encode password");
+        }
+
+        UserVO user = _userDao.persist(new UserVO(accountId, userName, encodedPassword, firstName, lastName, email, timezone));
 
         return user;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bd58cecc/ui/scripts/sharedFunctions.js
----------------------------------------------------------------------
diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js
index 5e187ed..28b3bb9 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -37,8 +37,8 @@ var ERROR_INTERNET_CANNOT_CONNECT = 12029;
 var ERROR_VMOPS_ACCOUNT_ERROR = 531;
 
 // Default password is MD5 hashed.  Set the following variable to false to disable this.
-var md5Hashed = true;
-var md5HashedLogin = true;
+var md5Hashed = false;
+var md5HashedLogin = false;
 
 //page size for API call (e.g."listXXXXXXX&pagesize=N" )
 var pageSize = 20;