[299275] Flexible Approach for an Authentication Mechanism 
https://bugs.eclipse.org/bugs/show_bug.cgi?id=299275
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOAuthenticator.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOAuthenticator.java
index 30490a2c..11dd65f 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOAuthenticator.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOAuthenticator.java
@@ -16,10 +16,12 @@
 
 /**
  * The front-end of the CDO challenge/response authentication.
- * 
+ *
  * @author Eike Stepper
  * @since 2.0
+ * @deprecated As of 4.2 use {@link IPasswordCredentialsProvider} directly
  */
+@Deprecated
 public interface CDOAuthenticator
 {
   public String getEncryptionAlgorithmName();
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOAuthenticationResult.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOAuthenticationResult.java
index 02fb08a..864a173 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOAuthenticationResult.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/CDOAuthenticationResult.java
@@ -18,10 +18,12 @@
 
 /**
  * The result of an authentication operation. Carries a userID and a crypted token.
- * 
+ *
  * @author Eike Stepper
  * @since 4.0
+ * @deprecated As of 4.2
  */
+@Deprecated
 public final class CDOAuthenticationResult implements Serializable
 {
   private static final long serialVersionUID = 1L;
diff --git a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
index 7475eef..f399432 100644
--- a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
@@ -28,11 +28,7 @@
     -->
 
     <!-- Example http://bugs.eclipse.org/302775
-			<userManager type="file" description="_database/repo1.users"/>
-    -->
-
-    <!-- Example http://bugs.eclipse.org/34583
-			<userManager type="TestRepository" description="repo1"/>
+			<authenticator type="file" description="_database/repo1.users"/>
     -->
 
     <!-- Example http://bugs.eclipse.org/345431
diff --git a/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
index 7475eef..f399432 100644
--- a/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
@@ -28,11 +28,7 @@
     -->
 
     <!-- Example http://bugs.eclipse.org/302775
-			<userManager type="file" description="_database/repo1.users"/>
-    -->
-
-    <!-- Example http://bugs.eclipse.org/34583
-			<userManager type="TestRepository" description="repo1"/>
+			<authenticator type="file" description="_database/repo1.users"/>
     -->
 
     <!-- Example http://bugs.eclipse.org/345431
diff --git a/plugins/org.eclipse.emf.cdo.examples.server/src/org/eclipse/emf/cdo/examples/server/DemoConfiguration.java b/plugins/org.eclipse.emf.cdo.examples.server/src/org/eclipse/emf/cdo/examples/server/DemoConfiguration.java
index a8b9a20..d406c87 100644
--- a/plugins/org.eclipse.emf.cdo.examples.server/src/org/eclipse/emf/cdo/examples/server/DemoConfiguration.java
+++ b/plugins/org.eclipse.emf.cdo.examples.server/src/org/eclipse/emf/cdo/examples/server/DemoConfiguration.java
@@ -32,7 +32,7 @@
 import org.eclipse.net4j.util.io.IOUtil;
 import org.eclipse.net4j.util.lifecycle.Lifecycle;
 import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
-import org.eclipse.net4j.util.security.IUserManager;
+import org.eclipse.net4j.util.security.IAuthenticator;
 import org.eclipse.net4j.util.security.UserManager;
 
 import org.h2.jdbcx.JdbcDataSource;
@@ -149,8 +149,8 @@
 
     if (userIDs != null)
     {
-      IUserManager userManager = createUserManager();
-      sessionManager.setUserManager(userManager);
+      IAuthenticator authenticator = createAuthenticator();
+      sessionManager.setAuthenticator(authenticator);
     }
 
     CDOServerUtil.addRepository(IPluginContainer.INSTANCE, repository);
@@ -235,7 +235,7 @@
     return sessionManager;
   }
 
-  protected IUserManager createUserManager()
+  protected IAuthenticator createAuthenticator()
   {
     userManager = new DemoUserManager();
     for (int i = 0; i < userIDs.length; i++)
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java
index 127a0aa..45fbe8b 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java
@@ -36,6 +36,7 @@
 
 import org.eclipse.net4j.connector.IConnector;
 import org.eclipse.net4j.signal.ISignalProtocol;
+import org.eclipse.net4j.signal.RemoteException;
 import org.eclipse.net4j.signal.SignalProtocol;
 import org.eclipse.net4j.util.io.IStreamWrapper;
 
@@ -223,21 +224,33 @@
     setSessionProtocol(protocol);
     hookSessionProtocol();
 
-    // TODO (CD) The next call is on the CDOClientProtocol; shouldn't it be on the DelegatingSessionProtocol instead?
-    OpenSessionResult result = protocol.openSession(repositoryName, getUserID(), options().isPassiveUpdateEnabled(),
-        options().getPassiveUpdateMode(), options().getLockNotificationMode());
-
-    if (result == null)
+    try
     {
-      // Skip to response because the user has canceled the authentication
-      return null;
-    }
+      // TODO (CD) The next call is on the CDOClientProtocol; shouldn't it be on the DelegatingSessionProtocol instead?
+      OpenSessionResult result = protocol.openSession(repositoryName, getUserID(), options().isPassiveUpdateEnabled(),
+          options().getPassiveUpdateMode(), options().getLockNotificationMode());
 
-    setSessionID(result.getSessionID());
-    setUserID(result.getUserID());
-    setLastUpdateTime(result.getLastUpdateTime());
-    setRepositoryInfo(new RepositoryInfo(this, repositoryName, result));
-    return result;
+      if (result == null)
+      {
+        // Skip to response because the user has canceled the authentication
+        return null;
+      }
+
+      setSessionID(result.getSessionID());
+      setUserID(result.getUserID());
+      setLastUpdateTime(result.getLastUpdateTime());
+      setRepositoryInfo(new RepositoryInfo(this, repositoryName, result));
+      return result;
+    }
+    catch (RemoteException ex)
+    {
+      if (ex.getCause() instanceof SecurityException)
+      {
+        throw (SecurityException)ex.getCause();
+      }
+
+      throw ex;
+    }
   }
 
   @Override
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/Net4jSessionFactory.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/Net4jSessionFactory.java
index f790c14..f78ba23 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/Net4jSessionFactory.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/Net4jSessionFactory.java
@@ -51,7 +51,7 @@
     CDONet4jSessionConfiguration configuration = CDONet4jUtil.createNet4jSessionConfiguration();
     configuration.setRepositoryName(repositoryName);
     configuration.setUserID(userID);
-    configuration.getAuthenticator().setCredentialsProvider(getCredentialsProvider());
+    configuration.setCredentialsProvider(getCredentialsProvider());
 
     // The session will be activated by the container
     configuration.setActivateOnOpen(false);
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/AuthenticationIndication.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/AuthenticationIndication.java
index 361377c..5e379e6 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/AuthenticationIndication.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/AuthenticationIndication.java
@@ -10,25 +10,32 @@
  */
 package org.eclipse.emf.cdo.internal.net4j.protocol;
 
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
 import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
-import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
+import org.eclipse.emf.cdo.internal.net4j.bundle.OM;
 
 import org.eclipse.net4j.signal.IndicationWithMonitoring;
 import org.eclipse.net4j.signal.SignalProtocol;
+import org.eclipse.net4j.util.StringUtil;
 import org.eclipse.net4j.util.io.ExtendedDataInputStream;
 import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
 import org.eclipse.net4j.util.om.monitor.OMMonitor;
 import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
+import org.eclipse.net4j.util.security.DiffieHellman;
+import org.eclipse.net4j.util.security.DiffieHellman.Client.Response;
+import org.eclipse.net4j.util.security.DiffieHellman.Server.Challenge;
+import org.eclipse.net4j.util.security.IPasswordCredentials;
+import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 
 import org.eclipse.emf.spi.cdo.InternalCDOSession;
 
+import java.io.ByteArrayOutputStream;
+
 /**
  * @author Eike Stepper
  */
 public class AuthenticationIndication extends IndicationWithMonitoring
 {
-  private byte[] randomToken;
+  private Challenge challenge;
 
   public AuthenticationIndication(SignalProtocol<?> protocol)
   {
@@ -49,7 +56,7 @@
   @Override
   protected void indicating(ExtendedDataInputStream in, OMMonitor monitor) throws Exception
   {
-    randomToken = in.readByteArray();
+    challenge = new Challenge(in);
   }
 
   @Override
@@ -60,38 +67,74 @@
 
     try
     {
-      CDOAuthenticator authenticator = getSession().getAuthenticator();
-      if (authenticator == null)
+      IPasswordCredentialsProvider credentialsProvider = getSession().getCredentialsProvider();
+      if (credentialsProvider == null)
       {
-        throw new IllegalStateException("No authenticator configured"); //$NON-NLS-1$
+        throw new IllegalStateException("No credentials provider configured"); //$NON-NLS-1$
       }
 
-      CDOAuthenticationResult result = authenticator.authenticate(randomToken);
-      if (result == null)
+      IPasswordCredentials credentials = credentialsProvider.getCredentials();
+      if (credentials == null)
       {
-        out.writeBoolean(false);
-        return;
+        throw new IllegalStateException("No credentials provided"); //$NON-NLS-1$
       }
 
-      String userID = result.getUserID();
-      if (userID == null)
+      String userID = credentials.getUserID();
+      if (StringUtil.isEmpty(userID))
       {
-        throw new SecurityException("No user ID"); //$NON-NLS-1$
+        throw new IllegalStateException("No userID provided"); //$NON-NLS-1$
       }
 
-      byte[] cryptedToken = result.getCryptedToken();
-      if (cryptedToken == null)
+      String password = new String(credentials.getPassword());
+      if (StringUtil.isEmpty(userID))
       {
-        throw new SecurityException("No crypted token"); //$NON-NLS-1$
+        throw new IllegalStateException("No password provided"); //$NON-NLS-1$
       }
 
+      ByteArrayOutputStream baos = new ByteArrayOutputStream();
+      ExtendedDataOutputStream stream = new ExtendedDataOutputStream(baos);
+      stream.writeString(userID);
+      stream.writeString(password);
+      stream.flush();
+      byte[] clearText = baos.toByteArray();
+
+      DiffieHellman.Client client = new DiffieHellman.Client();
+      Response response = client.handleChallenge(challenge, clearText);
       out.writeBoolean(true);
-      result.write(out);
+      response.write(out);
+
+      // CDOAuthenticator authenticator = getSession().getAuthenticator();
+      // if (authenticator == null)
+      // {
+      //        throw new IllegalStateException("No authenticator configured"); //$NON-NLS-1$
+      // }
+      //
+      // CDOAuthenticationResult result = authenticator.authenticate(challenge);
+      // if (result == null)
+      // {
+      // out.writeBoolean(false);
+      // return;
+      // }
+      //
+      // String userID = result.getUserID();
+      // if (userID == null)
+      // {
+      //        throw new SecurityException("No user ID"); //$NON-NLS-1$
+      // }
+      //
+      // byte[] cryptedToken = result.getCryptedToken();
+      // if (cryptedToken == null)
+      // {
+      //        throw new SecurityException("No crypted token"); //$NON-NLS-1$
+      // }
+      //
+      // out.writeBoolean(true);
+      // result.write(out);
     }
-    catch (Exception ex)
+    catch (Throwable ex)
     {
       out.writeBoolean(false);
-      throw ex;
+      OM.LOG.error(ex);
     }
     finally
     {
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/net4j/CDONet4jViewProvider.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/net4j/CDONet4jViewProvider.java
index 669d80f..f9db698 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/net4j/CDONet4jViewProvider.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/net4j/CDONet4jViewProvider.java
@@ -195,7 +195,7 @@
       }
     }
 
-    configuration.getAuthenticator().setCredentialsProvider(credentialsProvider);
+    configuration.setCredentialsProvider(credentialsProvider);
     return configuration;
   }
 
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/AuthenticationRequest.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/AuthenticationRequest.java
index 163350a..d5867e2 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/AuthenticationRequest.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/AuthenticationRequest.java
@@ -12,42 +12,42 @@
 
 import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
 import org.eclipse.emf.cdo.common.util.NotAuthenticatedException;
-import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
 
 import org.eclipse.net4j.signal.RemoteException;
 import org.eclipse.net4j.signal.RequestWithMonitoring;
 import org.eclipse.net4j.util.io.ExtendedDataInputStream;
 import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
 import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.security.DiffieHellman.Client.Response;
+import org.eclipse.net4j.util.security.DiffieHellman.Server.Challenge;
 
 /**
  * @author Eike Stepper
  */
-public class AuthenticationRequest extends RequestWithMonitoring<CDOAuthenticationResult>
+public class AuthenticationRequest extends RequestWithMonitoring<Response>
 {
-  private byte[] randomToken;
+  private Challenge challenge;
 
-  public AuthenticationRequest(CDOServerProtocol protocol, byte[] randomToken)
+  public AuthenticationRequest(CDOServerProtocol protocol, Challenge challenge)
   {
     super(protocol, CDOProtocolConstants.SIGNAL_AUTHENTICATION);
-    this.randomToken = randomToken;
+    this.challenge = challenge;
   }
 
   @Override
   protected void requesting(ExtendedDataOutputStream out, OMMonitor monitor) throws Exception
   {
-    out.writeByteArray(randomToken);
+    challenge.write(out);
   }
 
   @Override
-  protected CDOAuthenticationResult confirming(ExtendedDataInputStream in, OMMonitor monitor) throws Exception
+  protected Response confirming(ExtendedDataInputStream in, OMMonitor monitor) throws Exception
   {
     try
     {
-      boolean authenticated = in.readBoolean();
-      if (authenticated)
+      if (in.readBoolean())
       {
-        return new CDOAuthenticationResult(in);
+        return new Response(in);
       }
     }
     catch (RemoteException ex)
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
index dcc2ffd..b2414e3 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
@@ -22,7 +22,6 @@
 import org.eclipse.emf.cdo.server.IRepositoryProvider;
 import org.eclipse.emf.cdo.server.internal.net4j.bundle.OM;
 import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
-import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
 import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
 import org.eclipse.emf.cdo.spi.server.ISessionProtocol;
 import org.eclipse.emf.cdo.spi.server.InternalSession;
@@ -32,6 +31,8 @@
 import org.eclipse.net4j.util.io.StringCompressor;
 import org.eclipse.net4j.util.io.StringIO;
 import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+import org.eclipse.net4j.util.security.DiffieHellman.Client.Response;
+import org.eclipse.net4j.util.security.DiffieHellman.Server.Challenge;
 
 /**
  * @author Eike Stepper
@@ -83,9 +84,16 @@
     this.negotiationTimeout = negotiationTimeout;
   }
 
-  public CDOAuthenticationResult sendAuthenticationChallenge(byte[] randomToken) throws Exception
+  @Deprecated
+  public org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult sendAuthenticationChallenge(byte[] randomToken)
+      throws Exception
   {
-    return new AuthenticationRequest(this, randomToken).send(negotiationTimeout);
+    throw new UnsupportedOperationException();
+  }
+
+  public Response sendAuthenticationChallenge(Challenge challenge) throws Exception
+  {
+    return new AuthenticationRequest(this, challenge).send(negotiationTimeout);
   }
 
   public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType)
diff --git a/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
index e2e791c..9b730ec 100644
--- a/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
@@ -28,11 +28,7 @@
     -->
 
     <!-- Example http://bugs.eclipse.org/302775
-			<userManager type="file" description="_database/repo1.users"/>
-    -->
-
-    <!-- Example http://bugs.eclipse.org/34583
-			<userManager type="TestRepository" description="repo1"/>
+			<authenticator type="file" description="_database/repo1.users"/>
     -->
 
     <!-- Example http://bugs.eclipse.org/345431
diff --git a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java
index 8dd57ce..a86ee4d 100644
--- a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java
+++ b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java
@@ -56,13 +56,12 @@
 import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
 import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
 import org.eclipse.net4j.util.om.monitor.OMMonitor;
-import org.eclipse.net4j.util.security.IUserManager;
-import org.eclipse.net4j.util.security.SecurityUtil;
+import org.eclipse.net4j.util.security.IAuthenticator;
 
 import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.util.EcoreUtil;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -77,20 +76,17 @@
     @Override
     protected void onActivated(ILifecycle lifecycle)
     {
-      if (isActive())
-      {
-        init();
-      }
+      init();
     }
 
     @Override
     protected void onDeactivated(ILifecycle lifecycle)
     {
-      deactivate();
+      SecurityManager.this.deactivate();
     }
   };
 
-  private final IUserManager userManager = new UserManager();
+  private final IAuthenticator authenticator = new Authenticator();
 
   private final IPermissionManager permissionManager = new PermissionManager();
 
@@ -242,7 +238,11 @@
     {
       public void execute(Realm realm)
       {
+        UserPassword userPassword = SecurityFactory.eINSTANCE.createUserPassword();
+        userPassword.setEncrypted(new String(password));
+
         result[0] = realm.addUser(id);
+        result[0].setPassword(userPassword);
       }
     });
 
@@ -373,14 +373,22 @@
 
   protected void init()
   {
+    if (realm != null)
+    {
+      // Already initialized
+      return;
+    }
+
     if (repository == null)
     {
+      // Cannot initialize
       return;
     }
 
     repository.addListener(repositoryListener);
     if (!LifecycleUtil.isActive(repository))
     {
+      // Cannot initialize now
       return;
     }
 
@@ -422,7 +430,7 @@
     }
 
     InternalSessionManager sessionManager = repository.getSessionManager();
-    sessionManager.setUserManager(userManager);
+    sessionManager.setAuthenticator(authenticator);
     sessionManager.setPermissionManager(permissionManager);
     repository.addHandler(writeAccessHandler);
   }
@@ -561,61 +569,17 @@
   /**
    * @author Eike Stepper
    */
-  private final class UserManager implements IUserManager
+  private final class Authenticator implements IAuthenticator
   {
-    public void addUser(final String userID, final char[] password)
-    {
-      modify(new RealmOperation()
-      {
-        public void execute(Realm realm)
-        {
-          UserPassword userPassword = SecurityFactory.eINSTANCE.createUserPassword();
-          userPassword.setEncrypted(new String(password));
-
-          User user = SecurityFactory.eINSTANCE.createUser();
-          user.setId(userID);
-          user.setPassword(userPassword);
-
-          realm.getItems().add(user);
-        }
-      });
-    }
-
-    public void removeUser(final String userID)
-    {
-      modify(new RealmOperation()
-      {
-        public void execute(Realm realm)
-        {
-          User user = getUser(userID);
-          EcoreUtil.remove(user);
-        }
-      });
-    }
-
-    public byte[] encrypt(String userID, byte[] data, String algorithmName, byte[] salt, int count)
-        throws SecurityException
+    public void authenticate(String userID, char[] password) throws SecurityException
     {
       User user = getUser(userID);
       UserPassword userPassword = user.getPassword();
-      String encrypted = userPassword == null ? null : userPassword.getEncrypted();
-      char[] password = encrypted == null ? null : encrypted.toCharArray();
-      if (password == null)
-      {
-        throw new SecurityException("No password: " + userID);
-      }
 
-      try
+      String encrypted = userPassword.getEncrypted();
+      if (!Arrays.equals(password, encrypted == null ? null : encrypted.toCharArray()))
       {
-        return SecurityUtil.encrypt(data, password, algorithmName, salt, count);
-      }
-      catch (RuntimeException ex)
-      {
-        throw ex;
-      }
-      catch (Exception ex)
-      {
-        throw new SecurityException(ex);
+        throw new SecurityException("Access denied"); //$NON-NLS-1$
       }
     }
   }
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
index c9110b1..0dc84e5 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
@@ -22,7 +22,6 @@
 import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
 import org.eclipse.emf.cdo.common.lock.CDOLockState;
 import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
 import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
 import org.eclipse.emf.cdo.common.revision.CDORevision;
 import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
@@ -58,6 +57,7 @@
 import org.eclipse.net4j.util.lifecycle.LifecycleState;
 import org.eclipse.net4j.util.ref.ReferenceType;
 import org.eclipse.net4j.util.ref.ReferenceValueMap;
+import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 
 import org.eclipse.emf.common.notify.Adapter;
 import org.eclipse.emf.ecore.EObject;
@@ -941,12 +941,24 @@
       throw new UnsupportedOperationException();
     }
 
-    public CDOAuthenticator getAuthenticator()
+    @Deprecated
+    public org.eclipse.emf.cdo.common.protocol.CDOAuthenticator getAuthenticator()
     {
       throw new UnsupportedOperationException();
     }
 
-    public void setAuthenticator(CDOAuthenticator authenticator)
+    @Deprecated
+    public void setAuthenticator(org.eclipse.emf.cdo.common.protocol.CDOAuthenticator authenticator)
+    {
+      throw new UnsupportedOperationException();
+    }
+
+    public IPasswordCredentialsProvider getCredentialsProvider()
+    {
+      throw new UnsupportedOperationException();
+    }
+
+    public void setCredentialsProvider(IPasswordCredentialsProvider credentialsProvider)
     {
       throw new UnsupportedOperationException();
     }
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
index 3c787f9..03a1c25 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
@@ -23,25 +23,25 @@
 import org.eclipse.emf.cdo.server.IPermissionManager;
 import org.eclipse.emf.cdo.server.ISession;
 import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
-import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
 import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
 import org.eclipse.emf.cdo.spi.server.ISessionProtocol;
 import org.eclipse.emf.cdo.spi.server.InternalRepository;
 import org.eclipse.emf.cdo.spi.server.InternalSession;
 import org.eclipse.emf.cdo.spi.server.InternalSessionManager;
 
-import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
 import org.eclipse.net4j.util.container.Container;
+import org.eclipse.net4j.util.io.ExtendedDataInputStream;
 import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
 import org.eclipse.net4j.util.om.trace.ContextTracer;
-import org.eclipse.net4j.util.security.IRandomizer;
+import org.eclipse.net4j.util.security.DiffieHellman;
+import org.eclipse.net4j.util.security.DiffieHellman.Client.Response;
+import org.eclipse.net4j.util.security.DiffieHellman.Server.Challenge;
+import org.eclipse.net4j.util.security.IAuthenticator;
 import org.eclipse.net4j.util.security.IUserManager;
-import org.eclipse.net4j.util.security.NegotiationException;
-import org.eclipse.net4j.util.security.Randomizer;
-import org.eclipse.net4j.util.security.SecurityUtil;
+import org.eclipse.net4j.util.security.UserManagerAuthenticator;
 
+import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -52,26 +52,13 @@
  */
 public class SessionManager extends Container<ISession> implements InternalSessionManager
 {
-  public static final int DEFAULT_TOKEN_LENGTH = 1024;
-
   private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_SESSION, SessionManager.class);
 
   private InternalRepository repository;
 
-  @ExcludeFromDump
-  private String encryptionAlgorithmName = SecurityUtil.PBE_WITH_MD5_AND_DES;
+  private DiffieHellman.Server authenticationServer;
 
-  @ExcludeFromDump
-  private byte[] encryptionSaltBytes = SecurityUtil.DEFAULT_SALT;
-
-  @ExcludeFromDump
-  private int encryptionIterationCount = SecurityUtil.DEFAULT_ITERATION_COUNT;
-
-  private int tokenLength = DEFAULT_TOKEN_LENGTH;
-
-  private IRandomizer randomizer;
-
-  private IUserManager userManager;
+  private IAuthenticator authenticator;
 
   private IPermissionManager permissionManager;
 
@@ -103,69 +90,48 @@
     this.repository = repository;
   }
 
-  public String getEncryptionAlgorithmName()
-  {
-    return encryptionAlgorithmName;
-  }
-
-  public void setEncryptionAlgorithmName(String encryptionAlgorithmName)
-  {
-    checkInactive();
-    this.encryptionAlgorithmName = encryptionAlgorithmName;
-  }
-
-  public byte[] getEncryptionSaltBytes()
-  {
-    return encryptionSaltBytes;
-  }
-
-  public void setEncryptionSaltBytes(byte[] encryptionSaltBytes)
-  {
-    checkInactive();
-    this.encryptionSaltBytes = encryptionSaltBytes;
-  }
-
-  public int getEncryptionIterationCount()
-  {
-    return encryptionIterationCount;
-  }
-
-  public void setEncryptionIterationCount(int encryptionIterationCount)
-  {
-    checkInactive();
-    this.encryptionIterationCount = encryptionIterationCount;
-  }
-
-  public int getTokenLength()
-  {
-    return tokenLength;
-  }
-
-  public void setTokenLength(int tokenLength)
-  {
-    checkInactive();
-    this.tokenLength = tokenLength;
-  }
-
-  public IRandomizer getRandomizer()
-  {
-    return randomizer;
-  }
-
-  public void setRandomizer(IRandomizer randomizer)
-  {
-    checkInactive();
-    this.randomizer = randomizer;
-  }
-
+  @Deprecated
   public IUserManager getUserManager()
   {
-    return userManager;
+    if (authenticator instanceof UserManagerAuthenticator)
+    {
+      return ((UserManagerAuthenticator)authenticator).getUserManager();
+    }
+
+    return null;
   }
 
+  @Deprecated
   public void setUserManager(IUserManager userManager)
   {
-    this.userManager = userManager;
+    UserManagerAuthenticator userManagerAuthenticator = new UserManagerAuthenticator();
+    userManagerAuthenticator.setUserManager(userManager);
+
+    setAuthenticator(userManagerAuthenticator);
+  }
+
+  public DiffieHellman.Server getAuthenticationServer()
+  {
+    return authenticationServer;
+  }
+
+  public void setAuthenticationServer(DiffieHellman.Server authenticationServer)
+  {
+    this.authenticationServer = authenticationServer;
+  }
+
+  public IAuthenticator getAuthenticator()
+  {
+    return authenticator;
+  }
+
+  public void setAuthenticator(IAuthenticator authenticator)
+  {
+    this.authenticator = authenticator;
+    if (isActive() && authenticator != null)
+    {
+      initAuthentication();
+    }
   }
 
   public IPermissionManager getPermissionManager()
@@ -422,30 +388,27 @@
       return null;
     }
 
-    if (userManager == null)
+    if (authenticationServer == null || authenticator == null)
     {
       return null;
     }
 
     try
     {
-      byte[] randomToken = createRandomToken();
-      CDOAuthenticationResult result = protocol.sendAuthenticationChallenge(randomToken);
-      if (result == null)
+      Challenge challenge = authenticationServer.getChallenge();
+      Response response = protocol.sendAuthenticationChallenge(challenge);
+      if (response == null)
       {
         throw new NotAuthenticatedException();
       }
 
-      String userID = result.getUserID();
+      ByteArrayInputStream baos = new ByteArrayInputStream(authenticationServer.handleResponse(response));
+      ExtendedDataInputStream stream = new ExtendedDataInputStream(baos);
+      String userID = stream.readString();
+      char[] password = stream.readString().toCharArray();
 
-      byte[] cryptedToken = encryptToken(userID, randomToken);
-      boolean success = Arrays.equals(result.getCryptedToken(), cryptedToken);
-      if (success)
-      {
-        return userID;
-      }
-
-      throw new SecurityException("Access denied"); //$NON-NLS-1$
+      authenticator.authenticate(userID, password);
+      return userID;
     }
     catch (SecurityException ex)
     {
@@ -463,47 +426,36 @@
     }
   }
 
-  protected byte[] createRandomToken()
-  {
-    byte[] token = new byte[tokenLength];
-    randomizer.nextBytes(token);
-    return token;
-  }
-
-  protected byte[] encryptToken(String userID, byte[] token) throws NegotiationException
-  {
-    try
-    {
-      return userManager.encrypt(userID, token, getEncryptionAlgorithmName(), getEncryptionSaltBytes(),
-          getEncryptionIterationCount());
-    }
-    catch (Exception ex)
-    {
-      OM.LOG.error("Token encryption failed", ex); //$NON-NLS-1$
-      return null;
-    }
-  }
-
   @Override
   protected void doActivate() throws Exception
   {
     super.doActivate();
+    initAuthentication();
+  }
 
-    if (randomizer == null)
+  protected void initAuthentication()
+  {
+    if (authenticator != null)
     {
-      randomizer = new Randomizer();
-    }
+      if (authenticationServer == null)
+      {
+        authenticationServer = new DiffieHellman.Server();
+      }
 
-    LifecycleUtil.activate(randomizer);
+      LifecycleUtil.activate(authenticationServer);
+      LifecycleUtil.activate(authenticator);
+    }
   }
 
   @Override
   protected void doDeactivate() throws Exception
   {
-    InternalSession[] activeSessions = getSessions();
-    for (int i = 0; i < activeSessions.length; i++)
+    LifecycleUtil.deactivate(authenticator);
+    LifecycleUtil.deactivate(authenticationServer);
+
+    for (InternalSession session : getSessions())
     {
-      LifecycleUtil.deactivate(activeSessions[i]);
+      LifecycleUtil.deactivate(session);
     }
 
     super.doDeactivate();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java
index 53ccdae..37a5297 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedServerSessionProtocol.java
@@ -15,13 +15,14 @@
 import org.eclipse.emf.cdo.common.id.CDOID;
 import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
 import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
-import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
 import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
 import org.eclipse.emf.cdo.spi.server.ISessionProtocol;
 import org.eclipse.emf.cdo.spi.server.InternalRepository;
 import org.eclipse.emf.cdo.spi.server.InternalSession;
 
 import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.security.DiffieHellman.Client.Response;
+import org.eclipse.net4j.util.security.DiffieHellman.Server.Challenge;
 
 /**
  * @author Eike Stepper
@@ -57,11 +58,18 @@
     return session;
   }
 
-  public CDOAuthenticationResult sendAuthenticationChallenge(byte[] randomToken) throws Exception
+  @Deprecated
+  public org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult sendAuthenticationChallenge(byte[] randomToken)
+      throws Exception
   {
     return clientSessionProtocol.handleAuthenticationChallenge(randomToken);
   }
 
+  public Response sendAuthenticationChallenge(Challenge challenge) throws Exception
+  {
+    throw new UnsupportedOperationException();
+  }
+
   public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType)
   {
     EmbeddedClientSession clientSession = clientSessionProtocol.getSession();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISessionManager.java
index b1e4bab..3bc7979 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISessionManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISessionManager.java
@@ -11,10 +11,11 @@
 package org.eclipse.emf.cdo.server;
 
 import org.eclipse.net4j.util.container.IContainer;
+import org.eclipse.net4j.util.security.IAuthenticator;
 
 /**
  * Manages the user {@link ISession sessions} of a {@link IRepository repository}.
- * 
+ *
  * @author Eike Stepper
  * @noextend This interface is not intended to be extended by clients.
  * @noimplement This interface is not intended to be implemented by clients.
@@ -34,4 +35,14 @@
    * @since 2.0
    */
   public ISession getSession(int sessionID);
+
+  /**
+   * @since 4.2
+   */
+  public IAuthenticator getAuthenticator();
+
+  /**
+   * @since 4.2
+   */
+  public void setAuthenticator(IAuthenticator authenticator);
 }
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java
index 56ce4b8..34eee80 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/ISessionProtocol.java
@@ -16,9 +16,11 @@
 import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
 import org.eclipse.emf.cdo.common.protocol.CDOProtocol;
 import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
-import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
 import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
 
+import org.eclipse.net4j.util.security.DiffieHellman.Client.Response;
+import org.eclipse.net4j.util.security.DiffieHellman.Server.Challenge;
+
 /**
  * If the meaning of this type isn't clear, there really should be more of a description here...
  *
@@ -31,8 +33,16 @@
 {
   /**
    * @since 4.0
+   * @deprecated As of 4.2 {@link #sendAuthenticationChallenge(Challenge)} is called.
    */
-  public CDOAuthenticationResult sendAuthenticationChallenge(byte[] randomToken) throws Exception;
+  @Deprecated
+  public org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult sendAuthenticationChallenge(byte[] randomToken)
+      throws Exception;
+
+  /**
+   * @since 4.2
+   */
+  public Response sendAuthenticationChallenge(Challenge challenge) throws Exception;
 
   public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType)
       throws Exception;
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java
index 29af5aa..294bfb9 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java
@@ -19,6 +19,8 @@
 import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
 import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
 
+import org.eclipse.net4j.util.security.DiffieHellman;
+import org.eclipse.net4j.util.security.IAuthenticator;
 import org.eclipse.net4j.util.security.IUserManager;
 
 import java.util.List;
@@ -39,12 +41,28 @@
 
   /**
    * @since 4.1
+   * @deprecated As of 4.2 use {@link #getAuthenticator()}
    */
+  @Deprecated
   public IUserManager getUserManager();
 
+  /**
+   * @deprecated As of 4.2 use {@link #setAuthenticator(IAuthenticator)}
+   */
+  @Deprecated
   public void setUserManager(IUserManager userManager);
 
   /**
+   * @since 4.2
+   */
+  public DiffieHellman.Server getAuthenticationServer();
+
+  /**
+   * @since 4.2
+   */
+  public void setAuthenticationServer(DiffieHellman.Server authenticationServer);
+
+  /**
    * @since 4.1
    */
   public IPermissionManager getPermissionManager();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java
index 293d48d..b68cc86 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryConfigurator.java
@@ -24,7 +24,10 @@
 import org.eclipse.net4j.util.container.IManagedContainer;
 import org.eclipse.net4j.util.om.OMPlatform;
 import org.eclipse.net4j.util.om.trace.ContextTracer;
+import org.eclipse.net4j.util.security.AuthenticatorFactory;
+import org.eclipse.net4j.util.security.IAuthenticator;
 import org.eclipse.net4j.util.security.IUserManager;
+import org.eclipse.net4j.util.security.UserManagerFactory;
 
 import org.eclipse.emf.ecore.EPackage;
 
@@ -170,22 +173,8 @@
     repository.setStore((InternalStore)store);
     repository.setProperties(properties);
 
-    Element userManagerConfig = getUserManagerConfig(repositoryConfig);
-    if (userManagerConfig != null)
-    {
-      IUserManager userManager = getUserManager(userManagerConfig);
-      if (userManager != null)
-      {
-        InternalSessionManager sessionManager = repository.getSessionManager();
-        if (sessionManager == null)
-        {
-          sessionManager = new SessionManager();
-          repository.setSessionManager(sessionManager);
-        }
-
-        sessionManager.setUserManager(userManager);
-      }
-    }
+    setUserManager(repository, repositoryConfig);
+    setAuthenticator(repository, repositoryConfig);
 
     EPackage[] initialPackages = getInitialPackages(repositoryConfig);
     if (initialPackages.length != 0)
@@ -223,7 +212,7 @@
 
   protected IUserManager getUserManager(String type, String description) throws CoreException
   {
-    IUserManager userManager = (IUserManager)container.getElement("org.eclipse.net4j.userManagers", type, description); //$NON-NLS-1$
+    IUserManager userManager = (IUserManager)container.getElement(UserManagerFactory.PRODUCT_GROUP, type, description);
     if (userManager == null)
     {
       throw new IllegalStateException("UserManager factory not found: " + type); //$NON-NLS-1$
@@ -232,6 +221,93 @@
     return userManager;
   }
 
+  /**
+   * @since 4.2
+   */
+  @SuppressWarnings("deprecation")
+  protected void setUserManager(InternalRepository repository, Element repositoryConfig) throws CoreException
+  {
+    Element userManagerConfig = getUserManagerConfig(repositoryConfig);
+    if (userManagerConfig != null)
+    {
+      IUserManager userManager = getUserManager(userManagerConfig);
+      if (userManager != null)
+      {
+        InternalSessionManager sessionManager = repository.getSessionManager();
+        if (sessionManager == null)
+        {
+          sessionManager = new SessionManager();
+          repository.setSessionManager(sessionManager);
+        }
+
+        sessionManager.setUserManager(userManager);
+      }
+    }
+  }
+
+  /**
+   * @since 4.2
+   */
+  protected Element getAuthenticatorConfig(Element repositoryConfig)
+  {
+    NodeList authenticatorConfig = repositoryConfig.getElementsByTagName("authenticator"); //$NON-NLS-1$
+    if (authenticatorConfig.getLength() > 1)
+    {
+      String repositoryName = repositoryConfig.getAttribute("name"); //$NON-NLS-1$
+      throw new IllegalStateException("At most one authenticator must be configured for repository " + repositoryName); //$NON-NLS-1$
+    }
+
+    return (Element)(authenticatorConfig.getLength() > 0 ? authenticatorConfig.item(0) : null);
+  }
+
+  /**
+   * @since 4.2
+   */
+  protected IAuthenticator getAuthenticator(Element authenticatorConfig) throws CoreException
+  {
+    String type = authenticatorConfig.getAttribute("type"); //$NON-NLS-1$
+    String description = authenticatorConfig.getAttribute("description"); //$NON-NLS-1$
+    return getAuthenticator(type, description);
+  }
+
+  /**
+   * @since 4.2
+   */
+  protected IAuthenticator getAuthenticator(String type, String description) throws CoreException
+  {
+    IAuthenticator authenticator = (IAuthenticator)container.getElement(AuthenticatorFactory.PRODUCT_GROUP, type,
+        description);
+    if (authenticator == null)
+    {
+      throw new IllegalStateException("Authenticator factory not found: " + type); //$NON-NLS-1$
+    }
+
+    return authenticator;
+  }
+
+  /**
+   * @since 4.2
+   */
+  protected void setAuthenticator(InternalRepository repository, Element repositoryConfig) throws CoreException
+  {
+    Element authenticatorConfig = getAuthenticatorConfig(repositoryConfig);
+    if (authenticatorConfig != null)
+    {
+      IAuthenticator authenticator = getAuthenticator(authenticatorConfig);
+      if (authenticator != null)
+      {
+        InternalSessionManager sessionManager = repository.getSessionManager();
+        if (sessionManager == null)
+        {
+          sessionManager = new SessionManager();
+          repository.setSessionManager(sessionManager);
+        }
+
+        sessionManager.setAuthenticator(authenticator);
+      }
+    }
+  }
+
   protected EPackage[] getInitialPackages(Element repositoryConfig)
   {
     List<EPackage> result = new ArrayList<EPackage>();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryUserManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryUserManager.java
index b497ac6..6720ab8 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryUserManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/RepositoryUserManager.java
@@ -17,17 +17,21 @@
 import org.eclipse.net4j.util.container.IManagedContainer;
 import org.eclipse.net4j.util.factory.ProductCreationException;
 import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.security.AuthenticatorFactory;
+import org.eclipse.net4j.util.security.IAuthenticator;
 import org.eclipse.net4j.util.security.IUserManager;
 import org.eclipse.net4j.util.security.SecurityUtil;
 import org.eclipse.net4j.util.security.UserManagerFactory;
 
+import java.util.Arrays;
+
 /**
  * If the meaning of this type isn't clear, there really should be more of a description here...
  *
  * @author Eike Stepper
  * @since 4.0
  */
-public abstract class RepositoryUserManager extends Lifecycle implements IUserManager
+public abstract class RepositoryUserManager extends Lifecycle implements IUserManager, IAuthenticator
 {
   private IManagedContainer container;
 
@@ -60,20 +64,9 @@
   public byte[] encrypt(String userID, byte[] data, String algorithmName, byte[] salt, int count)
       throws SecurityException
   {
-    IRepository repository = getRepository(container, repositoryName);
-    if (repository == null)
-    {
-      throw new SecurityException("Repository not found: " + repositoryName); //$NON-NLS-1$
-    }
-
-    char[] password = getPassword(repository, userID);
-    if (password == null)
-    {
-      throw new SecurityException("No such user: " + userID); //$NON-NLS-1$
-    }
-
     try
     {
+      char[] password = getPassword(userID);
       return SecurityUtil.encrypt(data, password, algorithmName, salt, count);
     }
     catch (RuntimeException ex)
@@ -86,11 +79,42 @@
     }
   }
 
+  /**
+   * @since 4.2
+   */
+  public void authenticate(String userID, char[] password) throws SecurityException
+  {
+    char[] userPassword = getPassword(userID);
+    if (!Arrays.equals(password, userPassword))
+    {
+      throw new SecurityException("Access denied"); //$NON-NLS-1$
+    }
+  }
+
   protected IRepository getRepository(IManagedContainer container, String repositoryName)
   {
     return CDOServerUtil.getRepository(container, repositoryName);
   }
 
+  /**
+   * @since 4.2
+   */
+  protected char[] getPassword(String userID)
+  {
+    IRepository repository = getRepository(container, repositoryName);
+    if (repository == null)
+    {
+      throw new SecurityException("Repository not found: " + repositoryName); //$NON-NLS-1$
+    }
+
+    char[] password = getPassword(repository, userID);
+    if (password == null)
+    {
+      throw new SecurityException("No such user: " + userID); //$NON-NLS-1$
+    }
+    return password;
+  }
+
   protected abstract char[] getPassword(IRepository repository, String userID);
 
   public static void prepareContainer(IManagedContainer container, RepositoryUserManagerFactory factory)
@@ -131,6 +155,35 @@
    * If the meaning of this type isn't clear, there really should be more of a description here...
    *
    * @author Eike Stepper
+   * @since 4.2
+   */
+  public static abstract class RepositoryAuthenticatorFactory extends AuthenticatorFactory
+  {
+    protected RepositoryAuthenticatorFactory(String type)
+    {
+      super(type);
+    }
+
+    public final Object create(String description) throws ProductCreationException
+    {
+      RepositoryUserManager userManager = doCreate(description);
+      String repositoryName = getRepositoryName(description);
+      userManager.setRepositoryName(repositoryName);
+      return userManager;
+    }
+
+    protected String getRepositoryName(String description)
+    {
+      return description;
+    }
+
+    protected abstract RepositoryUserManager doCreate(String description) throws ProductCreationException;
+  }
+
+  /**
+   * If the meaning of this type isn't clear, there really should be more of a description here...
+   *
+   * @author Eike Stepper
    */
   public static class RepositoryInjector implements IElementProcessor
   {
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java
index 1cf0345..d80e79f 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java
@@ -100,7 +100,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
 
@@ -206,7 +206,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
 
@@ -332,7 +332,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
 
@@ -454,7 +454,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
 
@@ -568,7 +568,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
 
@@ -677,7 +677,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
 
@@ -786,7 +786,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
 
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
index 6df36ff..4d1fa2e 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
@@ -25,7 +25,6 @@
 import org.eclipse.emf.cdo.view.CDOView;
 
 import org.eclipse.net4j.signal.ISignalProtocol;
-import org.eclipse.net4j.signal.RemoteException;
 import org.eclipse.net4j.signal.SignalProtocol.TimeoutChangedEvent;
 import org.eclipse.net4j.util.WrappedException;
 import org.eclipse.net4j.util.container.ContainerEventAdapter;
@@ -272,7 +271,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD1);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     IRepository repository = getRepository("authrepo2");
 
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
@@ -292,17 +291,17 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD1);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getRepository("authrepo3");
 
     try
     {
       openSession("authrepo3");
-      fail("RemoteException expected");
+      fail("NotAuthenticatedException expected");
     }
-    catch (RemoteException success)
+    catch (NotAuthenticatedException expected)
     {
-      assertEquals(SecurityException.class, success.getCause().getClass());
+      // SUCCESS
     }
   }
 
@@ -312,7 +311,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD1);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getRepository("authrepo4");
 
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER, new PasswordCredentialsProvider(null));
@@ -334,7 +333,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD1);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getRepository("authrepo5");
 
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
@@ -343,11 +342,11 @@
     try
     {
       openSession("authrepo5");
-      fail("RemoteException expected");
+      fail("SecurityException expected");
     }
-    catch (RemoteException success)
+    catch (SecurityException expected)
     {
-      assertEquals(SecurityException.class, success.getCause().getClass());
+      // SUCCESS
     }
   }
 
@@ -357,7 +356,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD1);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getRepository("authrepo6");
 
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
@@ -366,11 +365,11 @@
     try
     {
       openSession("authrepo6");
-      fail("RemoteException expected");
+      fail("NotAuthenticatedException expected");
     }
-    catch (RemoteException success)
+    catch (NotAuthenticatedException expected)
     {
-      assertEquals(SecurityException.class, success.getCause().getClass());
+      // SUCCESS
     }
   }
 
@@ -380,7 +379,7 @@
     userManager.activate();
     userManager.addUser(USER_ID, PASSWORD1);
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getRepository("authrepo7");
 
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
@@ -389,11 +388,11 @@
     try
     {
       openSession("authrepo7");
-      fail("RemoteException expected");
+      fail("NotAuthenticatedException expected");
     }
-    catch (RemoteException success)
+    catch (NotAuthenticatedException expected)
     {
-      assertEquals(SecurityException.class, success.getCause().getClass());
+      // SUCCESS
     }
   }
 
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java
index 5d10660..b3b01e9 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java
@@ -73,7 +73,7 @@
       }
     };
 
-    getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+    getTestProperties().put(RepositoryConfig.PROP_TEST_AUTHENTICATOR, userManager);
     getTestProperties().put(RepositoryConfig.PROP_TEST_PERMISSION_MANAGER, permissionManager);
     getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
         new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
index cb253ee..cb27d1c 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
@@ -73,7 +73,7 @@
 import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
 import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
 import org.eclipse.net4j.util.om.monitor.OMMonitor;
-import org.eclipse.net4j.util.security.IUserManager;
+import org.eclipse.net4j.util.security.IAuthenticator;
 import org.eclipse.net4j.util.tests.AbstractOMTest;
 
 import org.eclipse.emf.spi.cdo.InternalCDOSession;
@@ -98,7 +98,7 @@
 
   public static final String PROP_TEST_SESSION_MANAGER = "test.repository.SessionManager";
 
-  public static final String PROP_TEST_USER_MANAGER = "test.repository.UserManager";
+  public static final String PROP_TEST_AUTHENTICATOR = "test.repository.Authenticator";
 
   public static final String PROP_TEST_PERMISSION_MANAGER = "test.repository.PermissionManager";
 
@@ -514,10 +514,10 @@
 
     repository.setSessionManager(sessionManager);
 
-    IUserManager userManager = getTestUserManager();
-    if (userManager != null)
+    IAuthenticator authenticator = getTestAuthenticator();
+    if (authenticator != null)
     {
-      sessionManager.setUserManager(userManager);
+      sessionManager.setAuthenticator(authenticator);
     }
 
     IPermissionManager permissionManager = getTestPermissionManager();
@@ -559,9 +559,9 @@
     return (InternalSessionManager)getTestProperty(PROP_TEST_SESSION_MANAGER);
   }
 
-  protected IUserManager getTestUserManager()
+  protected IAuthenticator getTestAuthenticator()
   {
-    return (IUserManager)getTestProperty(PROP_TEST_USER_MANAGER);
+    return (IAuthenticator)getTestProperty(PROP_TEST_AUTHENTICATOR);
   }
 
   protected IPermissionManager getTestPermissionManager()
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java
index 0931d8f..8922a07 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java
@@ -106,7 +106,7 @@
     IPasswordCredentialsProvider credentialsProvider = getTestCredentialsProvider();
     if (credentialsProvider != null)
     {
-      configuration.getAuthenticator().setCredentialsProvider(credentialsProvider);
+      configuration.setCredentialsProvider(credentialsProvider);
     }
 
     CDOSession session = configuration.openSession();
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java
index 21cbcef..8620f87 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/util/TestSessionConfiguration.java
@@ -13,12 +13,12 @@
 import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode;
 import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode;
 import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
 import org.eclipse.emf.cdo.session.CDOSession;
 import org.eclipse.emf.cdo.session.CDOSessionConfiguration;
 import org.eclipse.emf.cdo.view.CDOFetchRuleManager;
 
 import org.eclipse.net4j.util.event.Notifier;
+import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 
 /**
  * @author Eike Stepper
@@ -50,7 +50,18 @@
     throw new UnsupportedOperationException();
   }
 
-  public CDOAuthenticator getAuthenticator()
+  @Deprecated
+  public org.eclipse.emf.cdo.common.protocol.CDOAuthenticator getAuthenticator()
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public IPasswordCredentialsProvider getCredentialsProvider()
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public void setCredentialsProvider(IPasswordCredentialsProvider credentialsProvider)
   {
     throw new UnsupportedOperationException();
   }
diff --git a/plugins/org.eclipse.emf.cdo.ui.admin/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.ui.admin/META-INF/MANIFEST.MF
index 7233248..6731712 100644
--- a/plugins/org.eclipse.emf.cdo.ui.admin/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.cdo.ui.admin/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-SymbolicName: org.eclipse.emf.cdo.ui.admin;singleton:=true
-Bundle-Version: 4.1.0.qualifier
+Bundle-Version: 4.1.100.qualifier
 Bundle-Name: %pluginName
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
@@ -15,5 +15,5 @@
  org.eclipse.net4j.ui;bundle-version="[4.0.0,5.0.0)";visibility:=reexport,
  org.eclipse.emf.cdo.ui.shared;bundle-version="[4.0.0,5.0.0)",
  org.eclipse.net4j.ui.shared;bundle-version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.emf.cdo.ui.internal.admin;version="4.1.0";x-internal:=true,
- org.eclipse.emf.cdo.ui.internal.admin.bundle;version="4.1.0";x-internal:=true
+Export-Package: org.eclipse.emf.cdo.ui.internal.admin;version="4.1.100";x-internal:=true,
+ org.eclipse.emf.cdo.ui.internal.admin.bundle;version="4.1.100";x-internal:=true
diff --git a/plugins/org.eclipse.emf.cdo.ui.admin/src/org/eclipse/emf/cdo/ui/internal/admin/CDOAdminView.java b/plugins/org.eclipse.emf.cdo.ui.admin/src/org/eclipse/emf/cdo/ui/internal/admin/CDOAdminView.java
index 495f97a..7e2452c 100644
--- a/plugins/org.eclipse.emf.cdo.ui.admin/src/org/eclipse/emf/cdo/ui/internal/admin/CDOAdminView.java
+++ b/plugins/org.eclipse.emf.cdo.ui.admin/src/org/eclipse/emf/cdo/ui/internal/admin/CDOAdminView.java
@@ -310,7 +310,7 @@
     public void prepare(CDONet4jSessionConfiguration configuration)
     {
       IPasswordCredentialsProvider credentialsProvider = getCredentialsProvider();
-      configuration.getAuthenticator().setCredentialsProvider(credentialsProvider);
+      configuration.setCredentialsProvider(credentialsProvider);
     }
   }
 }
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java
index 5a5b66a..fdafe5d 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSessionConfiguration.java
@@ -13,11 +13,11 @@
 import org.eclipse.emf.cdo.common.CDOCommonSession.Options.LockNotificationMode;
 import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode;
 import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
 import org.eclipse.emf.cdo.view.CDOFetchRuleManager;
 
 import org.eclipse.net4j.util.event.IEvent;
 import org.eclipse.net4j.util.event.INotifier;
+import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 
 /**
  * Configures and opens new {@link CDOSession sessions}.
@@ -125,8 +125,21 @@
 
   /**
    * Returns the authenticator of this configuration, never <code>null</code>.
+   *
+   * @deprecated As of 4.2 use {@link #getCredentialsProvider()} and {@link #setCredentialsProvider(IPasswordCredentialsProvider)}, respectively
    */
-  public CDOAuthenticator getAuthenticator();
+  @Deprecated
+  public org.eclipse.emf.cdo.common.protocol.CDOAuthenticator getAuthenticator();
+
+  /**
+   * @since 4.2
+   */
+  public IPasswordCredentialsProvider getCredentialsProvider();
+
+  /**
+   * @since 4.2
+   */
+  public void setCredentialsProvider(IPasswordCredentialsProvider credentialsProvider);
 
   /**
    * Returns <code>true</code> if the session opened by {@link #openSession()} will be automatically activated,
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOAuthenticatorImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOAuthenticatorImpl.java
index 79a1bf1..295cb1a 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOAuthenticatorImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOAuthenticatorImpl.java
@@ -10,9 +10,6 @@
  */
 package org.eclipse.emf.internal.cdo.session;
 
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
-import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult;
-
 import org.eclipse.net4j.util.security.IPasswordCredentials;
 import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 import org.eclipse.net4j.util.security.SecurityUtil;
@@ -20,7 +17,8 @@
 /**
  * @author Eike Stepper
  */
-public class CDOAuthenticatorImpl implements CDOAuthenticator
+@Deprecated
+public class CDOAuthenticatorImpl implements org.eclipse.emf.cdo.common.protocol.CDOAuthenticator
 {
   private String encryptionAlgorithmName = SecurityUtil.PBE_WITH_MD5_AND_DES;
 
@@ -74,7 +72,7 @@
     this.credentialsProvider = credentialsProvider;
   }
 
-  public CDOAuthenticationResult authenticate(byte[] randomToken)
+  public org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult authenticate(byte[] randomToken)
   {
     if (credentialsProvider == null)
     {
@@ -86,7 +84,7 @@
     {
       String userID = credentials.getUserID();
       byte[] cryptedToken = encryptToken(credentials.getPassword(), randomToken);
-      return new CDOAuthenticationResult(userID, cryptedToken);
+      return new org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult(userID, cryptedToken);
     }
 
     return null;
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java
index 18a2ced..e723e0e 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionConfigurationImpl.java
@@ -16,7 +16,6 @@
 import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager;
 import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
 import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
 import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
 import org.eclipse.emf.cdo.session.CDOSession;
 import org.eclipse.emf.cdo.session.CDOSessionConfiguration;
@@ -32,6 +31,7 @@
 import org.eclipse.net4j.util.event.Notifier;
 import org.eclipse.net4j.util.lifecycle.ILifecycle;
 import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
+import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 
 import org.eclipse.emf.spi.cdo.InternalCDOSession;
 import org.eclipse.emf.spi.cdo.InternalCDOSessionConfiguration;
@@ -49,7 +49,7 @@
 
   private LockNotificationMode lockNotificationMode = LockNotificationMode.IF_REQUIRED_BY_VIEWS;
 
-  private CDOAuthenticator authenticator = new CDOAuthenticatorImpl();
+  private IPasswordCredentialsProvider credentialsProvider;
 
   private CDOSession.ExceptionHandler exceptionHandler;
 
@@ -155,15 +155,64 @@
     this.lockNotificationMode = lockNotificationMode;
   }
 
-  public CDOAuthenticator getAuthenticator()
+  @Deprecated
+  public org.eclipse.emf.cdo.common.protocol.CDOAuthenticator getAuthenticator()
   {
-    return authenticator;
+    return new org.eclipse.emf.cdo.common.protocol.CDOAuthenticator()
+    {
+      public String getEncryptionAlgorithmName()
+      {
+        return null;
+      }
+
+      public void setEncryptionAlgorithmName(String encryptionAlgorithmName)
+      {
+      }
+
+      public byte[] getEncryptionSaltBytes()
+      {
+        return null;
+      }
+
+      public void setEncryptionSaltBytes(byte[] encryptionSaltBytes)
+      {
+      }
+
+      public int getEncryptionIterationCount()
+      {
+        return 0;
+      }
+
+      public void setEncryptionIterationCount(int encryptionIterationCount)
+      {
+      }
+
+      public IPasswordCredentialsProvider getCredentialsProvider()
+      {
+        return CDOSessionConfigurationImpl.this.getCredentialsProvider();
+      }
+
+      public void setCredentialsProvider(IPasswordCredentialsProvider credentialsProvider)
+      {
+        CDOSessionConfigurationImpl.this.setCredentialsProvider(credentialsProvider);
+      }
+
+      public org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult authenticate(byte[] randomToken)
+      {
+        throw new UnsupportedOperationException();
+      }
+    };
   }
 
-  public void setAuthenticator(CDOAuthenticator authenticator)
+  public IPasswordCredentialsProvider getCredentialsProvider()
+  {
+    return credentialsProvider;
+  }
+
+  public void setCredentialsProvider(IPasswordCredentialsProvider credentialsProvider)
   {
     checkNotOpen();
-    this.authenticator = authenticator;
+    this.credentialsProvider = credentialsProvider;
   }
 
   public CDOSession.ExceptionHandler getExceptionHandler()
@@ -324,7 +373,7 @@
     session.setExceptionHandler(exceptionHandler);
     session.setFetchRuleManager(fetchRuleManager);
     session.setIDGenerator(idGenerator);
-    session.setAuthenticator(authenticator);
+    session.setCredentialsProvider(credentialsProvider);
     session.setRevisionManager(revisionManager);
     session.setBranchManager(branchManager);
     session.setCommitInfoManager(commitInfoManager);
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
index c773c24..a6b3860 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
@@ -31,7 +31,6 @@
 import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
 import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
 import org.eclipse.emf.cdo.common.model.EMFUtil;
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
 import org.eclipse.emf.cdo.common.revision.CDOElementProxy;
 import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
 import org.eclipse.emf.cdo.common.revision.CDOList;
@@ -109,6 +108,7 @@
 import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
 import org.eclipse.net4j.util.om.log.OMLogger;
 import org.eclipse.net4j.util.options.OptionsEvent;
+import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 
 import org.eclipse.emf.common.util.ECollections;
 import org.eclipse.emf.ecore.EPackage;
@@ -197,7 +197,7 @@
 
   private boolean mainBranchLocal;
 
-  private CDOAuthenticator authenticator;
+  private IPasswordCredentialsProvider credentialsProvider;
 
   private InternalCDORemoteSessionManager remoteSessionManager;
 
@@ -365,14 +365,26 @@
     this.fetchRuleManager = fetchRuleManager;
   }
 
-  public CDOAuthenticator getAuthenticator()
+  @Deprecated
+  public org.eclipse.emf.cdo.common.protocol.CDOAuthenticator getAuthenticator()
   {
-    return authenticator;
+    throw new UnsupportedOperationException();
   }
 
-  public void setAuthenticator(CDOAuthenticator authenticator)
+  @Deprecated
+  public void setAuthenticator(org.eclipse.emf.cdo.common.protocol.CDOAuthenticator authenticator)
   {
-    this.authenticator = authenticator;
+    throw new UnsupportedOperationException();
+  }
+
+  public IPasswordCredentialsProvider getCredentialsProvider()
+  {
+    return credentialsProvider;
+  }
+
+  public void setCredentialsProvider(IPasswordCredentialsProvider credentialsProvider)
+  {
+    this.credentialsProvider = credentialsProvider;
   }
 
   public boolean isMainBranchLocal()
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java
index 4b8e402..f5755ee 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSession.java
@@ -19,7 +19,6 @@
 import org.eclipse.emf.cdo.common.id.CDOIDGenerator;
 import org.eclipse.emf.cdo.common.lob.CDOLobStore;
 import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
 import org.eclipse.emf.cdo.common.revision.CDORevision;
 import org.eclipse.emf.cdo.session.CDORepositoryInfo;
 import org.eclipse.emf.cdo.session.CDOSession;
@@ -36,6 +35,7 @@
 import org.eclipse.emf.cdo.view.CDOFetchRuleManager;
 
 import org.eclipse.net4j.util.lifecycle.ILifecycle;
+import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
 
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.spi.cdo.CDOSessionProtocol.RefreshSessionResult;
@@ -63,13 +63,27 @@
 
   /**
    * @since 4.0
+   * @deprecated As of 4.2 use {@link #getCredentialsProvider()}
    */
-  public CDOAuthenticator getAuthenticator();
+  @Deprecated
+  public org.eclipse.emf.cdo.common.protocol.CDOAuthenticator getAuthenticator();
 
   /**
    * @since 4.0
+   * @deprecated As of 4.2 use {@link #setCredentialsProvider(IPasswordCredentialsProvider)}
    */
-  public void setAuthenticator(CDOAuthenticator authenticator);
+  @Deprecated
+  public void setAuthenticator(org.eclipse.emf.cdo.common.protocol.CDOAuthenticator authenticator);
+
+  /**
+   * @since 4.2
+   */
+  public IPasswordCredentialsProvider getCredentialsProvider();
+
+  /**
+   * @since 4.2
+   */
+  public void setCredentialsProvider(IPasswordCredentialsProvider credentialsProvider);
 
   public InternalCDOPackageRegistry getPackageRegistry();
 
diff --git a/plugins/org.eclipse.net4j.util/plugin.xml b/plugins/org.eclipse.net4j.util/plugin.xml
index 0250e90..0a37bfa 100644
--- a/plugins/org.eclipse.net4j.util/plugin.xml
+++ b/plugins/org.eclipse.net4j.util/plugin.xml
@@ -6,7 +6,7 @@
 	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:
 	  Eike Stepper - initial API and implementation
 -->
@@ -15,7 +15,7 @@
 
    <extension-point id="factories" name="%extension-point.name" schema="schema/factories.exsd"/>
    <extension-point id="elementProcessors" name="%extension-point.name.0" schema="schema/elementProcessors.exsd"/>
-   
+
    <extension
          point="org.eclipse.net4j.util.factories">
       <factory
@@ -34,6 +34,10 @@
             productGroup="org.eclipse.net4j.userManagers"
             type="file"
             class="org.eclipse.net4j.util.security.FileUserManagerFactory"/>
+      <factory
+            productGroup="org.eclipse.net4j.authenticators"
+            type="file"
+            class="org.eclipse.net4j.util.security.FileAuthenticatorFactory"/>
    </extension>
 
 </plugin>
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/AuthenticatorFactory.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/AuthenticatorFactory.java
new file mode 100644
index 0000000..6aadef0
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/AuthenticatorFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) 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:
+ *    Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.security;
+
+import org.eclipse.net4j.util.factory.Factory;
+
+/**
+ * @author Eike Stepper
+ * @since 3.3
+ */
+public abstract class AuthenticatorFactory extends Factory
+{
+  public static final String PRODUCT_GROUP = "org.eclipse.net4j.authenticators"; //$NON-NLS-1$
+
+  public AuthenticatorFactory(String type)
+  {
+    super(PRODUCT_GROUP, type);
+  }
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/DiffieHellman.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/DiffieHellman.java
new file mode 100644
index 0000000..b484fd2
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/DiffieHellman.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) 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:
+ *    Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.security;
+
+import org.eclipse.net4j.util.io.ExtendedDataInput;
+import org.eclipse.net4j.util.io.ExtendedDataOutput;
+import org.eclipse.net4j.util.io.IORuntimeException;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+/**
+ * Executes the Diffie-Hellman key agreement protocol between 2 parties: {@link Server} and {@link Client}.
+ *
+ * @author Eike Stepper
+ * @since 3.3
+ */
+public class DiffieHellman
+{
+  public static void main(String argv[]) throws Exception
+  {
+    byte[] clearText = "This is just an example".getBytes();
+
+    // Server server = new Server(SkipParameterSpec.INSTANCE, "DES", "DES/ECB/PKCS5Padding");
+    Server server = new Server(SkipParameterSpec.INSTANCE, "DES", "DES/CBC/PKCS5Padding");
+    Client client = new Client();
+
+    Server.Challenge challenge = server.getChallenge();
+    Client.Response result = client.handleChallenge(challenge, clearText);
+    byte[] recovered = server.handleResponse(result);
+
+    if (!Arrays.equals(clearText, recovered))
+    {
+      throw new Exception("Recovered text is different from cleartext");
+    }
+
+    System.out.println("Recovered text is same as cleartext");
+  }
+
+  /**
+   * Executes the server-side of the Diffie-Hellman key agreement protocol.
+   *
+   * @author Eike Stepper
+   */
+  public static class Server
+  {
+    public static final String DEFAULT_SECRET_ALGORITHM = "DES";
+
+    public static final String DEFAULT_CYPHER_TRANSFORMATION = "DES/CBC/PKCS5Padding";
+
+    private final KeyAgreement keyAgree;
+
+    private final Challenge challenge;
+
+    public Server(DHParameterSpec dhParamSpec, String secretAlgorithm, String cypherTransformation)
+    {
+      try
+      {
+        // Create DH key pair, using the passed DH parameters
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
+        keyPairGenerator.initialize(dhParamSpec);
+        KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+        // Create and initialize DH KeyAgreement object
+        keyAgree = KeyAgreement.getInstance("DH");
+        keyAgree.init(keyPair.getPrivate());
+
+        // Encode public key
+        byte[] pubKeyEnc = keyPair.getPublic().getEncoded();
+
+        // Create and remember Challenge object
+        challenge = new Challenge(secretAlgorithm, cypherTransformation, pubKeyEnc);
+      }
+      catch (GeneralSecurityException ex)
+      {
+        throw new SecurityException(ex);
+      }
+    }
+
+    public Server(DHParameterSpec dhParamSpec)
+    {
+      this(dhParamSpec, DEFAULT_SECRET_ALGORITHM, DEFAULT_CYPHER_TRANSFORMATION);
+    }
+
+    public Server()
+    {
+      this(SkipParameterSpec.INSTANCE);
+    }
+
+    public final Challenge getChallenge()
+    {
+      return challenge;
+    }
+
+    public byte[] handleResponse(Client.Response response)
+    {
+      try
+      {
+        // Instantiate a DH public key from the client's encoded key material.
+        KeyFactory keyFactory = KeyFactory.getInstance("DH");
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(response.getClientPubKeyEnc());
+        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
+
+        // Use Client's public key for the first (and only) phase of her version of the DH protocol.
+        keyAgree.doPhase(pubKey, true);
+        SecretKey sharedSecret = keyAgree.generateSecret(challenge.getSecretAlgorithm());
+
+        // Prepare the cipher used to decrypt
+        Cipher serverCipher = Cipher.getInstance(challenge.getCypherTransformation());
+
+        byte[] encodedParams = response.getParamsEnc();
+        if (encodedParams == null)
+        {
+          serverCipher.init(Cipher.DECRYPT_MODE, sharedSecret);
+        }
+        else
+        {
+          // Instantiate AlgorithmParameters object from parameter encoding obtained from client
+          AlgorithmParameters params = AlgorithmParameters.getInstance(challenge.getSecretAlgorithm());
+          params.init(encodedParams);
+
+          serverCipher.init(Cipher.DECRYPT_MODE, sharedSecret, params);
+        }
+
+        // Decrypt
+        return serverCipher.doFinal(response.getCipherText());
+      }
+      catch (GeneralSecurityException ex)
+      {
+        throw new SecurityException(ex);
+      }
+      catch (IOException ex)
+      {
+        throw new IORuntimeException(ex);
+      }
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static final class Challenge
+    {
+      private final String secretAlgorithm;
+
+      private final String cypherTransformation;
+
+      private final byte[] serverPubKeyEnc;
+
+      public Challenge(String secretAlgorithm, String cypherTransformation, byte[] serverPubKeyEnc)
+      {
+        this.secretAlgorithm = secretAlgorithm;
+        this.cypherTransformation = cypherTransformation;
+        this.serverPubKeyEnc = serverPubKeyEnc;
+      }
+
+      public Challenge(ExtendedDataInput in) throws IOException
+      {
+        secretAlgorithm = in.readString();
+        cypherTransformation = in.readString();
+        serverPubKeyEnc = in.readByteArray();
+      }
+
+      public void write(ExtendedDataOutput out) throws IOException
+      {
+        out.writeString(secretAlgorithm);
+        out.writeString(cypherTransformation);
+        out.writeByteArray(serverPubKeyEnc);
+      }
+
+      public String getSecretAlgorithm()
+      {
+        return secretAlgorithm;
+      }
+
+      public String getCypherTransformation()
+      {
+        return cypherTransformation;
+      }
+
+      public byte[] getServerPubKeyEnc()
+      {
+        return serverPubKeyEnc;
+      }
+    }
+  }
+
+  /**
+   * Executes the client-side of the Diffie-Hellman key agreement protocol.
+   *
+   * @author Eike Stepper
+   */
+  public static class Client
+  {
+    public Client()
+    {
+    }
+
+    public Response handleChallenge(Server.Challenge challenge, byte[] clearText)
+    {
+      try
+      {
+        KeyFactory keyFactory = KeyFactory.getInstance("DH");
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(challenge.getServerPubKeyEnc());
+        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
+
+        // Use the DH parameters associated with the server's public key to generate own key pair
+        DHParameterSpec dhParamSpec = ((DHPublicKey)pubKey).getParams();
+
+        // Create own DH key pair
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
+        keyPairGenerator.initialize(dhParamSpec);
+        KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+        // Create and initialize DH KeyAgreement object
+        KeyAgreement clientKeyAgree = KeyAgreement.getInstance("DH");
+        clientKeyAgree.init(keyPair.getPrivate());
+
+        // Encode public key
+        byte[] pubKeyEnc = keyPair.getPublic().getEncoded();
+
+        // Use server's public key for the first (and only) phase of his version of the DH protocol
+        clientKeyAgree.doPhase(pubKey, true);
+        SecretKey sharedSecret = clientKeyAgree.generateSecret(challenge.getSecretAlgorithm());
+
+        // Encrypt
+        Cipher clientCipher = Cipher.getInstance(challenge.getCypherTransformation());
+        clientCipher.init(Cipher.ENCRYPT_MODE, sharedSecret);
+        byte[] ciphertext = clientCipher.doFinal(clearText);
+
+        // Retrieve the parameter that was used, and transfer it to the server in encoded format
+        AlgorithmParameters params = clientCipher.getParameters();
+        byte[] paramsEnc = params == null ? null : params.getEncoded();
+
+        return new Response(pubKeyEnc, ciphertext, paramsEnc);
+      }
+      catch (GeneralSecurityException ex)
+      {
+        throw new SecurityException(ex);
+      }
+      catch (IOException ex)
+      {
+        throw new IORuntimeException(ex);
+      }
+    }
+
+    /**
+     * @author Eike Stepper
+     */
+    public static final class Response
+    {
+      private final byte[] clientPubKeyEnc;
+
+      private final byte[] cipherText;
+
+      private final byte[] paramsEnc;
+
+      public Response(byte[] clientPubKeyEnc, byte[] cipherText, byte[] paramsEnc)
+      {
+        this.clientPubKeyEnc = clientPubKeyEnc;
+        this.cipherText = cipherText;
+        this.paramsEnc = paramsEnc;
+      }
+
+      public Response(ExtendedDataInput in) throws IOException
+      {
+        clientPubKeyEnc = in.readByteArray();
+        cipherText = in.readByteArray();
+        paramsEnc = in.readByteArray();
+      }
+
+      public void write(ExtendedDataOutput out) throws IOException
+      {
+        out.writeByteArray(clientPubKeyEnc);
+        out.writeByteArray(cipherText);
+        out.writeByteArray(paramsEnc);
+      }
+
+      public byte[] getClientPubKeyEnc()
+      {
+        return clientPubKeyEnc;
+      }
+
+      public byte[] getCipherText()
+      {
+        return cipherText;
+      }
+
+      public byte[] getParamsEnc()
+      {
+        return paramsEnc;
+      }
+    }
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static final class SkipParameterSpec
+  {
+    /**
+     * The 1024 bit Diffie-Hellman modulus values used by SKIP
+     */
+    private static final byte skip1024ModulusBytes[] = { (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E,
+        (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91, (byte)0x07,
+        (byte)0x36, (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F,
+        (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6,
+        (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18,
+        (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38, (byte)0xD3,
+        (byte)0x34, (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18,
+        (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
+        (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84,
+        (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19, (byte)0xC8,
+        (byte)0x07, (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F,
+        (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08,
+        (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD,
+        (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2, (byte)0x5E,
+        (byte)0xC3, (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 };
+
+    /**
+     * The SKIP 1024 bit modulus
+     */
+    private static final BigInteger skip1024Modulus = new BigInteger(1, skip1024ModulusBytes);
+
+    /**
+     * The base used with the SKIP 1024 bit modulus
+     */
+    private static final BigInteger skip1024Base = BigInteger.valueOf(2);
+
+    public static final DHParameterSpec INSTANCE = new DHParameterSpec(skip1024Modulus, skip1024Base);
+  }
+
+  /**
+   * Creates Diffie-Hellman parameters.
+   *
+   * @author Eike Stepper
+   */
+  public static final class ParameterSpecGenerator
+  {
+    /**
+     * Create Diffie-Hellman parameters.
+     * <p>
+     * Takes VERY long...
+     */
+    public static DHParameterSpec generate(int bits)
+    {
+      try
+      {
+        AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH");
+        paramGen.init(bits);
+
+        AlgorithmParameters params = paramGen.generateParameters();
+        return params.getParameterSpec(DHParameterSpec.class);
+      }
+      catch (GeneralSecurityException ex)
+      {
+        throw new SecurityException(ex);
+      }
+    }
+  }
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/FileAuthenticatorFactory.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/FileAuthenticatorFactory.java
new file mode 100644
index 0000000..24c10df
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/FileAuthenticatorFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) 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:
+ *    Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.security;
+
+/**
+ * TODO Consider file attributes when creating initially empty file
+ *
+ * @author Eike Stepper
+ * @since 3.3
+ */
+public class FileAuthenticatorFactory extends AuthenticatorFactory
+{
+  public static final String TYPE = "file"; //$NON-NLS-1$
+
+  public FileAuthenticatorFactory()
+  {
+    super(TYPE);
+  }
+
+  public FileUserManager create(String description)
+  {
+    FileUserManager userManager = new FileUserManager();
+    userManager.setFileName(description);
+    return userManager;
+  }
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IAuthenticator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IAuthenticator.java
new file mode 100644
index 0000000..f38df45
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/IAuthenticator.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) 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:
+ *    Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.security;
+
+/**
+ * Authenticates users.
+ *
+ * @author Eike Stepper
+ * @since 3.3
+ */
+public interface IAuthenticator
+{
+  /**
+   * Authenticates the user with the passed <code>userID</code> by checking whether the supplied <code>password</code>
+   * matches the password <i>stored</i> for this user.
+   * <p>
+   * The implementation is required to throw a {@link SecurityException} if the passwords do <b>not</b> match.
+   */
+  public void authenticate(String userID, char[] password) throws SecurityException;
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java
index 03d8752..f7f1b61 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java
@@ -14,13 +14,14 @@
 import org.eclipse.net4j.util.io.IORuntimeException;
 import org.eclipse.net4j.util.lifecycle.Lifecycle;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
 /**
  * @author Eike Stepper
  */
-public class UserManager extends Lifecycle implements IUserManager
+public class UserManager extends Lifecycle implements IUserManager, IAuthenticator
 {
   @ExcludeFromDump
   protected transient Map<String, char[]> users = new HashMap<String, char[]>();
@@ -44,6 +45,36 @@
   }
 
   /**
+   * @since 3.3
+   */
+  public char[] getPassword(String userID)
+  {
+    return users.get(userID);
+  }
+
+  /**
+   * @since 3.3
+   */
+  public void authenticate(String userID, char[] password)
+  {
+    char[] userPassword;
+    synchronized (this)
+    {
+      userPassword = users.get(userID);
+    }
+
+    if (userPassword == null)
+    {
+      throw new SecurityException("No such user: " + userID); //$NON-NLS-1$
+    }
+
+    if (!Arrays.equals(userPassword, password))
+    {
+      throw new SecurityException("Wrong password for user: " + userID); //$NON-NLS-1$
+    }
+  }
+
+  /**
    * @since 2.0
    */
   public byte[] encrypt(String userID, byte[] data, String algorithmName, byte[] salt, int count)
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManagerAuthenticator.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManagerAuthenticator.java
new file mode 100644
index 0000000..235ff76
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManagerAuthenticator.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) 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:
+ *    Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.util.security;
+
+import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+
+import java.util.Arrays;
+
+/**
+ * @author Eike Stepper
+ * @since 3.3
+ */
+public class UserManagerAuthenticator extends Lifecycle implements IAuthenticator
+{
+  public static final int DEFAULT_TOKEN_LENGTH = 1024;
+
+  @ExcludeFromDump
+  private String encryptionAlgorithmName = SecurityUtil.PBE_WITH_MD5_AND_DES;
+
+  @ExcludeFromDump
+  private byte[] encryptionSaltBytes = SecurityUtil.DEFAULT_SALT;
+
+  @ExcludeFromDump
+  private int encryptionIterationCount = SecurityUtil.DEFAULT_ITERATION_COUNT;
+
+  private int tokenLength = DEFAULT_TOKEN_LENGTH;
+
+  private IRandomizer randomizer;
+
+  private IUserManager userManager;
+
+  public UserManagerAuthenticator()
+  {
+  }
+
+  public String getEncryptionAlgorithmName()
+  {
+    return encryptionAlgorithmName;
+  }
+
+  public void setEncryptionAlgorithmName(String encryptionAlgorithmName)
+  {
+    checkInactive();
+    this.encryptionAlgorithmName = encryptionAlgorithmName;
+  }
+
+  public byte[] getEncryptionSaltBytes()
+  {
+    return encryptionSaltBytes;
+  }
+
+  public void setEncryptionSaltBytes(byte[] encryptionSaltBytes)
+  {
+    checkInactive();
+    this.encryptionSaltBytes = encryptionSaltBytes;
+  }
+
+  public int getEncryptionIterationCount()
+  {
+    return encryptionIterationCount;
+  }
+
+  public void setEncryptionIterationCount(int encryptionIterationCount)
+  {
+    checkInactive();
+    this.encryptionIterationCount = encryptionIterationCount;
+  }
+
+  public int getTokenLength()
+  {
+    return tokenLength;
+  }
+
+  public void setTokenLength(int tokenLength)
+  {
+    checkInactive();
+    this.tokenLength = tokenLength;
+  }
+
+  public IRandomizer getRandomizer()
+  {
+    return randomizer;
+  }
+
+  public void setRandomizer(IRandomizer randomizer)
+  {
+    checkInactive();
+    this.randomizer = randomizer;
+  }
+
+  public IUserManager getUserManager()
+  {
+    return userManager;
+  }
+
+  public void setUserManager(IUserManager userManager)
+  {
+    checkInactive();
+    this.userManager = userManager;
+  }
+
+  public void authenticate(String userID, char[] password) throws SecurityException
+  {
+    try
+    {
+      byte[] randomToken = createRandomToken();
+      byte[] cryptedTokenClient = SecurityUtil.encrypt(randomToken, password, encryptionAlgorithmName,
+          encryptionSaltBytes, encryptionIterationCount);
+
+      byte[] cryptedTokenServer = userManager.encrypt(userID, randomToken, encryptionAlgorithmName,
+          encryptionSaltBytes, encryptionIterationCount);
+
+      if (!Arrays.equals(cryptedTokenClient, cryptedTokenServer))
+      {
+        throw new SecurityException("Access denied"); //$NON-NLS-1$
+      }
+    }
+    catch (SecurityException ex)
+    {
+      throw ex;
+    }
+    catch (Exception ex)
+    {
+      Throwable cause = ex.getCause();
+      if (cause instanceof SecurityException)
+      {
+        throw (SecurityException)cause;
+      }
+
+      throw new SecurityException(ex);
+    }
+  }
+
+  @Override
+  protected void doBeforeActivate() throws Exception
+  {
+    super.doBeforeActivate();
+    checkState(userManager, "userManager");
+  }
+
+  @Override
+  protected void doActivate() throws Exception
+  {
+    super.doActivate();
+
+    if (randomizer == null)
+    {
+      randomizer = new Randomizer();
+    }
+
+    LifecycleUtil.activate(randomizer);
+  }
+
+  protected byte[] createRandomToken()
+  {
+    byte[] token = new byte[tokenLength];
+    randomizer.nextBytes(token);
+    return token;
+  }
+}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManagerFactory.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManagerFactory.java
index 5b03f1f..44feb6f 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManagerFactory.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManagerFactory.java
@@ -4,7 +4,7 @@
  * 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:
  *    Eike Stepper - initial API and implementation
  */