Bug 507854 - Offer option to hash and salt password

* Introduce ESPasswordHashGenerator which is extensible via extension point
* If present super user password will be hashed
* EMFModelUserVerifer will use ESPasswordHashGenerator

Change-Id: I7a99aeaede1ed6a4cb928839b51865040f2361de
Signed-off-by: Johannes Faltermeier <jfaltermeier@eclipsesource.com>
diff --git a/bundles/org.eclipse.emf.emfstore.server/EMFStore Server with ExampleModel.launch b/bundles/org.eclipse.emf.emfstore.server/EMFStore Server with ExampleModel.launch
index 93c88de..06d333f 100644
--- a/bundles/org.eclipse.emf.emfstore.server/EMFStore Server with ExampleModel.launch
+++ b/bundles/org.eclipse.emf.emfstore.server/EMFStore Server with ExampleModel.launch
@@ -1,42 +1,42 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>

-<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">

-<setAttribute key="additional_plugins">

-<setEntry value="org.eclipse.emf.emfstore.internal.examplemodel:0.8.9.M909:default:true"/>

-</setAttribute>

-<booleanAttribute key="append.args" value="true"/>

-<booleanAttribute key="askclear" value="true"/>

-<booleanAttribute key="automaticAdd" value="false"/>

-<booleanAttribute key="automaticValidate" value="false"/>

-<stringAttribute key="bad_container_name" value="/emfstore.launch"/>

-<stringAttribute key="bootstrap" value=""/>

-<stringAttribute key="checked" value="[NONE]"/>

-<booleanAttribute key="clearConfig" value="false"/>

-<booleanAttribute key="clearws" value="false"/>

-<booleanAttribute key="clearwslog" value="false"/>

-<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/EMFStore Server with ExampleModel"/>

-<booleanAttribute key="default" value="false"/>

-<stringAttribute key="featureDefaultLocation" value="workspace"/>

-<stringAttribute key="featurePluginResolution" value="workspace"/>

-<booleanAttribute key="includeOptional" value="true"/>

-<stringAttribute key="location" value="${workspace_loc}/../runtime-org.eclipse.emf.emfstore.server.server"/>

-<listAttribute key="org.eclipse.debug.ui.favoriteGroups">

-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>

-</listAttribute>

-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>

-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>

-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>

-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx524m"/>

-<booleanAttribute key="pde.generated.config" value="false"/>

-<stringAttribute key="pde.version" value="3.3"/>

-<stringAttribute key="product" value="org.eclipse.emf.emfstore.server.server"/>

-<setAttribute key="selected_features"/>

-<stringAttribute key="selected_target_plugins" value="javax.servlet@default:default,org.apache.commons.codec@default:default,org.apache.commons.logging*1.1.1.v201101211721@default:default,org.eclipse.ant.core@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filesystem.win32.x86_64@default:false,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.resources@default:default,org.eclipse.core.runtime.compatibility.registry@default:false,org.eclipse.core.runtime@default:true,org.eclipse.core.variables@default:default,org.eclipse.emf.cdo.ecore.retrofit@default:false,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.servletbridge.extensionbundle@default:false,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true"/>

-<stringAttribute key="selected_workspace_plugins" value="org.eclipse.emf.emfstore.common.model@default:default,org.eclipse.emf.emfstore.common@default:default,org.eclipse.emf.emfstore.examplemodel@default:default,org.eclipse.emf.emfstore.migration@default:default,org.eclipse.emf.emfstore.server.model@default:default,org.eclipse.emf.emfstore.server@default:default"/>

-<booleanAttribute key="show_selected_only" value="false"/>

-<booleanAttribute key="tracing" value="false"/>

-<booleanAttribute key="useCustomFeatures" value="false"/>

-<booleanAttribute key="useDefaultConfig" value="true"/>

-<booleanAttribute key="useDefaultConfigArea" value="true"/>

-<booleanAttribute key="useProduct" value="true"/>

-<booleanAttribute key="usefeatures" value="false"/>

-</launchConfiguration>

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">
+<setAttribute key="additional_plugins">
+<setEntry value="org.eclipse.emf.emfstore.internal.examplemodel:0.8.9.M909:default:true"/>
+</setAttribute>
+<booleanAttribute key="append.args" value="true"/>
+<booleanAttribute key="askclear" value="true"/>
+<booleanAttribute key="automaticAdd" value="false"/>
+<booleanAttribute key="automaticValidate" value="false"/>
+<stringAttribute key="bad_container_name" value="/emfstore.launch"/>
+<stringAttribute key="bootstrap" value=""/>
+<stringAttribute key="checked" value="[NONE]"/>
+<booleanAttribute key="clearConfig" value="false"/>
+<booleanAttribute key="clearws" value="false"/>
+<booleanAttribute key="clearwslog" value="false"/>
+<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/EMFStore Server with ExampleModel"/>
+<booleanAttribute key="default" value="false"/>
+<stringAttribute key="featureDefaultLocation" value="workspace"/>
+<stringAttribute key="featurePluginResolution" value="workspace"/>
+<booleanAttribute key="includeOptional" value="true"/>
+<stringAttribute key="location" value="${workspace_loc}/../runtime-org.eclipse.emf.emfstore.server.server"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx524m"/>
+<booleanAttribute key="pde.generated.config" value="false"/>
+<stringAttribute key="pde.version" value="3.3"/>
+<stringAttribute key="product" value="org.eclipse.emf.emfstore.server.server"/>
+<setAttribute key="selected_features"/>
+<stringAttribute key="selected_target_plugins" value="javax.servlet*3.0.0.v201112011016@default:default,javax.servlet*3.1.0.v201410161800@default:default,javax.xml@default:default,org.apache.commons.codec@default:default,org.apache.commons.logging@default:default,org.eclipse.ant.core@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filesystem.linux.x86_64@default:default,org.eclipse.core.filesystem.win32.x86_64@default:false,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.resources@default:default,org.eclipse.core.runtime@default:true,org.eclipse.core.variables@default:default,org.eclipse.emf.cdo.ecore.retrofit@default:false,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.osgi*3.11.1.v20160708-1632@-1:true,org.eclipse.osgi.services*3.5.100.v20160504-1419@default:default"/>
+<stringAttribute key="selected_workspace_plugins" value="org.eclipse.emf.emfstore.common.model@default:default,org.eclipse.emf.emfstore.common@default:default,org.eclipse.emf.emfstore.examplemodel@default:default,org.eclipse.emf.emfstore.migration@default:default,org.eclipse.emf.emfstore.server.model@default:default,org.eclipse.emf.emfstore.server@default:default"/>
+<booleanAttribute key="show_selected_only" value="false"/>
+<booleanAttribute key="tracing" value="false"/>
+<booleanAttribute key="useCustomFeatures" value="false"/>
+<booleanAttribute key="useDefaultConfig" value="true"/>
+<booleanAttribute key="useDefaultConfigArea" value="true"/>
+<booleanAttribute key="useProduct" value="true"/>
+<booleanAttribute key="usefeatures" value="false"/>
+</launchConfiguration>
diff --git a/bundles/org.eclipse.emf.emfstore.server/schema/accessControl.exsd b/bundles/org.eclipse.emf.emfstore.server/schema/accessControl.exsd
index bcf693d..69cf4b2 100644
--- a/bundles/org.eclipse.emf.emfstore.server/schema/accessControl.exsd
+++ b/bundles/org.eclipse.emf.emfstore.server/schema/accessControl.exsd
@@ -22,6 +22,7 @@
             <element ref="authorizationServiceProvider" minOccurs="0" maxOccurs="1"/>
             <element ref="userVerifierServiceProvider" minOccurs="0" maxOccurs="1"/>
             <element ref="orgUnitProvider" minOccurs="0" maxOccurs="1"/>
+            <element ref="passwordHashGenerator" minOccurs="0" maxOccurs="1"/>
          </sequence>
          <attribute name="point" type="string" use="required">
             <annotation>
@@ -110,6 +111,21 @@
       </complexType>
    </element>
 
+   <element name="passwordHashGenerator">
+      <complexType>
+         <attribute name="passwordHashGeneratorClass" type="string">
+            <annotation>
+               <documentation>
+                  A PasswordHash Generator is able to generate a hash using a newly created salt for a given password. Moreover it is able to verify if a password matches a stored hash/salt.
+               </documentation>
+               <appInfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
    <annotation>
       <appInfo>
          <meta.section type="since"/>
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/EMFStoreController.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/EMFStoreController.java
index e068401..b6d5ed0 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/EMFStoreController.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/EMFStoreController.java
@@ -15,6 +15,8 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -23,6 +25,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Properties;
+import java.util.Scanner;
 import java.util.Set;
 
 import org.eclipse.core.runtime.ILogListener;
@@ -68,6 +71,8 @@
 import org.eclipse.emf.emfstore.internal.server.storage.ServerXMIResourceSetProvider;
 import org.eclipse.emf.emfstore.server.ESDynamicModelProvider;
 import org.eclipse.emf.emfstore.server.ESServerURIUtil;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt;
 import org.eclipse.emf.emfstore.server.exceptions.ESServerInitException;
 import org.eclipse.equinox.app.IApplication;
 import org.eclipse.equinox.app.IApplicationContext;
@@ -147,7 +152,9 @@
 			Messages.EMFStoreController_Could_Not_Copy_Properties_File,
 			Messages.EMFStoreController_Default_Properties_File_Copied);
 
-		initProperties();
+		final Properties properties = initProperties();
+
+		assureSuperUserPasswordIsSet(properties);
 
 		logGeneralInformation();
 
@@ -458,6 +465,73 @@
 		ModelUtil.logInfo(Messages.EMFStoreController_Added_SuperUser + superuser);
 	}
 
+	private void assureSuperUserPasswordIsSet(final Properties properties) {
+
+		final boolean unhashedPasswordWasPresent = properties.containsKey(ServerConfiguration.SUPER_USER_PASSWORD);
+
+		String password = null;
+		if (!unhashedPasswordWasPresent) {
+
+			if (properties.containsKey(ServerConfiguration.SUPER_USER_PASSWORD_HASH) &&
+				properties.containsKey(ServerConfiguration.SUPER_USER_PASSWORD_SALT)) {
+				/* super user password not present but hash and salt -> all is fine */
+				return;
+			}
+
+			/* no password is available in properties -> get password from user */
+			final Scanner scanner = new Scanner(System.in);
+			try {
+				boolean passwordDidNotMatch = true;
+				while (passwordDidNotMatch) {
+					System.out.println(Messages.EMFStoreController_NoSuperUserPasswordPrompt);
+					final String pw1 = scanner.nextLine();
+					System.out.println(Messages.EMFStoreController_EnterSuperUserPasswordAgain);
+					final String pw2 = scanner.nextLine();
+					if (pw1 != null && pw1.equals(pw2)) {
+						password = pw1;
+						passwordDidNotMatch = false;
+					} else {
+						System.out.println(Messages.EMFStoreController_PasswordDidNotMatch);
+					}
+				}
+			} finally {
+				scanner.close();
+			}
+		} else {
+			/* get unhashed password */
+			password = properties.getProperty(ServerConfiguration.SUPER_USER_PASSWORD);
+		}
+
+		/* migrate non hashed password */
+		final ESPasswordHashGenerator passwordHashGenerator = AccessControl.getESPasswordHashGenerator();
+		final File propertyFile = new File(ServerConfiguration.getConfFile());
+		FileOutputStream propertyFileOutputStream = null;
+		try {
+			propertyFileOutputStream = new FileOutputStream(propertyFile);
+			final ESHashAndSalt hashAndSalt = passwordHashGenerator.hashPassword(password);
+			properties.setProperty(ServerConfiguration.SUPER_USER_PASSWORD_SALT, hashAndSalt.getSalt());
+			properties.setProperty(ServerConfiguration.SUPER_USER_PASSWORD_HASH, hashAndSalt.getHash());
+			properties.remove(ServerConfiguration.SUPER_USER_PASSWORD);
+			properties.store(propertyFileOutputStream, ""); //$NON-NLS-1$
+		} catch (final FileNotFoundException ex) {
+			ModelUtil.logWarning(Messages.EMFStoreController_PasswordHashFailFileNotFound, ex);
+		} catch (final IOException ex) {
+			ModelUtil.logWarning(Messages.EMFStoreController_PasswordHashFailIOException, ex);
+		} finally {
+			if (propertyFileOutputStream != null) {
+				try {
+					propertyFileOutputStream.close();
+				} catch (final IOException ex) {
+					ModelUtil.logException(ex);
+				}
+			}
+		}
+
+		if (unhashedPasswordWasPresent) {
+			ServerConfiguration.initUserVerifierMigration();
+		}
+	}
+
 	private Properties initProperties() {
 		final File propertyFile = new File(ServerConfiguration.getConfFile());
 		final Properties properties = new Properties();
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/Messages.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/Messages.java
index 7def488..b461af1 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/Messages.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/Messages.java
@@ -34,11 +34,16 @@
 	public static String EMFStoreController_Default_Properties_File_Copied;
 	public static String EMFStoreController_Dynamic_Model_Loaded;
 	public static String EMFStoreController_EMFStore_Controller_Already_Running;
+	public static String EMFStoreController_EnterSuperUserPasswordAgain;
 	public static String EMFStoreController_Error_During_Migration;
 	public static String EMFStoreController_Failed_To_Copy_Keystore;
 	public static String EMFStoreController_Init_Complete;
 	public static String EMFStoreController_JVM_Max_Memory;
 	public static String EMFStoreController_Keystore_Copied;
+	public static String EMFStoreController_NoSuperUserPasswordPrompt;
+	public static String EMFStoreController_PasswordDidNotMatch;
+	public static String EMFStoreController_PasswordHashFailFileNotFound;
+	public static String EMFStoreController_PasswordHashFailIOException;
 	public static String EMFStoreController_Property_Init_Failed;
 	public static String EMFStoreController_PropertyFile_Read;
 	public static String EMFStoreController_Serve_Forcefully_Stopped;
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/ServerConfiguration.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/ServerConfiguration.java
index a3c1d65..395ff49 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/ServerConfiguration.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/ServerConfiguration.java
@@ -194,6 +194,16 @@
 	public static final String SUPER_USER_PASSWORD = "emfstore.accesscontrol.authentication.superuser.password"; //$NON-NLS-1$
 
 	/**
+	 * Property for the super user's password hash.
+	 */
+	public static final String SUPER_USER_PASSWORD_HASH = "emfstore.accesscontrol.authentication.superuser.password.hash"; //$NON-NLS-1$
+
+	/**
+	 * Property for the super user's password salt.
+	 */
+	public static final String SUPER_USER_PASSWORD_SALT = "emfstore.accesscontrol.authentication.superuser.password.salt"; //$NON-NLS-1$
+
+	/**
 	 * Default super user password.
 	 */
 	public static final String SUPER_USER_PASSWORD_DEFAULT = "super"; //$NON-NLS-1$
@@ -387,6 +397,8 @@
 	private static Boolean useFileBasedChangePackageOnServer;
 	private static Boolean saveProjectStateOnTag;
 
+	private static boolean migrateUserPasswords;
+
 	/**
 	 * Return the server home directory location.
 	 *
@@ -734,4 +746,21 @@
 		}
 		return saveProjectStateOnTag;
 	}
+
+	/**
+	 * Sets {@link #isUserPasswordMigrationRequired()} to <code>true</code>.
+	 */
+	static void initUserVerifierMigration() {
+		ServerConfiguration.migrateUserPasswords = true;
+	}
+
+	/**
+	 *
+	 * @return <code>true</code> if the super user password was migrated from clear text to hashed property. In this
+	 *         case user verifiers should hash their user password as well. <code>false</code> if no migration is
+	 *         needed.
+	 */
+	public static boolean isUserPasswordMigrationRequired() {
+		return ServerConfiguration.migrateUserPasswords;
+	}
 }
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/AccessControl.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/AccessControl.java
index f5e6f58..187e581 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/AccessControl.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/AccessControl.java
@@ -24,6 +24,7 @@
 import org.eclipse.emf.emfstore.server.auth.ESAuthenticationControlType;
 import org.eclipse.emf.emfstore.server.auth.ESAuthorizationService;
 import org.eclipse.emf.emfstore.server.auth.ESOrgUnitResolver;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
 import org.eclipse.emf.emfstore.server.auth.ESSessions;
 import org.eclipse.emf.emfstore.server.model.ESOrgUnitProvider;
 
@@ -41,8 +42,12 @@
 
 	private static final String AUTHORIZATION_SERVICE_CLASS = "authorizationServiceClass"; //$NON-NLS-1$
 
+	private static final String PASSWORD_HASH_GENERATOR_CLASS = "passwordHashGeneratorClass"; //$NON-NLS-1$
+
 	private static final String ACCESSCONTROL_EXTENSION_ID = "org.eclipse.emf.emfstore.server.accessControl"; //$NON-NLS-1$
 
+	private static ESPasswordHashGenerator passwordHashGenerator;
+
 	private final ESOrgUnitProvider orgUnitProvider;
 
 	private final ESAuthorizationService authorizationService;
@@ -95,6 +100,38 @@
 	}
 
 	/**
+	 * Parses the access control extension point and return the {@link ESPasswordHashGenerator} if found.
+	 *
+	 * @return the generator
+	 */
+	public static ESPasswordHashGenerator getESPasswordHashGenerator() {
+		if (AccessControl.passwordHashGenerator != null) {
+			return AccessControl.passwordHashGenerator;
+		}
+		ESPasswordHashGenerator passwordHashGenerator;
+		try {
+			final List<ESPasswordHashGenerator> services = new ESExtensionPoint(ACCESSCONTROL_EXTENSION_ID, false)
+				.getClasses(PASSWORD_HASH_GENERATOR_CLASS, ESPasswordHashGenerator.class);
+			if (services.isEmpty()) {
+				passwordHashGenerator = new DefaultESPasswordHashGenerator();
+			} else if (services.size() == 1) {
+				passwordHashGenerator = services.get(0);
+			} else {
+				throw new IllegalStateException(
+					MessageFormat.format(
+						Messages.AccessControl_MultipleExtensionsDiscovered,
+						ACCESSCONTROL_EXTENSION_ID + "." + PASSWORD_HASH_GENERATOR_CLASS)); //$NON-NLS-1$
+			}
+		} catch (final ESExtensionPointException e) {
+			final String message = Messages.AccessControl_CustomAuthorizationInitFailed;
+			ModelUtil.logException(message, e);
+			passwordHashGenerator = new DefaultESPasswordHashGenerator();
+		}
+		AccessControl.passwordHashGenerator = passwordHashGenerator;
+		return passwordHashGenerator;
+	}
+
+	/**
 	 * @return
 	 */
 	private LoginService initLoginService() {
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/DefaultESPasswordHashGenerator.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/DefaultESPasswordHashGenerator.java
new file mode 100644
index 0000000..ef482be
--- /dev/null
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/DefaultESPasswordHashGenerator.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.internal.server.accesscontrol;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang.RandomStringUtils;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
+
+/**
+ * Default implemention of the {@link ESPasswordHashGenerator} using a 128 char String as a salt and SHA512 as a hash
+ * function.
+ *
+ * @author Johannes Faltermeier
+ *
+ */
+public class DefaultESPasswordHashGenerator implements ESPasswordHashGenerator {
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator#hashPassword(java.lang.String)
+	 */
+	public ESHashAndSalt hashPassword(String password) {
+		final String salt = RandomStringUtils.randomAlphanumeric(128);
+		final String hash = createHash(password, salt);
+		return org.eclipse.emf.emfstore.server.auth.ESHashAndSalt.create(hash, salt);
+	}
+
+	private String createHash(String password, final String salt) {
+		String hash = DigestUtils.sha512Hex(password + salt);
+		for (int i = 0; i < 128; i++) {
+			if (i % 2 == 0) {
+				hash = DigestUtils.sha512Hex(hash + salt);
+			} else {
+				hash = DigestUtils.sha512Hex(salt + hash);
+			}
+		}
+		return hash;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator#verifyPassword(java.lang.String,
+	 *      java.lang.String, java.lang.String)
+	 */
+	public boolean verifyPassword(String password, String hash, String salt) {
+		if (password == null || hash == null || salt == null) {
+			return false;
+		}
+		final String hashToMatch = createHash(password, salt);
+		return hash.equals(hashToMatch);
+	}
+
+}
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/EMFModelUserVerifier.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/EMFModelUserVerifier.java
index a1c1365..610c1c8 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/EMFModelUserVerifier.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/EMFModelUserVerifier.java
@@ -11,9 +11,18 @@
  ******************************************************************************/
 package org.eclipse.emf.emfstore.internal.server.accesscontrol.authentication.verifiers;
 
+import java.io.IOException;
+import java.util.Set;
+
 import org.apache.commons.lang.StringUtils;
+import org.eclipse.emf.emfstore.internal.common.APIUtil;
+import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil;
+import org.eclipse.emf.emfstore.internal.server.ServerConfiguration;
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.AccessControl;
 import org.eclipse.emf.emfstore.internal.server.exceptions.AccessControlException;
 import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.ACUser;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt;
 import org.eclipse.emf.emfstore.server.model.ESOrgUnitProvider;
 
 /**
@@ -30,6 +39,28 @@
 	 */
 	public EMFModelUserVerifier(ESOrgUnitProvider orgUnitProvider) {
 		super(orgUnitProvider);
+		migrateToHashedPasswordIfNeeded(orgUnitProvider);
+
+	}
+
+	private void migrateToHashedPasswordIfNeeded(ESOrgUnitProvider orgUnitProvider) {
+		if (!ServerConfiguration.isUserPasswordMigrationRequired()) {
+			return;
+		}
+		final ESPasswordHashGenerator passwordHashGenerator = AccessControl.getESPasswordHashGenerator();
+		final Set<ACUser> users = APIUtil.toInternal(orgUnitProvider.getUsers());
+		for (final ACUser user : users) {
+			if (user.getPassword() == null) {
+				continue;
+			}
+			final ESHashAndSalt hashAndSalt = passwordHashGenerator.hashPassword(user.getPassword());
+			user.setPassword(hashAndSalt.getHash() + ESHashAndSalt.SEPARATOR + hashAndSalt.getSalt());
+		}
+		try {
+			orgUnitProvider.save();
+		} catch (final IOException ex) {
+			ModelUtil.logException("Migration of user passwords failed", ex); //$NON-NLS-1$
+		}
 	}
 
 	/**
@@ -59,7 +90,12 @@
 			return false;
 		}
 
-		return userPassword.equals(password);
+		final ESPasswordHashGenerator passwordHashGenerator = AccessControl.getESPasswordHashGenerator();
+		final int separatorIndex = userPassword.indexOf(ESHashAndSalt.SEPARATOR);
+		final String hash = userPassword.substring(0, separatorIndex);
+		final String salt = userPassword.substring(separatorIndex + 1);
+		return passwordHashGenerator.verifyPassword(password, hash, salt);
+
 	}
 
 	/**
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/PasswordVerifier.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/PasswordVerifier.java
index 09f772d..8cf9730 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/PasswordVerifier.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/verifiers/PasswordVerifier.java
@@ -13,12 +13,14 @@
 package org.eclipse.emf.emfstore.internal.server.accesscontrol.authentication.verifiers;
 
 import org.eclipse.emf.emfstore.internal.server.ServerConfiguration;
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.AccessControl;
 import org.eclipse.emf.emfstore.internal.server.connection.ServerKeyStoreManager;
 import org.eclipse.emf.emfstore.internal.server.exceptions.AccessControlException;
 import org.eclipse.emf.emfstore.internal.server.exceptions.ClientVersionOutOfDateException;
 import org.eclipse.emf.emfstore.internal.server.exceptions.ServerKeyStoreException;
 import org.eclipse.emf.emfstore.internal.server.model.AuthenticationInformation;
 import org.eclipse.emf.emfstore.internal.server.model.ModelFactory;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
 import org.eclipse.emf.emfstore.server.auth.ESUserVerifier;
 import org.eclipse.emf.emfstore.server.model.ESClientVersionInfo;
 
@@ -30,7 +32,8 @@
 public abstract class PasswordVerifier implements ESUserVerifier {
 
 	private final String superuser;
-	private final String superuserpw;
+	private final String hash;
+	private final String salt;
 
 	/**
 	 * Default constructor.
@@ -38,8 +41,8 @@
 	public PasswordVerifier() {
 		superuser = ServerConfiguration.getProperties().getProperty(ServerConfiguration.SUPER_USER,
 			ServerConfiguration.SUPER_USER_DEFAULT);
-		superuserpw = ServerConfiguration.getProperties().getProperty(ServerConfiguration.SUPER_USER_PASSWORD,
-			ServerConfiguration.SUPER_USER_PASSWORD_DEFAULT);
+		hash = ServerConfiguration.getProperties().getProperty(ServerConfiguration.SUPER_USER_PASSWORD_HASH);
+		salt = ServerConfiguration.getProperties().getProperty(ServerConfiguration.SUPER_USER_PASSWORD_SALT);
 	}
 
 	/**
@@ -75,7 +78,11 @@
 	 * @return true if super user
 	 */
 	protected boolean verifySuperUser(String username, String password) {
-		return username.equals(superuser) && password.equals(superuserpw);
+		final ESPasswordHashGenerator passwordHashGenerator = AccessControl.getESPasswordHashGenerator();
+		if (hash == null && salt == null) {
+			return username.equals(superuser) && ServerConfiguration.SUPER_USER_PASSWORD_DEFAULT.equals(password);
+		}
+		return username.equals(superuser) && passwordHashGenerator.verifyPassword(password, hash, salt);
 	}
 
 	/**
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/core/AdminEmfStoreImpl.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/core/AdminEmfStoreImpl.java
index 755e4f8..87b16f6 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/core/AdminEmfStoreImpl.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/core/AdminEmfStoreImpl.java
@@ -48,6 +48,8 @@
 import org.eclipse.emf.emfstore.internal.server.model.impl.api.ESGroupImpl;
 import org.eclipse.emf.emfstore.internal.server.model.impl.api.ESUserImpl;
 import org.eclipse.emf.emfstore.server.auth.ESAuthorizationService;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt;
 import org.eclipse.emf.emfstore.server.auth.ESProjectAdminPrivileges;
 import org.eclipse.emf.emfstore.server.exceptions.ESException;
 import org.eclipse.emf.emfstore.server.model.ESGroup;
@@ -783,7 +785,9 @@
 
 		final ACUser user = (ACUser) getOrgUnit(userId);
 		user.setName(name);
-		user.setPassword(password);
+		final ESPasswordHashGenerator passwordHashGenerator = AccessControl.getESPasswordHashGenerator();
+		final ESHashAndSalt hashAndSalt = passwordHashGenerator.hashPassword(password);
+		user.setPassword(hashAndSalt.getHash() + ESHashAndSalt.SEPARATOR + hashAndSalt.getSalt());
 		save();
 	}
 
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/messages.properties b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/messages.properties
index c8cb82e..a6cd530 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/messages.properties
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/messages.properties
@@ -11,11 +11,16 @@
 EMFStoreController_Default_Properties_File_Copied=Default es.properties file was copied to config folder.

 EMFStoreController_Dynamic_Model_Loaded=Dynamic Model "{0}" loaded.

 EMFStoreController_EMFStore_Controller_Already_Running=Another EmfStore Controller seems to be running already\!

+EMFStoreController_EnterSuperUserPasswordAgain=Please enter the password again:

 EMFStoreController_Error_During_Migration=Error during migration

 EMFStoreController_Failed_To_Copy_Keystore=Failed to copy keystore.

 EMFStoreController_Init_Complete=Initialitation COMPLETE.

 EMFStoreController_JVM_Max_Memory=JVM Max Memory: {0} MByte

 EMFStoreController_Keystore_Copied=Keystore was copied to server workspace.

+EMFStoreController_NoSuperUserPasswordPrompt=No super user password found. Please enter a password:

+EMFStoreController_PasswordDidNotMatch=Sorry, the passwords did not match. Please enter again.

+EMFStoreController_PasswordHashFailFileNotFound=Password hashing failed

+EMFStoreController_PasswordHashFailIOException=Password hashing failed

 EMFStoreController_Property_Init_Failed=Property initialization failed, using default properties.

 EMFStoreController_PropertyFile_Read=Property file read. ({0})

 EMFStoreController_Serve_Forcefully_Stopped=Server was forcefully stopped.

diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/server/auth/ESHashAndSalt.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/server/auth/ESHashAndSalt.java
new file mode 100644
index 0000000..3f6ac52
--- /dev/null
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/server/auth/ESHashAndSalt.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.server.auth;
+
+/**
+ * Default implementation of a {@link ESPasswordHashGenerator.ESHashAndSalt ESHashAndSalt}.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.9
+ *
+ */
+public final class ESHashAndSalt implements ESPasswordHashGenerator.ESHashAndSalt {
+
+	private final String hash;
+	private final String salt;
+
+	private ESHashAndSalt(String hash, String salt) {
+		this.hash = hash;
+		this.salt = salt;
+	}
+
+	/**
+	 * Factory method for creating {@link ESHashAndSalt}s.
+	 *
+	 * @param hash the hash
+	 * @param salt the salt
+	 * @return the instance
+	 */
+	public static ESHashAndSalt create(String hash, String salt) {
+		return new ESHashAndSalt(hash, salt);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt#getHash()
+	 */
+	public String getHash() {
+		return hash;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt#getSalt()
+	 */
+	public String getSalt() {
+		return salt;
+	}
+
+}
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/server/auth/ESPasswordHashGenerator.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/server/auth/ESPasswordHashGenerator.java
new file mode 100644
index 0000000..63613f0
--- /dev/null
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/server/auth/ESPasswordHashGenerator.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.server.auth;
+
+/**
+ * A PasswordHash Generator is able to generate a hash using a newly created salt for a given password. Moreover it is
+ * able to verify if a password matches a stored hash/salt.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.9
+ *
+ */
+public interface ESPasswordHashGenerator {
+
+	/**
+	 * This method will hash the password using a newly generated salt. Hash and salt will be returned.
+	 *
+	 * @param password the password to hash
+	 * @return a {@link ESHashAndSalt}
+	 */
+	ESHashAndSalt hashPassword(String password);
+
+	/**
+	 * Verifies if the given password matches the hash/salt.
+	 *
+	 * @param password the password to verify
+	 * @param hash the saved hash
+	 * @param salt the saved salt
+	 * @return <code>true</code> if password matches, <code>false</code> otherwise
+	 */
+	boolean verifyPassword(String password, String hash, String salt);
+
+	/**
+	 * Wrapper interface for a hash/salt pair.
+	 *
+	 * @author Johannes Faltermeier
+	 *
+	 */
+	interface ESHashAndSalt {
+		/**
+		 * A separator char helping to separate hashes and salts.
+		 */
+		String SEPARATOR = " "; //$NON-NLS-1$
+
+		/**
+		 * @return the hash
+		 */
+		String getHash();
+
+		/**
+		 *
+		 * @return the salt
+		 */
+		String getSalt();
+	}
+
+}
diff --git a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java
index 12ad3cf..c54a7a4 100644
--- a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java
+++ b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java
@@ -41,7 +41,8 @@
 	CreateUserWithPasswordMissingPrivilegTests.class,
 	AdminEMFStoreTests.class,
 	AddInitialParticipantTest.class,
-	AutoCreateACUserTestTest.class
+	AutoCreateACUserTestTest.class,
+	DefaultESPasswordHashGeneratorTests.class
 
 })
 public class AllAccessControlTests {
diff --git a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/ChangePasswordTests.java b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/ChangePasswordTests.java
index ea01967..2679025 100644
--- a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/ChangePasswordTests.java
+++ b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/ChangePasswordTests.java
@@ -12,6 +12,7 @@
 package org.eclipse.emf.emfstore.server.accesscontrol.test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import org.eclipse.emf.emfstore.client.test.common.dsl.Roles;
@@ -19,11 +20,13 @@
 import org.eclipse.emf.emfstore.client.test.common.util.ServerUtil;
 import org.eclipse.emf.emfstore.internal.client.model.ProjectSpace;
 import org.eclipse.emf.emfstore.internal.client.model.impl.api.ESUsersessionImpl;
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.AccessControl;
 import org.eclipse.emf.emfstore.internal.server.exceptions.AccessControlException;
 import org.eclipse.emf.emfstore.internal.server.model.ProjectId;
 import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.ACOrgUnitId;
 import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.ACUser;
 import org.eclipse.emf.emfstore.internal.server.model.impl.api.ESGlobalProjectIdImpl;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt;
 import org.eclipse.emf.emfstore.server.auth.ESProjectAdminPrivileges;
 import org.eclipse.emf.emfstore.server.exceptions.ESException;
 import org.junit.After;
@@ -85,7 +88,11 @@
 		getAdminBroker().changeRole(getProjectSpace().getProjectId(), createUser, Roles.writer());
 		ServerUtil.changePassword(getUsersession(), createUser, getNewUsername(), NEW_USER_PASSWORD);
 		final ACUser user = ServerUtil.getUser(getSuperUsersession(), createUser);
-		assertEquals(NEW_USER_PASSWORD, user.getPassword());
+		final String userPass = user.getPassword();
+		final int separatorIndex = userPass.indexOf(ESHashAndSalt.SEPARATOR);
+		final String hash = userPass.substring(0, separatorIndex);
+		final String salt = userPass.substring(separatorIndex + 1);
+		assertTrue(AccessControl.getESPasswordHashGenerator().verifyPassword(NEW_USER_PASSWORD, hash, salt));
 	}
 
 	@Test
@@ -96,7 +103,11 @@
 			ESUsersessionImpl.class.cast(getUsersession()).toInternalAPI().getACUser().getId(),
 			getUser(), "new-password"); //$NON-NLS-1$
 		final ACUser user = ServerUtil.getUser(getSuperUsersession(), getUser());
-		assertEquals("new-password", user.getPassword()); //$NON-NLS-1$
+		final String userPass = user.getPassword();
+		final int separatorIndex = userPass.indexOf(ESHashAndSalt.SEPARATOR);
+		final String hash = userPass.substring(0, separatorIndex);
+		final String salt = userPass.substring(separatorIndex + 1);
+		assertTrue(AccessControl.getESPasswordHashGenerator().verifyPassword("new-password", hash, salt)); //$NON-NLS-1$
 	}
 
 	@Test(expected = AccessControlException.class)
@@ -195,6 +206,10 @@
 		getAdminBroker().changeUser(newUser, getNewUsername(), NEW_USER_PASSWORD);
 		final ACUser user = ServerUtil.getUser(getSuperUsersession(), newUser);
 
-		assertEquals(NEW_USER_PASSWORD, user.getPassword());
+		final String userPass = user.getPassword();
+		final int separatorIndex = userPass.indexOf(ESHashAndSalt.SEPARATOR);
+		final String hash = userPass.substring(0, separatorIndex);
+		final String salt = userPass.substring(separatorIndex + 1);
+		assertTrue(AccessControl.getESPasswordHashGenerator().verifyPassword(NEW_USER_PASSWORD, hash, salt));
 	}
 }
\ No newline at end of file
diff --git a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/DefaultESPasswordHashGeneratorTests.java b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/DefaultESPasswordHashGeneratorTests.java
new file mode 100644
index 0000000..f1cb8ad
--- /dev/null
+++ b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/DefaultESPasswordHashGeneratorTests.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.server.accesscontrol.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.DefaultESPasswordHashGenerator;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
+import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt;
+import org.junit.Test;
+
+public class DefaultESPasswordHashGeneratorTests {
+
+	private static final String PASSWORD = "IAmPassword"; //$NON-NLS-1$
+	private static final String NOT_PASSWORD = "IAmNotPassword"; //$NON-NLS-1$
+
+	private static final String TEST_HASH = "eaf6acf17676f0b6bd554af88350c905fd0a444ec962f1840e7fabf182c79e881c3589ff66667b1f56e73a84b6585b57ef3d82e914b3584be18d3ad6e9641a9f"; //$NON-NLS-1$
+	private static final String TEST_SALT = "nPkctDB1Q45EOv6lyn5DiG14vEzAUeYhNbtKOWutolQayr2idOctVc2xpo6q4p6oUmYU1cG1q2DzQgJ0zHKctIP1SrKzEJzdAqYesRhoXLTLvGbuElGNaYBbd3eb8cRZ"; //$NON-NLS-1$
+
+	/* stateless */
+	private final ESPasswordHashGenerator passwordHashGenerator = new DefaultESPasswordHashGenerator();
+
+	@Test
+	public void testHashPasswordSamePasswordDifferentSalts() {
+		final ESHashAndSalt hash1 = passwordHashGenerator.hashPassword(PASSWORD);
+		final ESHashAndSalt hash2 = passwordHashGenerator.hashPassword(PASSWORD);
+		assertNotEquals(hash1.getSalt(), hash2.getSalt());
+		assertNotEquals(hash1.getHash(), hash2.getHash());
+	}
+
+	@Test
+	public void testVerifyPasswordMatching() {
+		assertTrue(passwordHashGenerator.verifyPassword(PASSWORD, TEST_HASH, TEST_SALT));
+	}
+
+	@Test
+	public void testVerifyPasswordNotMatching() {
+		assertFalse(passwordHashGenerator.verifyPassword(NOT_PASSWORD, TEST_HASH, TEST_SALT));
+	}
+
+	@Test
+	public void testVerifyPasswordInvalidInput() {
+		assertFalse(passwordHashGenerator.verifyPassword(null, TEST_HASH, TEST_SALT));
+		assertFalse(passwordHashGenerator.verifyPassword(PASSWORD, null, TEST_SALT));
+		assertFalse(passwordHashGenerator.verifyPassword(PASSWORD, TEST_HASH, null));
+	}
+
+}