summaryrefslogtreecommitdiffstats
path: root/src/test/java/com
diff options
context:
space:
mode:
authorFlorian Zschocke <florian.zschocke@cycos.com>2013-07-09 13:07:13 +0200
committerJames Moger <james.moger@gitblit.com>2013-08-12 16:32:12 -0400
commita0c34e37fe8e456a21c7a57e9d45e637ab40cce8 (patch)
treea85998534a5075716263d7d3c4529e5b3b9a11b5 /src/test/java/com
parent13208e8c3b34c321b470aa181b705f78fcc09c5f (diff)
downloadgitblit-a0c34e37fe8e456a21c7a57e9d45e637ab40cce8.tar.gz
gitblit-a0c34e37fe8e456a21c7a57e9d45e637ab40cce8.zip
Add an Apache htpasswd user service
Add a new class, HtpasswdUserService, which performs authentication against a text file created with the Apache 'htpasswd' program. Added dependency on commons-codec:1.7
Diffstat (limited to 'src/test/java/com')
-rw-r--r--src/test/java/com/gitblit/tests/GitBlitSuite.java2
-rw-r--r--src/test/java/com/gitblit/tests/HtpasswdUserServiceTest.java556
2 files changed, 557 insertions, 1 deletions
diff --git a/src/test/java/com/gitblit/tests/GitBlitSuite.java b/src/test/java/com/gitblit/tests/GitBlitSuite.java
index 6fff241c..64398b22 100644
--- a/src/test/java/com/gitblit/tests/GitBlitSuite.java
+++ b/src/test/java/com/gitblit/tests/GitBlitSuite.java
@@ -60,7 +60,7 @@ import com.gitblit.utils.JGitUtils;
DiffUtilsTest.class, MetricUtilsTest.class, TicgitUtilsTest.class, X509UtilsTest.class,
GitBlitTest.class, FederationTests.class, RpcTests.class, GitServletTest.class, GitDaemonTest.class,
GroovyScriptTest.class, LuceneExecutorTest.class, IssuesTest.class, RepositoryModelTest.class,
- FanoutServiceTest.class, Issue0259Test.class, Issue0271Test.class })
+ FanoutServiceTest.class, Issue0259Test.class, Issue0271Test.class, HtpasswdUserServiceTest.class })
public class GitBlitSuite {
public static final File REPOSITORIES = new File("data/git");
diff --git a/src/test/java/com/gitblit/tests/HtpasswdUserServiceTest.java b/src/test/java/com/gitblit/tests/HtpasswdUserServiceTest.java
new file mode 100644
index 00000000..ef9d35ff
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/HtpasswdUserServiceTest.java
@@ -0,0 +1,556 @@
+package com.gitblit.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.HashMap;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.gitblit.HtpasswdUserService;
+import com.gitblit.models.UserModel;
+import com.gitblit.tests.mock.MemorySettings;
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Test the Htpasswd user service.
+ *
+ */
+public class HtpasswdUserServiceTest {
+
+ private static final String RESOURCE_DIR = "src/test/resources/htpasswdUSTest/";
+ private static final String KEY_SUPPORT_PLAINTEXT_PWD = "realm.htpasswd.supportPlaintextPasswords";
+
+ private static final int NUM_USERS_HTPASSWD = 10;
+
+ private static final MemorySettings MS = new MemorySettings(new HashMap<String, Object>());
+
+ private HtpasswdUserService htpwdUserService;
+
+
+ private MemorySettings getSettings( String userfile, String groupfile, Boolean overrideLA)
+ {
+ MS.put("realm.htpasswd.backingUserService", RESOURCE_DIR + "users.conf");
+ MS.put("realm.htpasswd.userfile", (userfile == null) ? (RESOURCE_DIR+"htpasswd") : userfile);
+ MS.put("realm.htpasswd.groupfile", (groupfile == null) ? (RESOURCE_DIR+"htgroup") : groupfile);
+ MS.put("realm.htpasswd.overrideLocalAuthentication", (overrideLA == null) ? "false" : overrideLA.toString());
+ // Default to keep test the same on all platforms.
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
+
+ return MS;
+ }
+
+ private MemorySettings getSettings()
+ {
+ return getSettings(null, null, null);
+ }
+
+ private MemorySettings getSettings(boolean overrideLA)
+ {
+ return getSettings(null, null, new Boolean(overrideLA));
+ }
+
+
+ private void setupUS()
+ {
+ htpwdUserService = new HtpasswdUserService();
+ htpwdUserService.setup(getSettings());
+ }
+
+ private void setupUS(boolean overrideLA)
+ {
+ htpwdUserService = new HtpasswdUserService();
+ htpwdUserService.setup(getSettings(overrideLA));
+ }
+
+
+ private void copyInFiles() throws IOException
+ {
+ File dir = new File(RESOURCE_DIR);
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String file) {
+ return file.endsWith(".in");
+ }
+ };
+ for (File inf : dir.listFiles(filter)) {
+ File dest = new File(inf.getParent(), inf.getName().substring(0, inf.getName().length()-3));
+ FileUtils.copyFile(inf, dest);
+ }
+ }
+
+
+ private void deleteGeneratedFiles()
+ {
+ File dir = new File(RESOURCE_DIR);
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String file) {
+ return !(file.endsWith(".in"));
+ }
+ };
+ for (File file : dir.listFiles(filter)) {
+ file.delete();
+ }
+ }
+
+
+ @Before
+ public void setup() throws IOException
+ {
+ copyInFiles();
+ setupUS();
+ }
+
+
+ @After
+ public void tearDown()
+ {
+ deleteGeneratedFiles();
+ }
+
+
+
+ @Test
+ public void testSetup() throws IOException
+ {
+ assertEquals(NUM_USERS_HTPASSWD, htpwdUserService.getNumberHtpasswdUsers());
+ }
+
+
+ @Test
+ public void testAuthenticate()
+ {
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
+ UserModel user = htpwdUserService.authenticate("user1", "pass1".toCharArray());
+ assertNotNull(user);
+ assertEquals("user1", user.username);
+
+ user = htpwdUserService.authenticate("user2", "pass2".toCharArray());
+ assertNotNull(user);
+ assertEquals("user2", user.username);
+
+ // Test different encryptions
+ user = htpwdUserService.authenticate("plain", "passWord".toCharArray());
+ assertNotNull(user);
+ assertEquals("plain", user.username);
+
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
+ user = htpwdUserService.authenticate("crypt", "password".toCharArray());
+ assertNotNull(user);
+ assertEquals("crypt", user.username);
+
+ user = htpwdUserService.authenticate("md5", "password".toCharArray());
+ assertNotNull(user);
+ assertEquals("md5", user.username);
+
+ user = htpwdUserService.authenticate("sha", "password".toCharArray());
+ assertNotNull(user);
+ assertEquals("sha", user.username);
+
+
+ // Test leading and trailing whitespace
+ user = htpwdUserService.authenticate("trailing", "whitespace".toCharArray());
+ assertNotNull(user);
+ assertEquals("trailing", user.username);
+
+ user = htpwdUserService.authenticate("tabbed", "frontAndBack".toCharArray());
+ assertNotNull(user);
+ assertEquals("tabbed", user.username);
+
+ user = htpwdUserService.authenticate("leading", "whitespace".toCharArray());
+ assertNotNull(user);
+ assertEquals("leading", user.username);
+
+
+ // Test local account
+ user = htpwdUserService.authenticate("admin", "admin".toCharArray());
+ assertNotNull(user);
+ assertEquals("admin", user.username);
+ }
+
+
+ @Test
+ public void testAttributes()
+ {
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
+ UserModel user = htpwdUserService.authenticate("user1", "pass1".toCharArray());
+ assertNotNull(user);
+ assertEquals("El Capitan", user.displayName);
+ assertEquals("cheffe@example.com", user.emailAddress);
+ assertTrue(user.canAdmin);
+
+ user = htpwdUserService.authenticate("user2", "pass2".toCharArray());
+ assertNotNull(user);
+ assertEquals("User Two", user.displayName);
+ assertTrue(user.canCreate);
+ assertTrue(user.canFork);
+
+
+ user = htpwdUserService.authenticate("admin", "admin".toCharArray());
+ assertNotNull(user);
+ assertTrue(user.canAdmin);
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("Local User", user.displayName);
+ assertFalse(user.canCreate);
+ assertFalse(user.canFork);
+ assertFalse(user.canAdmin);
+ }
+
+
+ @Test
+ public void testAuthenticateDenied()
+ {
+ UserModel user = null;
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
+ user = htpwdUserService.authenticate("user1", "".toCharArray());
+ assertNull("User 'user1' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("user1", "pass2".toCharArray());
+ assertNull("User 'user1' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("user2", "lalala".toCharArray());
+ assertNull("User 'user2' falsely authenticated.", user);
+
+
+ user = htpwdUserService.authenticate("user3", "disabled".toCharArray());
+ assertNull("User 'user3' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("user4", "disabled".toCharArray());
+ assertNull("User 'user4' falsely authenticated.", user);
+
+
+ user = htpwdUserService.authenticate("plain", "text".toCharArray());
+ assertNull("User 'plain' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("plain", "password".toCharArray());
+ assertNull("User 'plain' falsely authenticated.", user);
+
+
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
+
+ user = htpwdUserService.authenticate("crypt", "".toCharArray());
+ assertNull("User 'cyrpt' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("crypt", "passwd".toCharArray());
+ assertNull("User 'crypt' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("md5", "".toCharArray());
+ assertNull("User 'md5' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("md5", "pwd".toCharArray());
+ assertNull("User 'md5' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("sha", "".toCharArray());
+ assertNull("User 'sha' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate("sha", "letmein".toCharArray());
+ assertNull("User 'sha' falsely authenticated.", user);
+
+
+ user = htpwdUserService.authenticate(" tabbed", "frontAndBack".toCharArray());
+ assertNull("User 'tabbed' falsely authenticated.", user);
+
+ user = htpwdUserService.authenticate(" leading", "whitespace".toCharArray());
+ assertNull("User 'leading' falsely authenticated.", user);
+ }
+
+
+ @Test
+ public void testNewLocalAccount()
+ {
+ UserModel newUser = new UserModel("newlocal");
+ newUser.displayName = "Local User 2";
+ newUser.password = StringUtils.MD5_TYPE + StringUtils.getMD5("localPwd2");
+ assertTrue("Failed to add local account.", htpwdUserService.updateUserModel(newUser));
+
+ UserModel localAccount = htpwdUserService.authenticate(newUser.username, "localPwd2".toCharArray());
+ assertNotNull(localAccount);
+ assertEquals(newUser, localAccount);
+
+ localAccount = htpwdUserService.authenticate(newUser.username, "localPwd2".toCharArray());
+ assertNotNull(localAccount);
+ assertEquals(newUser, localAccount);
+
+ assertTrue("Failed to delete local account.", htpwdUserService.deleteUser(localAccount.username));
+ assertNull(htpwdUserService.authenticate(newUser.username, "localPwd2".toCharArray()));
+ }
+
+
+ @Test
+ public void testCleartextIntrusion()
+ {
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
+ assertNull(htpwdUserService.authenticate("md5", "$apr1$qAGGNfli$sAn14mn.WKId/3EQS7KSX0".toCharArray()));
+ assertNull(htpwdUserService.authenticate("sha", "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=".toCharArray()));
+
+ assertNull(htpwdUserService.authenticate("user1", "#externalAccount".toCharArray()));
+
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
+ assertNull(htpwdUserService.authenticate("md5", "$apr1$qAGGNfli$sAn14mn.WKId/3EQS7KSX0".toCharArray()));
+ assertNull(htpwdUserService.authenticate("sha", "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=".toCharArray()));
+
+ assertNull(htpwdUserService.authenticate("user1", "#externalAccount".toCharArray()));
+ }
+
+
+ @Test
+ public void testCryptVsPlaintext()
+ {
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false");
+ assertNull(htpwdUserService.authenticate("crypt", "6TmlbxqZ2kBIA".toCharArray()));
+ assertNotNull(htpwdUserService.authenticate("crypt", "password".toCharArray()));
+
+ MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
+ assertNotNull(htpwdUserService.authenticate("crypt", "6TmlbxqZ2kBIA".toCharArray()));
+ assertNull(htpwdUserService.authenticate("crypt", "password".toCharArray()));
+ }
+
+
+ /*
+ * Test case: User exists in user.conf with a local password and in htpasswd with an external password.
+ * If overrideLocalAuthentication is false, the local account takes precedence and is never updated.
+ */
+ @Test
+ public void testPreparedAccountPreferLocal() throws IOException
+ {
+ setupUS(false);
+
+ UserModel user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("staylocal", user.getName());
+
+
+ deleteGeneratedFiles();
+ copyInFiles();
+ setupUS(false);
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("staylocal", user.getName());
+ }
+
+
+ /*
+ * Test case: User exists in user.conf with a local password and in htpasswd with an external password.
+ * If overrideLocalAuthentication is true, the external account takes precedence,
+ * the initial local password is never used and discarded.
+ */
+ @Test
+ public void testPreparedAccountPreferExternal() throws IOException
+ {
+ setupUS(true);
+
+ UserModel user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("staylocal", user.getName());
+
+
+ deleteGeneratedFiles();
+ copyInFiles();
+ setupUS(true);
+
+
+ user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("staylocal", user.getName());
+
+ // Make sure no authentication by using the string constant for external accounts is possible.
+ user = htpwdUserService.authenticate("leaderred", "#externalAccount".toCharArray());
+ assertNull(user);
+ }
+
+
+ /*
+ * Test case: User exists in user.conf with a local password and in htpasswd with an external password.
+ * If overrideLocalAuthentication is true, the external account takes precedence,
+ * the initial local password is never used and discarded.
+ */
+ @Test
+ public void testPreparedAccountChangeSetting() throws IOException
+ {
+ getSettings(false);
+
+ UserModel user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("staylocal", user.getName());
+
+
+ getSettings(true);
+
+
+ user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("staylocal", user.getName());
+
+ // Make sure no authentication by using the string constant for external accounts is possible.
+ user = htpwdUserService.authenticate("leaderred", "#externalAccount".toCharArray());
+ assertNull(user);
+
+
+ getSettings(false);
+ // The preference is now back to local accounts but since the prepared account got switched
+ // to an external account, it will stay this way.
+
+ user = htpwdUserService.authenticate("leaderred", "localPassword".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("leaderred", "externalPassword".toCharArray());
+ assertNotNull(user);
+ assertEquals("leaderred", user.getName());
+
+ user = htpwdUserService.authenticate("staylocal", "localUser".toCharArray());
+ assertNotNull(user);
+ assertEquals("staylocal", user.getName());
+
+ // Make sure no authentication by using the string constant for external accounts is possible.
+ user = htpwdUserService.authenticate("leaderred", "#externalAccount".toCharArray());
+ assertNull(user);
+ }
+
+
+ @Test
+ public void testChangeHtpasswdFile()
+ {
+ UserModel user;
+
+ // User default set up.
+ user = htpwdUserService.authenticate("md5", "password".toCharArray());
+ assertNotNull(user);
+ assertEquals("md5", user.username);
+
+ user = htpwdUserService.authenticate("sha", "password".toCharArray());
+ assertNotNull(user);
+ assertEquals("sha", user.username);
+
+ user = htpwdUserService.authenticate("blueone", "GoBlue!".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("bluetwo", "YayBlue!".toCharArray());
+ assertNull(user);
+
+
+ // Switch to different htpasswd file.
+ getSettings(RESOURCE_DIR + "htpasswd-user", null, null);
+
+ user = htpwdUserService.authenticate("md5", "password".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("sha", "password".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("blueone", "GoBlue!".toCharArray());
+ assertNotNull(user);
+ assertEquals("blueone", user.username);
+
+ user = htpwdUserService.authenticate("bluetwo", "YayBlue!".toCharArray());
+ assertNotNull(user);
+ assertEquals("bluetwo", user.username);
+ }
+
+
+ @Test
+ public void testChangeHtpasswdFileNotExisting()
+ {
+ UserModel user;
+
+ // User default set up.
+ user = htpwdUserService.authenticate("md5", "password".toCharArray());
+ assertNotNull(user);
+ assertEquals("md5", user.username);
+
+ user = htpwdUserService.authenticate("sha", "password".toCharArray());
+ assertNotNull(user);
+ assertEquals("sha", user.username);
+
+ user = htpwdUserService.authenticate("blueone", "GoBlue!".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("bluetwo", "YayBlue!".toCharArray());
+ assertNull(user);
+
+
+ // Switch to different htpasswd file that doesn't exist.
+ // Currently we stop working with old users upon this change.
+ getSettings(RESOURCE_DIR + "no-such-file", null, null);
+
+ user = htpwdUserService.authenticate("md5", "password".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("sha", "password".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("blueone", "GoBlue!".toCharArray());
+ assertNull(user);
+
+ user = htpwdUserService.authenticate("bluetwo", "YayBlue!".toCharArray());
+ assertNull(user);
+ }
+
+}