summaryrefslogtreecommitdiffstats
path: root/src/test/java
diff options
context:
space:
mode:
authorFlorian Zschocke <fzs@users.noreply.github.com>2016-12-18 17:01:15 +0100
committerGitHub <noreply@github.com>2016-12-18 17:01:15 +0100
commitd6ddafdb24ea55e59ac718b92f4b74e3b825ca63 (patch)
treee029423f37eb109a123f8d9fc267d6638fa1be59 /src/test/java
parent34b98a07b8f01015ddbafd4bdaad0458c25765ae (diff)
parent1afeccc09bfaa885b5c01d3db29d42695b8290a1 (diff)
downloadgitblit-d6ddafdb24ea55e59ac718b92f4b74e3b825ca63.tar.gz
gitblit-d6ddafdb24ea55e59ac718b92f4b74e3b825ca63.zip
Merge pull request #1160 from fzs/sshLdapAuthenticator
LDAP SSH key manager
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/com/gitblit/tests/LdapAuthenticationTest.java339
-rw-r--r--src/test/java/com/gitblit/tests/LdapBasedUnitTest.java410
-rw-r--r--src/test/java/com/gitblit/tests/LdapConnectionTest.java280
-rw-r--r--src/test/java/com/gitblit/tests/LdapPublicKeyManagerTest.java723
-rw-r--r--src/test/java/com/gitblit/tests/SshKeysDispatcherTest.java14
5 files changed, 1427 insertions, 339 deletions
diff --git a/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java b/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
index b7a77fc2..4f79edfb 100644
--- a/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
+++ b/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
@@ -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
index 00000000..7aec50e6
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/LdapBasedUnitTest.java
@@ -0,0 +1,410 @@
+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,
+ DS_MANAGER,
+ USR_MANAGER;
+
+
+ private int ldapPort;
+ private InMemoryDirectoryServer ds;
+ private InMemoryDirectoryServerSnapshot dsSnapshot;
+ private BindTracker bindTracker;
+
+ void setLdapPort(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("anonymous"));
+ ds = createInMemoryLdapServer(config);
+ AuthMode.ANONYMOUS.setDS(ds);
+ AuthMode.ANONYMOUS.setLdapPort(ds.getListenPort("anonymous"));
+
+
+ config = createInMemoryLdapServerConfig(AuthMode.DS_MANAGER);
+ config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("ds_manager"));
+ config.setAuthenticationRequiredOperationTypes(EnumSet.allOf(OperationType.class));
+ ds = createInMemoryLdapServer(config);
+ AuthMode.DS_MANAGER.setDS(ds);
+ AuthMode.DS_MANAGER.setLdapPort(ds.getListenPort("ds_manager"));
+
+
+ config = createInMemoryLdapServerConfig(AuthMode.USR_MANAGER);
+ config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("usr_manager"));
+ config.setAuthenticationRequiredOperationTypes(EnumSet.allOf(OperationType.class));
+ ds = createInMemoryLdapServer(config);
+ AuthMode.USR_MANAGER.setDS(ds);
+ AuthMode.USR_MANAGER.setLdapPort(ds.getListenPort("usr_manager"));
+
+ }
+
+ @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());
+ backingMap.put(Keys.realm.ldap.server, "ldap://localhost:" + authMode.ldapPort());
+ switch(authMode) {
+ case ANONYMOUS:
+ backingMap.put(Keys.realm.ldap.username, "");
+ backingMap.put(Keys.realm.ldap.password, "");
+ break;
+ case DS_MANAGER:
+ backingMap.put(Keys.realm.ldap.username, DIRECTORY_MANAGER);
+ backingMap.put(Keys.realm.ldap.password, "password");
+ break;
+ case USR_MANAGER:
+ 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;
+ }
+ }
+
+}
diff --git a/src/test/java/com/gitblit/tests/LdapConnectionTest.java b/src/test/java/com/gitblit/tests/LdapConnectionTest.java
new file mode 100644
index 00000000..3da54777
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/LdapConnectionTest.java
@@ -0,0 +1,280 @@
+package com.gitblit.tests;
+
+import static org.junit.Assume.assumeTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import com.gitblit.Keys;
+import com.gitblit.ldap.LdapConnection;
+import com.unboundid.ldap.sdk.BindResult;
+import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.ResultCode;
+import com.unboundid.ldap.sdk.SearchRequest;
+import com.unboundid.ldap.sdk.SearchResult;
+import com.unboundid.ldap.sdk.SearchResultEntry;
+import com.unboundid.ldap.sdk.SearchScope;
+
+/*
+ * Test for the LdapConnection
+ *
+ * @author Florian Zschocke
+ *
+ */
+@RunWith(Parameterized.class)
+public class LdapConnectionTest extends LdapBasedUnitTest {
+
+ @Test
+ public void testEscapeLDAPFilterString() {
+ // This test is independent from authentication mode, so run only once.
+ assumeTrue(authMode == AuthMode.ANONYMOUS);
+
+ // From: https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
+ assertEquals("No special characters to escape", "Hi This is a test #çà", LdapConnection.escapeLDAPSearchFilter("Hi This is a test #çà"));
+ assertEquals("LDAP Christams Tree", "Hi \\28This\\29 = is \\2a a \\5c test # ç à ô", LdapConnection.escapeLDAPSearchFilter("Hi (This) = is * a \\ test # ç à ô"));
+
+ assertEquals("Injection", "\\2a\\29\\28userPassword=secret", LdapConnection.escapeLDAPSearchFilter("*)(userPassword=secret"));
+ }
+
+
+ @Test
+ public void testConnect() {
+ // This test is independent from authentication mode, so run only once.
+ assumeTrue(authMode == AuthMode.ANONYMOUS);
+
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+ } finally {
+ conn.close();
+ }
+ }
+
+
+ @Test
+ public void testBindAnonymous() {
+ // This test tests for anonymous bind, so run only in authentication mode ANONYMOUS.
+ assumeTrue(authMode == AuthMode.ANONYMOUS);
+
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+
+ BindResult br = conn.bind();
+ assertNotNull(br);
+ assertEquals(ResultCode.SUCCESS, br.getResultCode());
+ assertEquals("", authMode.getBindTracker().getLastSuccessfulBindDN(br.getMessageID()));
+
+ } finally {
+ conn.close();
+ }
+ }
+
+
+ @Test
+ public void testBindAsAdmin() {
+ // This test tests for anonymous bind, so run only in authentication mode DS_MANAGER.
+ assumeTrue(authMode == AuthMode.DS_MANAGER);
+
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+
+ BindResult br = conn.bind();
+ assertNotNull(br);
+ assertEquals(ResultCode.SUCCESS, br.getResultCode());
+ assertEquals(settings.getString(Keys.realm.ldap.username, "UNSET"), authMode.getBindTracker().getLastSuccessfulBindDN(br.getMessageID()));
+
+ } finally {
+ conn.close();
+ }
+ }
+
+
+ @Test
+ public void testBindToBindpattern() {
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+
+ String bindPattern = "CN=${username},OU=Canada," + ACCOUNT_BASE;
+
+ BindResult br = conn.bind(bindPattern, "UserThree", "userThreePassword");
+ assertNotNull(br);
+ assertEquals(ResultCode.SUCCESS, br.getResultCode());
+ assertEquals("CN=UserThree,OU=Canada," + ACCOUNT_BASE, authMode.getBindTracker().getLastSuccessfulBindDN(br.getMessageID()));
+
+ br = conn.bind(bindPattern, "UserFour", "userThreePassword");
+ assertNull(br);
+
+ br = conn.bind(bindPattern, "UserTwo", "userTwoPassword");
+ assertNull(br);
+
+ } finally {
+ conn.close();
+ }
+ }
+
+
+ @Test
+ public void testRebindAsUser() {
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+
+ assertFalse(conn.rebindAsUser());
+
+ BindResult br = conn.bind();
+ assertNotNull(br);
+ assertFalse(conn.rebindAsUser());
+
+
+ String bindPattern = "CN=${username},OU=Canada," + ACCOUNT_BASE;
+ br = conn.bind(bindPattern, "UserThree", "userThreePassword");
+ assertNotNull(br);
+ assertFalse(conn.rebindAsUser());
+
+ br = conn.bind();
+ assertNotNull(br);
+ assertTrue(conn.rebindAsUser());
+ assertEquals(ResultCode.SUCCESS, br.getResultCode());
+ assertEquals("CN=UserThree,OU=Canada," + ACCOUNT_BASE, authMode.getBindTracker().getLastSuccessfulBindDN());
+
+ } finally {
+ conn.close();
+ }
+ }
+
+
+
+ @Test
+ public void testSearchRequest() throws LDAPException {
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+ BindResult br = conn.bind();
+ assertNotNull(br);
+
+ SearchRequest req;
+ SearchResult result;
+ SearchResultEntry entry;
+
+ req = new SearchRequest(ACCOUNT_BASE, SearchScope.BASE, "(CN=UserOne)");
+ result = conn.search(req);
+ assertNotNull(result);
+ assertEquals(0, result.getEntryCount());
+
+ req = new SearchRequest(ACCOUNT_BASE, SearchScope.ONE, "(CN=UserTwo)");
+ result = conn.search(req);
+ assertNotNull(result);
+ assertEquals(0, result.getEntryCount());
+
+ req = new SearchRequest(ACCOUNT_BASE, SearchScope.SUB, "(CN=UserThree)");
+ result = conn.search(req);
+ assertNotNull(result);
+ assertEquals(1, result.getEntryCount());
+ entry = result.getSearchEntries().get(0);
+ assertEquals("CN=UserThree,OU=Canada," + ACCOUNT_BASE, entry.getDN());
+
+ req = new SearchRequest(ACCOUNT_BASE, SearchScope.SUBORDINATE_SUBTREE, "(CN=UserFour)");
+ result = conn.search(req);
+ assertNotNull(result);
+ assertEquals(1, result.getEntryCount());
+ entry = result.getSearchEntries().get(0);
+ assertEquals("CN=UserFour,OU=Canada," + ACCOUNT_BASE, entry.getDN());
+
+ } finally {
+ conn.close();
+ }
+ }
+
+
+ @Test
+ public void testSearch() throws LDAPException {
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+ BindResult br = conn.bind();
+ assertNotNull(br);
+
+ SearchResult result;
+ SearchResultEntry entry;
+
+ result = conn.search(ACCOUNT_BASE, false, "(CN=UserOne)", null);
+ assertNotNull(result);
+ assertEquals(1, result.getEntryCount());
+ entry = result.getSearchEntries().get(0);
+ assertEquals("CN=UserOne,OU=US," + ACCOUNT_BASE, entry.getDN());
+
+ result = conn.search(ACCOUNT_BASE, true, "(&(CN=UserOne)(surname=One))", null);
+ assertNotNull(result);
+ assertEquals(1, result.getEntryCount());
+ entry = result.getSearchEntries().get(0);
+ assertEquals("CN=UserOne,OU=US," + ACCOUNT_BASE, entry.getDN());
+
+ result = conn.search(ACCOUNT_BASE, true, "(&(CN=UserOne)(surname=Two))", null);
+ assertNotNull(result);
+ assertEquals(0, result.getEntryCount());
+
+ result = conn.search(ACCOUNT_BASE, true, "(surname=Two)", Arrays.asList("givenName", "surname"));
+ assertNotNull(result);
+ assertEquals(1, result.getEntryCount());
+ entry = result.getSearchEntries().get(0);
+ assertEquals("CN=UserTwo,OU=US," + ACCOUNT_BASE, entry.getDN());
+ assertEquals(2, entry.getAttributes().size());
+ assertEquals("User", entry.getAttributeValue("givenName"));
+ assertEquals("Two", entry.getAttributeValue("surname"));
+
+ result = conn.search(ACCOUNT_BASE, true, "(personalTitle=Mr*)", null);
+ assertNotNull(result);
+ assertEquals(3, result.getEntryCount());
+ ArrayList<String> names = new ArrayList<>(3);
+ names.add(result.getSearchEntries().get(0).getAttributeValue("surname"));
+ names.add(result.getSearchEntries().get(1).getAttributeValue("surname"));
+ names.add(result.getSearchEntries().get(2).getAttributeValue("surname"));
+ assertTrue(names.contains("One"));
+ assertTrue(names.contains("Two"));
+ assertTrue(names.contains("Three"));
+
+ } finally {
+ conn.close();
+ }
+ }
+
+
+ @Test
+ public void testSearchUser() throws LDAPException {
+ LdapConnection conn = new LdapConnection(settings);
+ try {
+ assertTrue(conn.connect());
+ BindResult br = conn.bind();
+ assertNotNull(br);
+
+ SearchResult result;
+ SearchResultEntry entry;
+
+ result = conn.searchUser("UserOne");
+ assertNotNull(result);
+ assertEquals(1, result.getEntryCount());
+ entry = result.getSearchEntries().get(0);
+ assertEquals("CN=UserOne,OU=US," + ACCOUNT_BASE, entry.getDN());
+
+ result = conn.searchUser("UserFour", Arrays.asList("givenName", "surname"));
+ assertNotNull(result);
+ assertEquals(1, result.getEntryCount());
+ entry = result.getSearchEntries().get(0);
+ assertEquals("CN=UserFour,OU=Canada," + ACCOUNT_BASE, entry.getDN());
+ assertEquals(2, entry.getAttributes().size());
+ assertEquals("User", entry.getAttributeValue("givenName"));
+ assertEquals("Four", entry.getAttributeValue("surname"));
+
+ } finally {
+ conn.close();
+ }
+ }
+
+}
diff --git a/src/test/java/com/gitblit/tests/LdapPublicKeyManagerTest.java b/src/test/java/com/gitblit/tests/LdapPublicKeyManagerTest.java
new file mode 100644
index 00000000..c426254f
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/LdapPublicKeyManagerTest.java
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2016 Florian Zschocke
+ * Copyright 2016 gitblit.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.tests;
+
+import static org.junit.Assume.assumeTrue;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.spec.ECGenParameterSpec;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sshd.common.util.SecurityUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import com.gitblit.Keys;
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.transport.ssh.LdapKeyManager;
+import com.gitblit.transport.ssh.SshKey;
+import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.Modification;
+import com.unboundid.ldap.sdk.ModificationType;
+
+/**
+ * Test LdapPublicKeyManager going against an in-memory UnboundID
+ * LDAP server.
+ *
+ * @author Florian Zschocke
+ *
+ */
+@RunWith(Parameterized.class)
+public class LdapPublicKeyManagerTest extends LdapBasedUnitTest {
+
+ private static Map<String,KeyPair> keyPairs = new HashMap<>(10);
+ private static KeyPairGenerator rsaGenerator;
+ private static KeyPairGenerator dsaGenerator;
+ private static KeyPairGenerator ecGenerator;
+
+
+
+ @BeforeClass
+ public static void init() throws GeneralSecurityException {
+ rsaGenerator = SecurityUtils.getKeyPairGenerator("RSA");
+ dsaGenerator = SecurityUtils.getKeyPairGenerator("DSA");
+ ecGenerator = SecurityUtils.getKeyPairGenerator("ECDSA");
+ }
+
+
+
+ @Test
+ public void testGetKeys() throws LDAPException {
+ String keyRsaOne = getRsaPubKey("UserOne@example.com");
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", keyRsaOne));
+
+ String keyRsaTwo = getRsaPubKey("UserTwo@example.com");
+ String keyDsaTwo = getDsaPubKey("UserTwo@example.com");
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", keyRsaTwo, keyDsaTwo));
+
+ String keyRsaThree = getRsaPubKey("UserThree@example.com");
+ String keyDsaThree = getDsaPubKey("UserThree@example.com");
+ String keyEcThree = getEcPubKey("UserThree@example.com");
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", keyEcThree, keyRsaThree, keyDsaThree));
+
+ LdapKeyManager kmgr = new LdapKeyManager(settings);
+
+ List<SshKey> keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertTrue(keys.size() == 1);
+ assertEquals(keyRsaOne, keys.get(0).getRawData());
+
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertTrue(keys.size() == 2);
+ if (keyRsaTwo.equals(keys.get(0).getRawData())) {
+ assertEquals(keyDsaTwo, keys.get(1).getRawData());
+ } else if (keyDsaTwo.equals(keys.get(0).getRawData())) {
+ assertEquals(keyRsaTwo, keys.get(1).getRawData());
+ } else {
+ fail("Mismatch in UserTwo keys.");
+ }
+
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertTrue(keys.size() == 3);
+ assertEquals(keyEcThree, keys.get(0).getRawData());
+ assertEquals(keyRsaThree, keys.get(1).getRawData());
+ assertEquals(keyDsaThree, keys.get(2).getRawData());
+
+ keys = kmgr.getKeys("UserFour");
+ assertNotNull(keys);
+ assertTrue(keys.size() == 0);
+ }
+
+
+ @Test
+ public void testGetKeysAttributeName() throws LDAPException {
+ settings.put(Keys.realm.ldap.sshPublicKey, "sshPublicKey");
+
+ String keyRsaOne = getRsaPubKey("UserOne@example.com");
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", keyRsaOne));
+
+ String keyDsaTwo = getDsaPubKey("UserTwo@example.com");
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "publicsshkey", keyDsaTwo));
+
+ String keyRsaThree = getRsaPubKey("UserThree@example.com");
+ String keyDsaThree = getDsaPubKey("UserThree@example.com");
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", keyRsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "publicsshkey", keyDsaThree));
+
+
+ LdapKeyManager kmgr = new LdapKeyManager(settings);
+
+ List<SshKey> keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ assertEquals(keyRsaOne, keys.get(0).getRawData());
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ assertEquals(keyRsaThree, keys.get(0).getRawData());
+
+ keys = kmgr.getKeys("UserFour");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+
+ settings.put(Keys.realm.ldap.sshPublicKey, "publicsshkey");
+
+ keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ assertEquals(keyDsaTwo, keys.get(0).getRawData());
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ assertEquals(keyDsaThree, keys.get(0).getRawData());
+
+ keys = kmgr.getKeys("UserFour");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+ }
+
+
+ @Test
+ public void testGetKeysPrefixed() throws LDAPException {
+ // This test is independent from authentication mode, so run only once.
+ assumeTrue(authMode == AuthMode.ANONYMOUS);
+
+ String keyRsaOne = getRsaPubKey("UserOne@example.com");
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", keyRsaOne));
+
+ String keyRsaTwo = getRsaPubKey("UserTwo@example.com");
+ String keyDsaTwo = getDsaPubKey("UserTwo@example.com");
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", keyRsaTwo));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHKey: " + keyDsaTwo));
+
+ String keyRsaThree = getRsaPubKey("UserThree@example.com");
+ String keyDsaThree = getDsaPubKey("UserThree@example.com");
+ String keyEcThree = getEcPubKey("UserThree@example.com");
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", " SshKey :\r\n" + keyRsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", " sshkey: " + keyDsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "ECDSAKey :\n " + keyEcThree));
+
+
+ LdapKeyManager kmgr = new LdapKeyManager(settings);
+
+ settings.put(Keys.realm.ldap.sshPublicKey, "altSecurityIdentities");
+
+ List<SshKey> keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ assertEquals(keyRsaTwo, keys.get(0).getRawData());
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+ keys = kmgr.getKeys("UserFour");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+
+
+ settings.put(Keys.realm.ldap.sshPublicKey, "altSecurityIdentities:SSHKey");
+
+ keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ assertEquals(keyDsaTwo, keys.get(0).getRawData());
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(2, keys.size());
+ assertEquals(keyRsaThree, keys.get(0).getRawData());
+ assertEquals(keyDsaThree, keys.get(1).getRawData());
+
+ keys = kmgr.getKeys("UserFour");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+
+
+ settings.put(Keys.realm.ldap.sshPublicKey, "altSecurityIdentities:ECDSAKey");
+
+ keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ assertEquals(keyEcThree, keys.get(0).getRawData());
+
+ keys = kmgr.getKeys("UserFour");
+ assertNotNull(keys);
+ assertEquals(0, keys.size());
+ }
+
+
+ @Test
+ public void testGetKeysPermissions() throws LDAPException {
+ // This test is independent from authentication mode, so run only once.
+ assumeTrue(authMode == AuthMode.ANONYMOUS);
+
+ String keyRsaOne = getRsaPubKey("UserOne@example.com");
+ String keyRsaTwo = getRsaPubKey("");
+ String keyDsaTwo = getDsaPubKey("UserTwo at example.com");
+ String keyRsaThree = getRsaPubKey("UserThree@example.com");
+ String keyDsaThree = getDsaPubKey("READ key for user 'Three' @example.com");
+ String keyEcThree = getEcPubKey("UserThree@example.com");
+
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", keyRsaOne));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", " " + keyRsaTwo));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", "no-agent-forwarding " + keyDsaTwo));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", " command=\"sh /etc/netstart tun0 \" " + keyRsaThree));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", " command=\"netstat -nult\",environment=\"gb=\\\"What now\\\"\" " + keyDsaThree));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "sshPublicKey", "environment=\"SSH=git\",command=\"netstat -nult\",environment=\"gbPerms=VIEW\" " + keyEcThree));
+
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", "environment=\"gbPerm=R\" " + keyRsaOne));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", " restrict,environment=\"gbperm=V\" " + keyRsaTwo));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", "restrict,environment=\"GBPerm=RW\",pty " + keyDsaTwo));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", " environment=\"gbPerm=CLONE\",environment=\"X=\\\" Y \\\"\" " + keyRsaThree));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", " environment=\"A = B \",from=\"*.example.com,!pc.example.com\",environment=\"gbPerm=VIEW\" " + keyDsaThree));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", "environment=\"SSH=git\",environment=\"gbPerm=PUSH\",environment=\"XYZ='Ali Baba'\" " + keyEcThree));
+
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", "environment=\"gbPerm=R\",environment=\"josh=\\\"mean\\\"\",tunnel=\"0\" " + keyRsaOne));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", " environment=\" gbPerm = V \" " + keyRsaTwo));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", "command=\"sh echo \\\"Nope, not you!\\\" \",user-rc,environment=\"gbPerm=RW\" " + keyDsaTwo));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", "environment=\"gbPerm=VIEW\",command=\"sh /etc/netstart tun0 \",environment=\"gbPerm=CLONE\",no-pty " + keyRsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", " command=\"netstat -nult\",environment=\"gbPerm=VIEW\" " + keyDsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "sshPublicKey", "environment=\"SSH=git\",command=\"netstat -nult\",environment=\"gbPerm=PUSH\" " + keyEcThree));
+
+
+ LdapKeyManager kmgr = new LdapKeyManager(settings);
+
+ List<SshKey> keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(6, keys.size());
+ for (SshKey key : keys) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ }
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(6, keys.size());
+ int seen = 0;
+ for (SshKey key : keys) {
+ if (keyRsaOne.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(63, seen);
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(6, keys.size());
+ seen = 0;
+ for (SshKey key : keys) {
+ if (keyRsaOne.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(63, seen);
+ }
+
+
+ @Test
+ public void testGetKeysPrefixedPermissions() throws LDAPException {
+ // This test is independent from authentication mode, so run only once.
+ assumeTrue(authMode == AuthMode.ANONYMOUS);
+
+ String keyRsaOne = getRsaPubKey("UserOne@example.com");
+ String keyRsaTwo = getRsaPubKey("UserTwo at example.com");
+ String keyDsaTwo = getDsaPubKey("UserTwo@example.com");
+ String keyRsaThree = getRsaPubKey("example.com: user Three");
+ String keyDsaThree = getDsaPubKey("");
+ String keyEcThree = getEcPubKey(" ");
+
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "altSecurityIdentities", "permitopen=\"host:220\"" + keyRsaOne));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "altSecurityIdentities", "sshkey:" + " " + keyRsaTwo));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHKEY :" + "no-agent-forwarding " + keyDsaTwo));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + " command=\"sh /etc/netstart tun0 \" " + keyRsaThree));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + " command=\"netstat -nult\",environment=\"gb=\\\"What now\\\"\" " + keyDsaThree));
+ getDS().modify(DN_USER_ONE, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + "environment=\"SSH=git\",command=\"netstat -nult\",environment=\"gbPerms=VIEW\" " + keyEcThree));
+
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHkey: " + "environment=\"gbPerm=R\" " + keyRsaOne));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHKey : " + " restrict,environment=\"gbPerm=V\",permitopen=\"sshkey: 220\" " + keyRsaTwo));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHkey: " + "permitopen=\"sshkey: 443\",restrict,environment=\"gbPerm=RW\",pty " + keyDsaTwo));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + "environment=\"gbPerm=CLONE\",permitopen=\"pubkey: 29184\",environment=\"X=\\\" Y \\\"\" " + keyRsaThree));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + " environment=\"A = B \",from=\"*.example.com,!pc.example.com\",environment=\"gbPerm=VIEW\" " + keyDsaThree));
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + "environment=\"SSH=git\",environment=\"gbPerm=PUSH\",environemnt=\"XYZ='Ali Baba'\" " + keyEcThree));
+
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHkey: " + "environment=\"gbPerm=R\",environment=\"josh=\\\"mean\\\"\",tunnel=\"0\" " + keyRsaOne));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHkey : " + " environment=\" gbPerm = V \" " + keyRsaTwo));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "SSHkey: " + "command=\"sh echo \\\"Nope, not you! \\b (bell)\\\" \",user-rc,environment=\"gbPerm=RW\" " + keyDsaTwo));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + "environment=\"gbPerm=VIEW\",command=\"sh /etc/netstart tun0 \",environment=\"gbPerm=CLONE\",no-pty " + keyRsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + " command=\"netstat -nult\",environment=\"gbPerm=VIEW\" " + keyDsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "pubkey: " + "environment=\"SSH=git\",command=\"netstat -nult\",environment=\"gbPerm=PUSH\" " + keyEcThree));
+
+ // Weird stuff, not to specification but shouldn't make it stumble.
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", "opttest: " + "permitopen=host:443,command=,environment=\"gbPerm=CLONE\",no-pty= " + keyRsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", " opttest: " + " cmd=git,environment=\"gbPerm=\\\"VIEW\\\"\" " + keyDsaThree));
+ getDS().modify(DN_USER_THREE, new Modification(ModificationType.ADD, "altSecurityIdentities", " opttest:" + "environment=,command=netstat,environment=gbperm=push " + keyEcThree));
+
+
+ LdapKeyManager kmgr = new LdapKeyManager(settings);
+
+ settings.put(Keys.realm.ldap.sshPublicKey, "altSecurityIdentities:SSHkey");
+
+ List<SshKey> keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(2, keys.size());
+ int seen = 0;
+ for (SshKey key : keys) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ if (keyRsaOne.equals(key.getRawData())) {
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(6, seen);
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(3, keys.size());
+ seen = 0;
+ for (SshKey key : keys) {
+ if (keyRsaOne.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(7, seen);
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(3, keys.size());
+ seen = 0;
+ for (SshKey key : keys) {
+ if (keyRsaOne.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(7, seen);
+
+
+
+ settings.put(Keys.realm.ldap.sshPublicKey, "altSecurityIdentities:pubKey");
+
+ keys = kmgr.getKeys("UserOne");
+ assertNotNull(keys);
+ assertEquals(3, keys.size());
+ seen = 0;
+ for (SshKey key : keys) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ if (keyRsaOne.equals(key.getRawData())) {
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(56, seen);
+
+ keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(3, keys.size());
+ seen = 0;
+ for (SshKey key : keys) {
+ if (keyRsaOne.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(56, seen);
+
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(3, keys.size());
+ seen = 0;
+ for (SshKey key : keys) {
+ if (keyRsaOne.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(56, seen);
+
+
+ settings.put(Keys.realm.ldap.sshPublicKey, "altSecurityIdentities:opttest");
+ keys = kmgr.getKeys("UserThree");
+ assertNotNull(keys);
+ assertEquals(3, keys.size());
+ seen = 0;
+ for (SshKey key : keys) {
+ if (keyRsaOne.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 0;
+ }
+ else if (keyRsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 1;
+ }
+ else if (keyDsaTwo.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 2;
+ }
+ else if (keyRsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.CLONE, key.getPermission());
+ seen += 1 << 3;
+ }
+ else if (keyDsaThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.VIEW, key.getPermission());
+ seen += 1 << 4;
+ }
+ else if (keyEcThree.equals(key.getRawData())) {
+ assertEquals(AccessPermission.PUSH, key.getPermission());
+ seen += 1 << 5;
+ }
+ }
+ assertEquals(56, seen);
+
+ }
+
+
+ @Test
+ public void testKeyValidity() throws LDAPException, GeneralSecurityException {
+ LdapKeyManager kmgr = new LdapKeyManager(settings);
+
+ String comment = "UserTwo@example.com";
+ String keyDsaTwo = getDsaPubKey(comment);
+ getDS().modify(DN_USER_TWO, new Modification(ModificationType.ADD, "sshPublicKey", keyDsaTwo));
+
+
+ List<SshKey> keys = kmgr.getKeys("UserTwo");
+ assertNotNull(keys);
+ assertEquals(1, keys.size());
+ SshKey sshKey = keys.get(0);
+ assertEquals(keyDsaTwo, sshKey.getRawData());
+
+ Signature signature = SecurityUtils.getSignature("DSA");
+ signature.initSign(getDsaKeyPair(comment).getPrivate());
+ byte[] message = comment.getBytes();
+ signature.update(message);
+ byte[] sigBytes = signature.sign();
+
+ signature.initVerify(sshKey.getPublicKey());
+ signature.update(message);
+ assertTrue("Verify failed with retrieved SSH key.", signature.verify(sigBytes));
+ }
+
+
+
+
+
+
+
+
+ private KeyPair getDsaKeyPair(String comment) {
+ return getKeyPair("DSA", comment, dsaGenerator);
+ }
+
+ private KeyPair getKeyPair(String type, String comment, KeyPairGenerator generator) {
+ String kpkey = type + ":" + comment;
+ KeyPair kp = keyPairs.get(kpkey);
+ if (kp == null) {
+ if ("EC".equals(type)) {
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("P-384");
+ try {
+ ecGenerator.initialize(ecSpec);
+ } catch (InvalidAlgorithmParameterException e) {
+ kp = generator.generateKeyPair();
+ e.printStackTrace();
+ }
+ kp = ecGenerator.generateKeyPair();
+ } else {
+ kp = generator.generateKeyPair();
+ }
+ keyPairs.put(kpkey, kp);
+ }
+
+ return kp;
+ }
+
+
+ private String getRsaPubKey(String comment) {
+ return getPubKey("RSA", comment, rsaGenerator);
+ }
+
+ private String getDsaPubKey(String comment) {
+ return getPubKey("DSA", comment, dsaGenerator);
+ }
+
+ private String getEcPubKey(String comment) {
+ return getPubKey("EC", comment, ecGenerator);
+ }
+
+ private String getPubKey(String type, String comment, KeyPairGenerator generator) {
+ KeyPair kp = getKeyPair(type, comment, generator);
+ if (kp == null) {
+ return null;
+ }
+
+ SshKey sk = new SshKey(kp.getPublic());
+ sk.setComment(comment);
+ return sk.getRawData();
+ }
+
+}
diff --git a/src/test/java/com/gitblit/tests/SshKeysDispatcherTest.java b/src/test/java/com/gitblit/tests/SshKeysDispatcherTest.java
index 23e61795..4784e468 100644
--- a/src/test/java/com/gitblit/tests/SshKeysDispatcherTest.java
+++ b/src/test/java/com/gitblit/tests/SshKeysDispatcherTest.java
@@ -37,7 +37,7 @@ public class SshKeysDispatcherTest extends SshUnitTest {
String result = testSshCommand("keys ls -L");
List<SshKey> keys = getKeyManager().getKeys(username);
assertEquals(String.format("There are %d keys!", keys.size()), 2, keys.size());
- assertEquals(keys.get(0).getRawData() + "\n" + keys.get(1).getRawData(), result);
+ assertEquals(String.format("%s%n%s", keys.get(0).getRawData(), keys.get(1).getRawData()), result);
}
@Test
@@ -64,9 +64,9 @@ public class SshKeysDispatcherTest extends SshUnitTest {
assertEquals(String.format("There are %d keys!", keys.size()), 0, keys.size());
try {
testSshCommand("keys ls -L");
- assertTrue("Authentication worked without a public key?!", false);
+ fail("Authentication worked without a public key?!");
} catch (AssertionError e) {
- assertTrue(true);
+ // expected
}
}
@@ -77,9 +77,9 @@ public class SshKeysDispatcherTest extends SshUnitTest {
assertEquals(String.format("There are %d keys!", keys.size()), 0, keys.size());
try {
testSshCommand("keys ls -L");
- assertTrue("Authentication worked without a public key?!", false);
+ fail("Authentication worked without a public key?!");
} catch (AssertionError e) {
- assertTrue(true);
+ // expected
}
}
@@ -96,9 +96,9 @@ public class SshKeysDispatcherTest extends SshUnitTest {
StringBuilder sb = new StringBuilder();
for (SshKey sk : keys) {
sb.append(sk.getRawData());
- sb.append('\n');
+ sb.append(System.getProperty("line.separator", "\n"));
}
- sb.setLength(sb.length() - 1);
+ sb.setLength(sb.length() - System.getProperty("line.separator", "\n").length());
assertEquals(sb.toString(), result);
}