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));
+ }
+
+}