| /* |
| * Copyright 2013 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 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.IStoredSettings; |
| import com.gitblit.auth.HtpasswdAuthProvider; |
| import com.gitblit.manager.AuthenticationManager; |
| import com.gitblit.manager.RuntimeManager; |
| import com.gitblit.manager.UserManager; |
| import com.gitblit.models.UserModel; |
| import com.gitblit.tests.mock.MemorySettings; |
| import com.gitblit.utils.XssFilter; |
| import com.gitblit.utils.XssFilter.AllowXssFilter; |
| |
| /** |
| * Test the Htpasswd user service. |
| * |
| */ |
| public class HtpasswdAuthenticationTest extends GitblitUnitTest { |
| |
| private static final String RESOURCE_DIR = "src/test/resources/htpasswd/"; |
| 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 HtpasswdAuthProvider htpasswd; |
| |
| private AuthenticationManager auth; |
| |
| private MemorySettings getSettings(String userfile, String groupfile, Boolean overrideLA) |
| { |
| MS.put("realm.userService", 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 void setupUS() |
| { |
| htpasswd = newHtpasswdAuthentication(getSettings()); |
| auth = newAuthenticationManager(getSettings()); |
| } |
| |
| private HtpasswdAuthProvider newHtpasswdAuthentication(IStoredSettings settings) { |
| XssFilter xssFilter = new AllowXssFilter(); |
| RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start(); |
| UserManager users = new UserManager(runtime, null).start(); |
| HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider(); |
| htpasswd.setup(runtime, users); |
| return htpasswd; |
| } |
| |
| private AuthenticationManager newAuthenticationManager(IStoredSettings settings) { |
| XssFilter xssFilter = new AllowXssFilter(); |
| RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start(); |
| UserManager users = new UserManager(runtime, null).start(); |
| HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider(); |
| htpasswd.setup(runtime, users); |
| AuthenticationManager auth = new AuthenticationManager(runtime, users); |
| auth.addAuthenticationProvider(htpasswd); |
| return auth; |
| } |
| |
| |
| private void copyInFiles() throws IOException |
| { |
| File dir = new File(RESOURCE_DIR); |
| FilenameFilter filter = new FilenameFilter() { |
| @Override |
| 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() { |
| @Override |
| 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, htpasswd.getNumberHtpasswdUsers()); |
| } |
| |
| |
| @Test |
| public void testAuthenticate() |
| { |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true"); |
| UserModel user = htpasswd.authenticate("user1", "pass1".toCharArray()); |
| assertNotNull(user); |
| assertEquals("user1", user.username); |
| |
| user = htpasswd.authenticate("user2", "pass2".toCharArray()); |
| assertNotNull(user); |
| assertEquals("user2", user.username); |
| |
| // Test different encryptions |
| user = htpasswd.authenticate("plain", "passWord".toCharArray()); |
| assertNotNull(user); |
| assertEquals("plain", user.username); |
| |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false"); |
| user = htpasswd.authenticate("crypt", "password".toCharArray()); |
| assertNotNull(user); |
| assertEquals("crypt", user.username); |
| |
| user = htpasswd.authenticate("md5", "password".toCharArray()); |
| assertNotNull(user); |
| assertEquals("md5", user.username); |
| |
| user = htpasswd.authenticate("sha", "password".toCharArray()); |
| assertNotNull(user); |
| assertEquals("sha", user.username); |
| |
| |
| // Test leading and trailing whitespace |
| user = htpasswd.authenticate("trailing", "whitespace".toCharArray()); |
| assertNotNull(user); |
| assertEquals("trailing", user.username); |
| |
| user = htpasswd.authenticate("tabbed", "frontAndBack".toCharArray()); |
| assertNotNull(user); |
| assertEquals("tabbed", user.username); |
| |
| user = htpasswd.authenticate("leading", "whitespace".toCharArray()); |
| assertNotNull(user); |
| assertEquals("leading", user.username); |
| } |
| |
| |
| @Test |
| public void testAuthenticationManager() |
| { |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true"); |
| UserModel user = auth.authenticate("user1", "pass1".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("user1", user.username); |
| |
| user = auth.authenticate("user2", "pass2".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("user2", user.username); |
| |
| // Test different encryptions |
| user = auth.authenticate("plain", "passWord".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("plain", user.username); |
| |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false"); |
| user = auth.authenticate("crypt", "password".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("crypt", user.username); |
| |
| user = auth.authenticate("md5", "password".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("md5", user.username); |
| |
| user = auth.authenticate("sha", "password".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("sha", user.username); |
| |
| |
| // Test leading and trailing whitespace |
| user = auth.authenticate("trailing", "whitespace".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("trailing", user.username); |
| |
| user = auth.authenticate("tabbed", "frontAndBack".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("tabbed", user.username); |
| |
| user = auth.authenticate("leading", "whitespace".toCharArray(), null); |
| assertNotNull(user); |
| assertEquals("leading", user.username); |
| } |
| |
| |
| @Test |
| public void testAttributes() |
| { |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true"); |
| UserModel user = htpasswd.authenticate("user1", "pass1".toCharArray()); |
| assertNotNull(user); |
| assertEquals("El Capitan", user.displayName); |
| assertEquals("cheffe@example.com", user.emailAddress); |
| assertTrue(user.canAdmin); |
| |
| user = htpasswd.authenticate("user2", "pass2".toCharArray()); |
| assertNotNull(user); |
| assertEquals("User Two", user.displayName); |
| assertTrue(user.canCreate); |
| assertTrue(user.canFork); |
| } |
| |
| |
| @Test |
| public void testAuthenticateDenied() |
| { |
| UserModel user = null; |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true"); |
| user = htpasswd.authenticate("user1", "".toCharArray()); |
| assertNull("User 'user1' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("user1", "pass2".toCharArray()); |
| assertNull("User 'user1' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("user2", "lalala".toCharArray()); |
| assertNull("User 'user2' falsely authenticated.", user); |
| |
| |
| user = htpasswd.authenticate("user3", "disabled".toCharArray()); |
| assertNull("User 'user3' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("user4", "disabled".toCharArray()); |
| assertNull("User 'user4' falsely authenticated.", user); |
| |
| |
| user = htpasswd.authenticate("plain", "text".toCharArray()); |
| assertNull("User 'plain' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("plain", "password".toCharArray()); |
| assertNull("User 'plain' falsely authenticated.", user); |
| |
| |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false"); |
| |
| user = htpasswd.authenticate("crypt", "".toCharArray()); |
| assertNull("User 'cyrpt' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("crypt", "passwd".toCharArray()); |
| assertNull("User 'crypt' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("md5", "".toCharArray()); |
| assertNull("User 'md5' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("md5", "pwd".toCharArray()); |
| assertNull("User 'md5' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("sha", "".toCharArray()); |
| assertNull("User 'sha' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate("sha", "letmein".toCharArray()); |
| assertNull("User 'sha' falsely authenticated.", user); |
| |
| |
| user = htpasswd.authenticate(" tabbed", "frontAndBack".toCharArray()); |
| assertNull("User 'tabbed' falsely authenticated.", user); |
| |
| user = htpasswd.authenticate(" leading", "whitespace".toCharArray()); |
| assertNull("User 'leading' falsely authenticated.", user); |
| } |
| |
| |
| @Test |
| public void testAuthenticationMangerDenied() |
| { |
| UserModel user = null; |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true"); |
| user = auth.authenticate("user1", "".toCharArray(), null); |
| assertNull("User 'user1' falsely authenticated.", user); |
| |
| user = auth.authenticate("user1", "pass2".toCharArray(), null); |
| assertNull("User 'user1' falsely authenticated.", user); |
| |
| user = auth.authenticate("user2", "lalala".toCharArray(), null); |
| assertNull("User 'user2' falsely authenticated.", user); |
| |
| |
| user = auth.authenticate("user3", "disabled".toCharArray(), null); |
| assertNull("User 'user3' falsely authenticated.", user); |
| |
| user = auth.authenticate("user4", "disabled".toCharArray(), null); |
| assertNull("User 'user4' falsely authenticated.", user); |
| |
| |
| user = auth.authenticate("plain", "text".toCharArray(), null); |
| assertNull("User 'plain' falsely authenticated.", user); |
| |
| user = auth.authenticate("plain", "password".toCharArray(), null); |
| assertNull("User 'plain' falsely authenticated.", user); |
| |
| |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false"); |
| |
| user = auth.authenticate("crypt", "".toCharArray(), null); |
| assertNull("User 'cyrpt' falsely authenticated.", user); |
| |
| user = auth.authenticate("crypt", "passwd".toCharArray(), null); |
| assertNull("User 'crypt' falsely authenticated.", user); |
| |
| user = auth.authenticate("md5", "".toCharArray(), null); |
| assertNull("User 'md5' falsely authenticated.", user); |
| |
| user = auth.authenticate("md5", "pwd".toCharArray(), null); |
| assertNull("User 'md5' falsely authenticated.", user); |
| |
| user = auth.authenticate("sha", "".toCharArray(), null); |
| assertNull("User 'sha' falsely authenticated.", user); |
| |
| user = auth.authenticate("sha", "letmein".toCharArray(), null); |
| assertNull("User 'sha' falsely authenticated.", user); |
| |
| |
| user = auth.authenticate(" tabbed", "frontAndBack".toCharArray(), null); |
| assertNull("User 'tabbed' falsely authenticated.", user); |
| |
| user = auth.authenticate(" leading", "whitespace".toCharArray(), null); |
| assertNull("User 'leading' falsely authenticated.", user); |
| } |
| |
| @Test |
| public void testCleartextIntrusion() |
| { |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true"); |
| assertNull(htpasswd.authenticate("md5", "$apr1$qAGGNfli$sAn14mn.WKId/3EQS7KSX0".toCharArray())); |
| assertNull(htpasswd.authenticate("sha", "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=".toCharArray())); |
| |
| assertNull(htpasswd.authenticate("user1", "#externalAccount".toCharArray())); |
| |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false"); |
| assertNull(htpasswd.authenticate("md5", "$apr1$qAGGNfli$sAn14mn.WKId/3EQS7KSX0".toCharArray())); |
| assertNull(htpasswd.authenticate("sha", "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=".toCharArray())); |
| |
| assertNull(htpasswd.authenticate("user1", "#externalAccount".toCharArray())); |
| } |
| |
| |
| @Test |
| public void testCryptVsPlaintext() |
| { |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "false"); |
| assertNull(htpasswd.authenticate("crypt", "6TmlbxqZ2kBIA".toCharArray())); |
| assertNotNull(htpasswd.authenticate("crypt", "password".toCharArray())); |
| |
| MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true"); |
| assertNotNull(htpasswd.authenticate("crypt", "6TmlbxqZ2kBIA".toCharArray())); |
| assertNull(htpasswd.authenticate("crypt", "password".toCharArray())); |
| } |
| |
| @Test |
| public void testChangeHtpasswdFile() |
| { |
| UserModel user; |
| |
| // User default set up. |
| user = htpasswd.authenticate("md5", "password".toCharArray()); |
| assertNotNull(user); |
| assertEquals("md5", user.username); |
| |
| user = htpasswd.authenticate("sha", "password".toCharArray()); |
| assertNotNull(user); |
| assertEquals("sha", user.username); |
| |
| user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray()); |
| assertNull(user); |
| |
| user = htpasswd.authenticate("bluetwo", "YayBlue!".toCharArray()); |
| assertNull(user); |
| |
| |
| // Switch to different htpasswd file. |
| getSettings(RESOURCE_DIR + "htpasswd-user", null, null); |
| |
| user = htpasswd.authenticate("md5", "password".toCharArray()); |
| assertNull(user); |
| |
| user = htpasswd.authenticate("sha", "password".toCharArray()); |
| assertNull(user); |
| |
| user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray()); |
| assertNotNull(user); |
| assertEquals("blueone", user.username); |
| |
| user = htpasswd.authenticate("bluetwo", "YayBlue!".toCharArray()); |
| assertNotNull(user); |
| assertEquals("bluetwo", user.username); |
| } |
| |
| |
| @Test |
| public void testChangeHtpasswdFileNotExisting() |
| { |
| UserModel user; |
| |
| // User default set up. |
| user = htpasswd.authenticate("md5", "password".toCharArray()); |
| assertNotNull(user); |
| assertEquals("md5", user.username); |
| |
| user = htpasswd.authenticate("sha", "password".toCharArray()); |
| assertNotNull(user); |
| assertEquals("sha", user.username); |
| |
| user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray()); |
| assertNull(user); |
| |
| user = htpasswd.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 = htpasswd.authenticate("md5", "password".toCharArray()); |
| assertNull(user); |
| |
| user = htpasswd.authenticate("sha", "password".toCharArray()); |
| assertNull(user); |
| |
| user = htpasswd.authenticate("blueone", "GoBlue!".toCharArray()); |
| assertNull(user); |
| |
| user = htpasswd.authenticate("bluetwo", "YayBlue!".toCharArray()); |
| assertNull(user); |
| } |
| |
| } |