diff options
author | Florian Zschocke <fzs@users.noreply.github.com> | 2016-12-18 17:01:15 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-18 17:01:15 +0100 |
commit | d6ddafdb24ea55e59ac718b92f4b74e3b825ca63 (patch) | |
tree | e029423f37eb109a123f8d9fc267d6638fa1be59 /src/test/java | |
parent | 34b98a07b8f01015ddbafd4bdaad0458c25765ae (diff) | |
parent | 1afeccc09bfaa885b5c01d3db29d42695b8290a1 (diff) | |
download | gitblit-d6ddafdb24ea55e59ac718b92f4b74e3b825ca63.tar.gz gitblit-d6ddafdb24ea55e59ac718b92f4b74e3b825ca63.zip |
Merge pull request #1160 from fzs/sshLdapAuthenticator
LDAP SSH key manager
Diffstat (limited to 'src/test/java')
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); } |