]> source.dussan.org Git - gitblit.git/commitdiff
Create base unit test class for LDAP tests.
authorFlorian Zschocke <florian.zschocke@devolo.de>
Wed, 23 Nov 2016 01:48:38 +0000 (02:48 +0100)
committerFlorian Zschocke <florian.zschocke@devolo.de>
Wed, 23 Nov 2016 01:48:38 +0000 (02:48 +0100)
Extract the creation of the in-memory servers and the interceptor
code to a base class that LDAP related unit tests can extend to
have the servers available.

src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
src/test/java/com/gitblit/tests/LdapBasedUnitTest.java [new file with mode: 0644]

index b7a77fc244b6f06656c15359d56780abbb5e48e8..4f79edfb844de6905333bf92ff60edf70bd2440f 100644 (file)
@@ -18,25 +18,10 @@ package com.gitblit.tests;
 
 import static org.junit.Assume.*;
 
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.io.FileUtils;
-import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
 import com.gitblit.Constants.AccountType;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
@@ -50,26 +35,8 @@ import com.gitblit.models.UserModel;
 import com.gitblit.tests.mock.MemorySettings;
 import com.gitblit.utils.XssFilter;
 import com.gitblit.utils.XssFilter.AllowXssFilter;
-import com.unboundid.ldap.listener.InMemoryDirectoryServer;
-import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
-import com.unboundid.ldap.listener.InMemoryDirectoryServerSnapshot;
-import com.unboundid.ldap.listener.InMemoryListenerConfig;
-import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedRequest;
-import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedResult;
-import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchEntry;
-import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchRequest;
-import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
-import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSimpleBindResult;
-import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
-import com.unboundid.ldap.sdk.BindRequest;
-import com.unboundid.ldap.sdk.BindResult;
-import com.unboundid.ldap.sdk.LDAPException;
-import com.unboundid.ldap.sdk.LDAPResult;
-import com.unboundid.ldap.sdk.OperationType;
-import com.unboundid.ldap.sdk.ResultCode;
 import com.unboundid.ldap.sdk.SearchResult;
 import com.unboundid.ldap.sdk.SearchScope;
-import com.unboundid.ldap.sdk.SimpleBindRequest;
 import com.unboundid.ldif.LDIFReader;
 
 /**
@@ -80,68 +47,7 @@ import com.unboundid.ldif.LDIFReader;
  *
  */
 @RunWith(Parameterized.class)
-public class LdapAuthenticationTest extends GitblitUnitTest {
-
-       private static final String RESOURCE_DIR = "src/test/resources/ldap/";
-       private static final String DIRECTORY_MANAGER = "cn=Directory Manager";
-       private static final String USER_MANAGER = "cn=UserManager";
-       private static final String ACCOUNT_BASE = "OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain";
-       private static final String GROUP_BASE  = "OU=Groups,OU=UserControl,OU=MyOrganization,DC=MyDomain";
-
-
-       /**
-        * Enumeration of different test modes, representing different use scenarios.
-        * With ANONYMOUS anonymous binds are used to search LDAP.
-        * DS_MANAGER will use a DIRECTORY_MANAGER to search LDAP. Normal users are prohibited to search the DS.
-        * With USR_MANAGER, a USER_MANAGER account is used to search in LDAP. This account can only search users
-        * but not groups. Normal users can search groups, though.
-        *
-        */
-       enum AuthMode {
-               ANONYMOUS(1389),
-               DS_MANAGER(2389),
-               USR_MANAGER(3389);
-
-
-               private int ldapPort;
-               private InMemoryDirectoryServer ds;
-               private InMemoryDirectoryServerSnapshot dsSnapshot;
-
-               AuthMode(int port) {
-                       this.ldapPort = port;
-               }
-
-               int ldapPort() {
-                       return this.ldapPort;
-               }
-
-               void setDS(InMemoryDirectoryServer ds) {
-                       if (this.ds == null) {
-                               this.ds = ds;
-                               this.dsSnapshot = ds.createSnapshot();
-                       };
-               }
-
-               InMemoryDirectoryServer getDS() {
-                       return ds;
-               }
-
-               void restoreSnapshot() {
-                       ds.restoreSnapshot(dsSnapshot);
-               }
-       };
-
-
-
-       @Parameter
-       public AuthMode authMode;
-
-       @Rule
-       public TemporaryFolder folder = new TemporaryFolder();
-
-       private File usersConf;
-
-
+public class LdapAuthenticationTest extends LdapBasedUnitTest {
 
        private LdapAuthProvider ldap;
 
@@ -149,87 +55,9 @@ public class LdapAuthenticationTest extends GitblitUnitTest {
 
        private AuthenticationManager auth;
 
-       private MemorySettings settings;
-
-
-       /**
-        * Run the tests with each authentication scenario once.
-        */
-       @Parameters(name = "{0}")
-       public static Collection<Object[]> data() {
-               return Arrays.asList(new Object[][] { {AuthMode.ANONYMOUS}, {AuthMode.DS_MANAGER}, {AuthMode.USR_MANAGER} });
-       }
-
-
-
-       /**
-        * Create three different in memory DS.
-        *
-        * Each DS has a different configuration:
-        * The first allows anonymous binds.
-        * The second requires authentication for all operations. It will only allow the DIRECTORY_MANAGER account
-        * to search for users and groups.
-        * The third one is like the second, but it allows users to search for users and groups, and restricts the
-        * USER_MANAGER from searching for groups.
-        */
-       @BeforeClass
-       public static void init() throws Exception {
-               InMemoryDirectoryServer ds;
-               InMemoryDirectoryServerConfig config = createInMemoryLdapServerConfig(AuthMode.ANONYMOUS);
-               config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", AuthMode.ANONYMOUS.ldapPort()));
-               ds = createInMemoryLdapServer(config);
-               AuthMode.ANONYMOUS.setDS(ds);
-
-
-               config = createInMemoryLdapServerConfig(AuthMode.DS_MANAGER);
-               config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", AuthMode.DS_MANAGER.ldapPort()));
-               config.setAuthenticationRequiredOperationTypes(EnumSet.allOf(OperationType.class));
-               ds = createInMemoryLdapServer(config);
-               AuthMode.DS_MANAGER.setDS(ds);
-
-
-               config = createInMemoryLdapServerConfig(AuthMode.USR_MANAGER);
-               config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", AuthMode.USR_MANAGER.ldapPort()));
-               config.setAuthenticationRequiredOperationTypes(EnumSet.allOf(OperationType.class));
-               ds = createInMemoryLdapServer(config);
-               AuthMode.USR_MANAGER.setDS(ds);
-
-       }
-
-       @AfterClass
-       public static void destroy() throws Exception {
-               for (AuthMode am : AuthMode.values()) {
-                       am.getDS().shutDown(true);
-               }
-       }
-
-       public static InMemoryDirectoryServer createInMemoryLdapServer(InMemoryDirectoryServerConfig config) throws Exception {
-               InMemoryDirectoryServer imds = new InMemoryDirectoryServer(config);
-               imds.importFromLDIF(true, RESOURCE_DIR + "sampledata.ldif");
-               imds.startListening();
-               return imds;
-       }
-
-       public static InMemoryDirectoryServerConfig createInMemoryLdapServerConfig(AuthMode authMode) throws Exception {
-               InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=MyDomain");
-               config.addAdditionalBindCredentials(DIRECTORY_MANAGER, "password");
-               config.addAdditionalBindCredentials(USER_MANAGER, "passwd");
-               config.setSchema(null);
-
-               config.addInMemoryOperationInterceptor(new AccessInterceptor(authMode));
-
-               return config;
-       }
-
-
 
        @Before
        public void setup() throws Exception {
-               authMode.restoreSnapshot();
-
-               usersConf = folder.newFile("users.conf");
-               FileUtils.copyFile(new File(RESOURCE_DIR + "users.conf"), usersConf);
-               settings = getSettings();
                ldap = newLdapAuthentication(settings);
                auth = newAuthenticationManager(settings);
        }
@@ -251,45 +79,6 @@ public class LdapAuthenticationTest extends GitblitUnitTest {
                return auth;
        }
 
-       private MemorySettings getSettings() {
-               Map<String, Object> backingMap = new HashMap<String, Object>();
-               backingMap.put(Keys.realm.userService, usersConf.getAbsolutePath());
-               switch(authMode) {
-               case ANONYMOUS:
-                       backingMap.put(Keys.realm.ldap.server, "ldap://localhost:" + authMode.ldapPort());
-                       backingMap.put(Keys.realm.ldap.username, "");
-                       backingMap.put(Keys.realm.ldap.password, "");
-                       break;
-               case DS_MANAGER:
-                       backingMap.put(Keys.realm.ldap.server, "ldap://localhost:" + authMode.ldapPort());
-                       backingMap.put(Keys.realm.ldap.username, DIRECTORY_MANAGER);
-                       backingMap.put(Keys.realm.ldap.password, "password");
-                       break;
-               case USR_MANAGER:
-                       backingMap.put(Keys.realm.ldap.server, "ldap://localhost:" + authMode.ldapPort());
-                       backingMap.put(Keys.realm.ldap.username, USER_MANAGER);
-                       backingMap.put(Keys.realm.ldap.password, "passwd");
-                       break;
-               default:
-                       throw new RuntimeException("Unimplemented AuthMode case!");
-
-               }
-               backingMap.put(Keys.realm.ldap.maintainTeams, "true");
-               backingMap.put(Keys.realm.ldap.accountBase, ACCOUNT_BASE);
-               backingMap.put(Keys.realm.ldap.accountPattern, "(&(objectClass=person)(sAMAccountName=${username}))");
-               backingMap.put(Keys.realm.ldap.groupBase, GROUP_BASE);
-               backingMap.put(Keys.realm.ldap.groupMemberPattern, "(&(objectClass=group)(member=${dn}))");
-               backingMap.put(Keys.realm.ldap.admins, "UserThree @Git_Admins \"@Git Admins\"");
-               backingMap.put(Keys.realm.ldap.displayName, "displayName");
-               backingMap.put(Keys.realm.ldap.email, "email");
-               backingMap.put(Keys.realm.ldap.uid, "sAMAccountName");
-
-               MemorySettings ms = new MemorySettings(backingMap);
-               return ms;
-       }
-
-
-
        @Test
        public void testAuthenticate() {
                UserModel userOneModel = ldap.authenticate("UserOne", "userOnePassword".toCharArray());
@@ -708,10 +497,12 @@ public class LdapAuthenticationTest extends GitblitUnitTest {
        }
 
 
-       private InMemoryDirectoryServer getDS()
-       {
-               return authMode.getDS();
-       }
+
+
+
+
+
+
 
        private int countLdapUsersInUserManager() {
                int ldapAccountCount = 0;
@@ -733,120 +524,4 @@ public class LdapAuthenticationTest extends GitblitUnitTest {
                return ldapAccountCount;
        }
 
-
-
-
-       /**
-        * Operation interceptor for the in memory DS. This interceptor
-        * implements access restrictions for certain user/DN combinations.
-        *
-        * The USER_MANAGER is only allowed to search for users, but not for groups.
-        * This is to test the original behaviour where the teams were searched under
-        * the user binding.
-        * When running in a DIRECTORY_MANAGER scenario, only the manager account
-        * is allowed to search for users and groups, while a normal user may not do so.
-        * This tests the scenario where a normal user cannot read teams and thus the
-        * manager account needs to be used for all searches.
-        *
-        */
-       private static class AccessInterceptor extends InMemoryOperationInterceptor {
-               AuthMode authMode;
-               Map<Long,String> lastSuccessfulBindDN = new HashMap<>();
-               Map<Long,Boolean> resultProhibited = new HashMap<>();
-
-               public AccessInterceptor(AuthMode authMode) {
-                       this.authMode = authMode;
-               }
-
-
-               @Override
-               public void processSimpleBindResult(InMemoryInterceptedSimpleBindResult bind) {
-                       BindResult result = bind.getResult();
-                       if (result.getResultCode() == ResultCode.SUCCESS) {
-                                BindRequest bindRequest = bind.getRequest();
-                                lastSuccessfulBindDN.put(bind.getConnectionID(), ((SimpleBindRequest)bindRequest).getBindDN());
-                                resultProhibited.remove(bind.getConnectionID());
-                       }
-               }
-
-
-
-               @Override
-               public void processSearchRequest(InMemoryInterceptedSearchRequest request) throws LDAPException {
-                       String bindDN = getLastBindDN(request);
-
-                       if (USER_MANAGER.equals(bindDN)) {
-                               if (request.getRequest().getBaseDN().endsWith(GROUP_BASE)) {
-                                       throw new LDAPException(ResultCode.NO_SUCH_OBJECT);
-                               }
-                       }
-                       else if(authMode == AuthMode.DS_MANAGER && !DIRECTORY_MANAGER.equals(bindDN)) {
-                               throw new LDAPException(ResultCode.NO_SUCH_OBJECT);
-                       }
-               }
-
-
-               @Override
-               public void processSearchEntry(InMemoryInterceptedSearchEntry entry) {
-                       String bindDN = getLastBindDN(entry);
-
-                       boolean prohibited = false;
-
-                       if (USER_MANAGER.equals(bindDN)) {
-                               if (entry.getSearchEntry().getDN().endsWith(GROUP_BASE)) {
-                                       prohibited = true;
-                               }
-                       }
-                       else if(authMode == AuthMode.DS_MANAGER && !DIRECTORY_MANAGER.equals(bindDN)) {
-                               prohibited = true;
-                       }
-
-                       if (prohibited) {
-                               // Found entry prohibited for bound user. Setting entry to null.
-                               entry.setSearchEntry(null);
-                               resultProhibited.put(entry.getConnectionID(), Boolean.TRUE);
-                       }
-               }
-
-               @Override
-               public void processSearchResult(InMemoryInterceptedSearchResult result) {
-                       String bindDN = getLastBindDN(result);
-
-                       boolean prohibited = false;
-
-                       Boolean rspb = resultProhibited.get(result.getConnectionID());
-                       if (USER_MANAGER.equals(bindDN)) {
-                               if (rspb != null && rspb) {
-                                       prohibited = true;
-                               }
-                       }
-                       else if(authMode == AuthMode.DS_MANAGER && !DIRECTORY_MANAGER.equals(bindDN)) {
-                               if (rspb != null && rspb) {
-                                       prohibited = true;
-                               }
-                       }
-
-                       if (prohibited) {
-                               // Result prohibited for bound user. Returning error
-                               result.setResult(new LDAPResult(result.getMessageID(), ResultCode.INSUFFICIENT_ACCESS_RIGHTS));
-                               resultProhibited.remove(result.getConnectionID());
-                       }
-               }
-
-               private String getLastBindDN(InMemoryInterceptedResult result) {
-                       String bindDN = lastSuccessfulBindDN.get(result.getConnectionID());
-                       if (bindDN == null) {
-                               return "UNKNOWN";
-                       }
-                       return bindDN;
-               }
-               private String getLastBindDN(InMemoryInterceptedRequest request) {
-                       String bindDN = lastSuccessfulBindDN.get(request.getConnectionID());
-                       if (bindDN == null) {
-                               return "UNKNOWN";
-                       }
-                       return bindDN;
-               }
-       }
-
 }
diff --git a/src/test/java/com/gitblit/tests/LdapBasedUnitTest.java b/src/test/java/com/gitblit/tests/LdapBasedUnitTest.java
new file mode 100644 (file)
index 0000000..cf3ab1f
--- /dev/null
@@ -0,0 +1,409 @@
+package com.gitblit.tests;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import com.gitblit.Keys;
+import com.gitblit.tests.mock.MemorySettings;
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerSnapshot;
+import com.unboundid.ldap.listener.InMemoryListenerConfig;
+import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedRequest;
+import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedResult;
+import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchEntry;
+import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchRequest;
+import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
+import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSimpleBindResult;
+import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
+import com.unboundid.ldap.sdk.BindRequest;
+import com.unboundid.ldap.sdk.BindResult;
+import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.LDAPResult;
+import com.unboundid.ldap.sdk.OperationType;
+import com.unboundid.ldap.sdk.ResultCode;
+import com.unboundid.ldap.sdk.SimpleBindRequest;
+
+
+
+/**
+ * Base class for Unit (/Integration) tests that test going against an
+ * in-memory UnboundID LDAP server.
+ *
+ * This base class creates separate in-memory LDAP servers for different scenarios:
+ * - ANONYMOUS: anonymous bind to LDAP.
+ * - DS_MANAGER: The DIRECTORY_MANAGER is set as DN to bind as an admin.
+ *               Normal users are prohibited to search the DS, they can only bind.
+ * - USR_MANAGER: The USER_MANAGER is set as DN to bind as an admin.
+ *                This account can only search users but not groups. Normal users can search groups.
+ *
+ * @author Florian Zschocke
+ *
+ */
+public abstract class LdapBasedUnitTest extends GitblitUnitTest {
+
+       protected static final String RESOURCE_DIR = "src/test/resources/ldap/";
+       private static final String DIRECTORY_MANAGER = "cn=Directory Manager";
+       private static final String USER_MANAGER = "cn=UserManager";
+       protected static final String ACCOUNT_BASE = "OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain";
+       private static final String GROUP_BASE = "OU=Groups,OU=UserControl,OU=MyOrganization,DC=MyDomain";
+       protected static final String DN_USER_ONE = "CN=UserOne,OU=US," + ACCOUNT_BASE;
+       protected static final String DN_USER_TWO = "CN=UserTwo,OU=US," + ACCOUNT_BASE;
+       protected static final String DN_USER_THREE = "CN=UserThree,OU=Canada," + ACCOUNT_BASE;
+
+
+       /**
+        * Enumeration of different test modes, representing different use scenarios.
+        * With ANONYMOUS anonymous binds are used to search LDAP.
+        * DS_MANAGER will use a DIRECTORY_MANAGER to search LDAP. Normal users are prohibited to search the DS.
+        * With USR_MANAGER, a USER_MANAGER account is used to search in LDAP. This account can only search users
+        * but not groups. Normal users can search groups, though.
+        *
+        */
+       protected enum AuthMode {
+               ANONYMOUS(1389),
+               DS_MANAGER(2389),
+               USR_MANAGER(3389);
+
+
+               private int ldapPort;
+               private InMemoryDirectoryServer ds;
+               private InMemoryDirectoryServerSnapshot dsSnapshot;
+               private BindTracker bindTracker;
+
+               AuthMode(int port) {
+                       this.ldapPort = port;
+               }
+
+               int ldapPort() {
+                       return this.ldapPort;
+               }
+
+               void setDS(InMemoryDirectoryServer ds) {
+                       if (this.ds == null) {
+                               this.ds = ds;
+                               this.dsSnapshot = ds.createSnapshot();
+                       };
+               }
+
+               InMemoryDirectoryServer getDS() {
+                       return ds;
+               }
+
+               void setBindTracker(BindTracker bindTracker) {
+                       this.bindTracker = bindTracker;
+               }
+
+               BindTracker getBindTracker() {
+                       return bindTracker;
+               }
+
+               void restoreSnapshot() {
+                       ds.restoreSnapshot(dsSnapshot);
+               }
+       }
+
+       @Parameter
+       public AuthMode authMode = AuthMode.ANONYMOUS;
+
+       @Rule
+       public TemporaryFolder folder = new TemporaryFolder();
+
+
+       protected File usersConf;
+
+       protected MemorySettings settings;
+
+
+       /**
+        * Run the tests with each authentication scenario once.
+        */
+       @Parameters(name = "{0}")
+       public static Collection<Object[]> data() {
+               return Arrays.asList(new Object[][] { {AuthMode.ANONYMOUS}, {AuthMode.DS_MANAGER}, {AuthMode.USR_MANAGER} });
+       }
+
+
+       /**
+        * Create three different in memory DS.
+        *
+        * Each DS has a different configuration:
+        * The first allows anonymous binds.
+        * The second requires authentication for all operations. It will only allow the DIRECTORY_MANAGER account
+        * to search for users and groups.
+        * The third one is like the second, but it allows users to search for users and groups, and restricts the
+        * USER_MANAGER from searching for groups.
+        */
+       @BeforeClass
+       public static void ldapInit() throws Exception {
+               InMemoryDirectoryServer ds;
+               InMemoryDirectoryServerConfig config = createInMemoryLdapServerConfig(AuthMode.ANONYMOUS);
+               config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", AuthMode.ANONYMOUS.ldapPort()));
+               ds = createInMemoryLdapServer(config);
+               AuthMode.ANONYMOUS.setDS(ds);
+
+
+               config = createInMemoryLdapServerConfig(AuthMode.DS_MANAGER);
+               config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", AuthMode.DS_MANAGER.ldapPort()));
+               config.setAuthenticationRequiredOperationTypes(EnumSet.allOf(OperationType.class));
+               ds = createInMemoryLdapServer(config);
+               AuthMode.DS_MANAGER.setDS(ds);
+
+
+               config = createInMemoryLdapServerConfig(AuthMode.USR_MANAGER);
+               config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", AuthMode.USR_MANAGER.ldapPort()));
+               config.setAuthenticationRequiredOperationTypes(EnumSet.allOf(OperationType.class));
+               ds = createInMemoryLdapServer(config);
+               AuthMode.USR_MANAGER.setDS(ds);
+
+       }
+
+       @AfterClass
+       public static void destroy() throws Exception {
+               for (AuthMode am : AuthMode.values()) {
+                       am.getDS().shutDown(true);
+               }
+       }
+
+       public static InMemoryDirectoryServer createInMemoryLdapServer(InMemoryDirectoryServerConfig config) throws Exception {
+               InMemoryDirectoryServer imds = new InMemoryDirectoryServer(config);
+               imds.importFromLDIF(true, RESOURCE_DIR + "sampledata.ldif");
+               imds.startListening();
+               return imds;
+       }
+
+       public static InMemoryDirectoryServerConfig createInMemoryLdapServerConfig(AuthMode authMode) throws Exception {
+               InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=MyDomain");
+               config.addAdditionalBindCredentials(DIRECTORY_MANAGER, "password");
+               config.addAdditionalBindCredentials(USER_MANAGER, "passwd");
+               config.setSchema(null);
+
+               authMode.setBindTracker(new BindTracker());
+               config.addInMemoryOperationInterceptor(authMode.getBindTracker());
+               config.addInMemoryOperationInterceptor(new AccessInterceptor(authMode));
+
+               return config;
+       }
+
+
+
+       @Before
+       public void setupBase() throws Exception {
+               authMode.restoreSnapshot();
+               authMode.getBindTracker().reset();
+
+               usersConf = folder.newFile("users.conf");
+               FileUtils.copyFile(new File(RESOURCE_DIR + "users.conf"), usersConf);
+               settings = getSettings();
+       }
+
+
+       protected InMemoryDirectoryServer getDS() {
+               return authMode.getDS();
+       }
+
+
+
+       protected MemorySettings getSettings() {
+               Map<String, Object> backingMap = new HashMap<String, Object>();
+               backingMap.put(Keys.realm.userService, usersConf.getAbsolutePath());
+               switch(authMode) {
+               case ANONYMOUS:
+                       backingMap.put(Keys.realm.ldap.server, "ldap://localhost:" + authMode.ldapPort());
+                       backingMap.put(Keys.realm.ldap.username, "");
+                       backingMap.put(Keys.realm.ldap.password, "");
+                       break;
+               case DS_MANAGER:
+                       backingMap.put(Keys.realm.ldap.server, "ldap://localhost:" + authMode.ldapPort());
+                       backingMap.put(Keys.realm.ldap.username, DIRECTORY_MANAGER);
+                       backingMap.put(Keys.realm.ldap.password, "password");
+                       break;
+               case USR_MANAGER:
+                       backingMap.put(Keys.realm.ldap.server, "ldap://localhost:" + authMode.ldapPort());
+                       backingMap.put(Keys.realm.ldap.username, USER_MANAGER);
+                       backingMap.put(Keys.realm.ldap.password, "passwd");
+                       break;
+               default:
+                       throw new RuntimeException("Unimplemented AuthMode case!");
+
+               }
+               backingMap.put(Keys.realm.ldap.maintainTeams, "true");
+               backingMap.put(Keys.realm.ldap.accountBase, ACCOUNT_BASE);
+               backingMap.put(Keys.realm.ldap.accountPattern, "(&(objectClass=person)(sAMAccountName=${username}))");
+               backingMap.put(Keys.realm.ldap.groupBase, GROUP_BASE);
+               backingMap.put(Keys.realm.ldap.groupMemberPattern, "(&(objectClass=group)(member=${dn}))");
+               backingMap.put(Keys.realm.ldap.admins, "UserThree @Git_Admins \"@Git Admins\"");
+               backingMap.put(Keys.realm.ldap.displayName, "displayName");
+               backingMap.put(Keys.realm.ldap.email, "email");
+               backingMap.put(Keys.realm.ldap.uid, "sAMAccountName");
+
+               MemorySettings ms = new MemorySettings(backingMap);
+               return ms;
+       }
+
+
+
+
+       /**
+        * Operation interceptor for the in memory DS. This interceptor
+        * tracks bind requests.
+        *
+        */
+       protected static class BindTracker extends InMemoryOperationInterceptor {
+               private Map<Integer,String> lastSuccessfulBindDNs = new HashMap<>();
+               private String lastSuccessfulBindDN;
+
+
+               @Override
+               public void processSimpleBindResult(InMemoryInterceptedSimpleBindResult bind) {
+                       BindResult result = bind.getResult();
+                       if (result.getResultCode() == ResultCode.SUCCESS) {
+                                BindRequest bindRequest = bind.getRequest();
+                                lastSuccessfulBindDNs.put(bind.getMessageID(), ((SimpleBindRequest)bindRequest).getBindDN());
+                                lastSuccessfulBindDN = ((SimpleBindRequest)bindRequest).getBindDN();
+                       }
+               }
+
+               String getLastSuccessfulBindDN() {
+                       return lastSuccessfulBindDN;
+               }
+
+               String getLastSuccessfulBindDN(int messageID) {
+                       return lastSuccessfulBindDNs.get(messageID);
+               }
+
+               void reset() {
+                       lastSuccessfulBindDNs = new HashMap<>();
+                       lastSuccessfulBindDN = null;
+               }
+       }
+
+
+
+       /**
+        * Operation interceptor for the in memory DS. This interceptor
+        * implements access restrictions for certain user/DN combinations.
+        *
+        * The USER_MANAGER is only allowed to search for users, but not for groups.
+        * This is to test the original behaviour where the teams were searched under
+        * the user binding.
+        * When running in a DIRECTORY_MANAGER scenario, only the manager account
+        * is allowed to search for users and groups, while a normal user may not do so.
+        * This tests the scenario where a normal user cannot read teams and thus the
+        * manager account needs to be used for all searches.
+        *
+        */
+       protected static class AccessInterceptor extends InMemoryOperationInterceptor {
+               AuthMode authMode;
+               Map<Long,String> lastSuccessfulBindDN = new HashMap<>();
+               Map<Long,Boolean> resultProhibited = new HashMap<>();
+
+               public AccessInterceptor(AuthMode authMode) {
+                       this.authMode = authMode;
+               }
+
+
+               @Override
+               public void processSimpleBindResult(InMemoryInterceptedSimpleBindResult bind) {
+                       BindResult result = bind.getResult();
+                       if (result.getResultCode() == ResultCode.SUCCESS) {
+                                BindRequest bindRequest = bind.getRequest();
+                                lastSuccessfulBindDN.put(bind.getConnectionID(), ((SimpleBindRequest)bindRequest).getBindDN());
+                                resultProhibited.remove(bind.getConnectionID());
+                       }
+               }
+
+
+
+               @Override
+               public void processSearchRequest(InMemoryInterceptedSearchRequest request) throws LDAPException {
+                       String bindDN = getLastBindDN(request);
+
+                       if (USER_MANAGER.equals(bindDN)) {
+                               if (request.getRequest().getBaseDN().endsWith(GROUP_BASE)) {
+                                       throw new LDAPException(ResultCode.NO_SUCH_OBJECT);
+                               }
+                       }
+                       else if(authMode == AuthMode.DS_MANAGER && !DIRECTORY_MANAGER.equals(bindDN)) {
+                               throw new LDAPException(ResultCode.NO_SUCH_OBJECT);
+                       }
+               }
+
+
+               @Override
+               public void processSearchEntry(InMemoryInterceptedSearchEntry entry) {
+                       String bindDN = getLastBindDN(entry);
+
+                       boolean prohibited = false;
+
+                       if (USER_MANAGER.equals(bindDN)) {
+                               if (entry.getSearchEntry().getDN().endsWith(GROUP_BASE)) {
+                                       prohibited = true;
+                               }
+                       }
+                       else if(authMode == AuthMode.DS_MANAGER && !DIRECTORY_MANAGER.equals(bindDN)) {
+                               prohibited = true;
+                       }
+
+                       if (prohibited) {
+                               // Found entry prohibited for bound user. Setting entry to null.
+                               entry.setSearchEntry(null);
+                               resultProhibited.put(entry.getConnectionID(), Boolean.TRUE);
+                       }
+               }
+
+               @Override
+               public void processSearchResult(InMemoryInterceptedSearchResult result) {
+                       String bindDN = getLastBindDN(result);
+
+                       boolean prohibited = false;
+
+                       Boolean rspb = resultProhibited.get(result.getConnectionID());
+                       if (USER_MANAGER.equals(bindDN)) {
+                               if (rspb != null && rspb) {
+                                       prohibited = true;
+                               }
+                       }
+                       else if(authMode == AuthMode.DS_MANAGER && !DIRECTORY_MANAGER.equals(bindDN)) {
+                               if (rspb != null && rspb) {
+                                       prohibited = true;
+                               }
+                       }
+
+                       if (prohibited) {
+                               // Result prohibited for bound user. Returning error
+                               result.setResult(new LDAPResult(result.getMessageID(), ResultCode.INSUFFICIENT_ACCESS_RIGHTS));
+                               resultProhibited.remove(result.getConnectionID());
+                       }
+               }
+
+               private String getLastBindDN(InMemoryInterceptedResult result) {
+                       String bindDN = lastSuccessfulBindDN.get(result.getConnectionID());
+                       if (bindDN == null) {
+                               return "UNKNOWN";
+                       }
+                       return bindDN;
+               }
+               private String getLastBindDN(InMemoryInterceptedRequest request) {
+                       String bindDN = lastSuccessfulBindDN.get(request.getConnectionID());
+                       if (bindDN == null) {
+                               return "UNKNOWN";
+                       }
+                       return bindDN;
+               }
+       }
+
+}