diff --git a/plugins/pom.xml b/plugins/pom.xml
index d7e8debbf02..c5d3a2c9b78 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -54,6 +54,7 @@
user-authenticators/md5
user-authenticators/plain-text
user-authenticators/sha256salted
+ user-authenticators/sha513salted
network-elements/dns-notifier
storage/image/s3
storage/volume/solidfire
diff --git a/plugins/user-authenticators/sha512salted/pom.xml b/plugins/user-authenticators/sha512salted/pom.xml
new file mode 100644
index 00000000000..8ff1454888f
--- /dev/null
+++ b/plugins/user-authenticators/sha512salted/pom.xml
@@ -0,0 +1,29 @@
+
+
+ 4.0.0
+ cloud-plugin-user-authenticator-sha512salted
+ Apache CloudStack Plugin - User Authenticator SHA512 Salted
+
+ org.apache.cloudstack
+ cloudstack-plugins
+ 4.2.0-SNAPSHOT
+ ../../pom.xml
+
+
diff --git a/plugins/user-authenticators/sha512salted/src/com/cloud/server/auth/SHA512SaltedUserAuthenticator.java b/plugins/user-authenticators/sha512salted/src/com/cloud/server/auth/SHA512SaltedUserAuthenticator.java
new file mode 100644
index 00000000000..abb38c1a390
--- /dev/null
+++ b/plugins/user-authenticators/sha512salted/src/com/cloud/server/auth/SHA512SaltedUserAuthenticator.java
@@ -0,0 +1,120 @@
+// 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.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+import org.bouncycastle.util.encoders.Base64;
+
+import com.cloud.user.UserAccount;
+import com.cloud.user.dao.UserAccountDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Local(value={UserAuthenticator.class})
+public class SHA512SaltedUserAuthenticator extends DefaultUserAuthenticator {
+ public static final Logger s_logger = Logger.getLogger(SHA512SaltedUserAuthenticator.class);
+
+ @Inject
+ private UserAccountDao _userAccountDao;
+ private static int s_saltlen = 20;
+
+ @Override
+ public boolean configure(String name, Map 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 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-512");
+ md.update(hashSource);
+ byte[] digest = md.digest();
+
+ return new String(Base64.encode(digest));
+ }
+}
diff --git a/plugins/user-authenticators/sha512salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java b/plugins/user-authenticators/sha512salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
new file mode 100644
index 00000000000..c4c82e903ce
--- /dev/null
+++ b/plugins/user-authenticators/sha512salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
@@ -0,0 +1,63 @@
+// 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 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.SHA512SaltedUserAuthenticator;
+
+public class AuthenticatorTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @Test
+ public void testEncode() throws UnsupportedEncodingException, NoSuchAlgorithmException {
+ SHA512SaltedUserAuthenticator authenticator =
+ new SHA512SaltedUserAuthenticator();
+
+ try {
+ authenticator.configure("SHA512", Collections.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);
+
+ }
+
+}