James Moger
2015-10-26 e69804d4001796a49476089bcbe8f67c3c700497
Merge pull request #947 from paulsputer/LogUpdateForAllAuthentication

Log update for Fail2Ban usage
11 files modified
132 ■■■■ changed files
src/main/java/com/gitblit/manager/AuthenticationManager.java 36 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/manager/GitblitManager.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/manager/IAuthenticationManager.java 3 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java 2 ●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/RootPage.java 5 ●●●● patch | view | raw | blame | history
src/site/setup_fail2ban.mkd 14 ●●●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/AuthenticationManagerTest.java 4 ●●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/GitBlitTest.java 2 ●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java 48 ●●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/LdapAuthenticationTest.java 12 ●●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java 2 ●●● patch | view | raw | blame | history
src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -310,15 +310,12 @@
            if (values.length == 2) {
                String username = values[0];
                char[] password = values[1].toCharArray();
                user = authenticate(username, password);
                user = authenticate(username, password, httpRequest.getRemoteAddr());
                if (user != null) {
                    flagRequest(httpRequest, AuthenticationType.CREDENTIALS, user.username);
                    logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}",
                            user.username, httpRequest.getRemoteAddr()));
                    return validateAuthentication(user, AuthenticationType.CREDENTIALS);
                } else {
                    logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}",
                            username, httpRequest.getRemoteAddr()));
                }
            }
        }
@@ -445,7 +442,7 @@
     * @return a user object or null
     */
    @Override
    public UserModel authenticate(String username, char[] password) {
    public UserModel authenticate(String username, char[] password, String remoteIP) {
        if (StringUtils.isEmpty(username)) {
            // can not authenticate empty username
            return null;
@@ -462,22 +459,29 @@
        // try local authentication
        if (user != null && user.isLocalAccount()) {
            return authenticateLocal(user, password);
        }
        // try registered external authentication providers
        for (AuthenticationProvider provider : authenticationProviders) {
            if (provider instanceof UsernamePasswordAuthenticationProvider) {
                UserModel returnedUser = provider.authenticate(usernameDecoded, password);
                if (returnedUser != null) {
                    // user authenticated
                    returnedUser.accountType = provider.getAccountType();
                    return validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS);
            UserModel returnedUser = authenticateLocal(user, password);
            if (returnedUser != null) {
                // user authenticated
                return returnedUser;
            }
        } else {
            // try registered external authentication providers
            for (AuthenticationProvider provider : authenticationProviders) {
                if (provider instanceof UsernamePasswordAuthenticationProvider) {
                    UserModel returnedUser = provider.authenticate(usernameDecoded, password);
                    if (returnedUser != null) {
                        // user authenticated
                        returnedUser.accountType = provider.getAccountType();
                        return validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS);
                    }
                }
            }
        }
        // could not authenticate locally or with a provider
        logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}", username,
                remoteIP != null ? remoteIP : "unknown"));
        return null;
    }
src/main/java/com/gitblit/manager/GitblitManager.java
@@ -649,8 +649,8 @@
     */
    @Override
    public UserModel authenticate(String username, char[] password) {
        return authenticationManager.authenticate(username, password);
    public UserModel authenticate(String username, char[] password, String remoteIP) {
        return authenticationManager.authenticate(username, password, remoteIP);
    }
    @Override
src/main/java/com/gitblit/manager/IAuthenticationManager.java
@@ -65,10 +65,11 @@
     * @see IUserService.authenticate(String, char[])
     * @param username
     * @param password
     * @param remoteIP
     * @return a user object or null
     * @since 1.4.0
     */
    UserModel authenticate(String username, char[] password);
    UserModel authenticate(String username, char[] password, String remoteIP);
    /**
     * Return the UserModel for already authenticated user.
src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java
@@ -51,7 +51,7 @@
        }
        username = username.toLowerCase(Locale.US);
        UserModel user = authManager.authenticate(username, password.toCharArray());
        UserModel user = authManager.authenticate(username, password.toCharArray(), null);
        if (user != null) {
            client.setUser(user);
            return true;
src/main/java/com/gitblit/wicket/pages/RootPage.java
@@ -36,6 +36,7 @@
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.PageParameters;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.behavior.HeaderContributor;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
@@ -566,7 +567,9 @@
                    String username = RootPage.this.username.getObject();
                    char[] password = RootPage.this.password.getObject().toCharArray();
                    UserModel user = app().authentication().authenticate(username, password);
                    HttpServletRequest request = ((WebRequest)RequestCycle.get().getRequest()).getHttpServletRequest();
                    UserModel user = app().authentication().authenticate(username, password, request.getRemoteAddr());
                    if (user == null) {
                        error(getString("gb.invalidUsernameOrPassword"));
                    } else if (user.username.equals(Constants.FEDERATION_USER)) {
src/site/setup_fail2ban.mkd
@@ -1,20 +1,24 @@
## Configure fail2ban for Gitblit-SSH
This procedure is based on a Debian installation of [fail2ban](http://www.fail2ban.org/), but it should works in any installation.
This procedure uses [fail2ban](http://www.fail2ban.org/).
First, create a new filter file `gitblit.conf` in filter directory (Debian: `/etc/fail2ban/filter.d/`) or into `filter.conf` file. Here an example:
First, create a new filter file `gitblit.conf` in filter directory (Debian/CentOS: `/etc/fail2ban/filter.d/`) or into `filter.conf` file. Here is an example:
    [Definition]
    failregex = could not authenticate .*? \(/<HOST>:[0-9]*\) for SSH using the supplied password$
    failregex =  Failed login attempt for .+, invalid credentials from <HOST>\s*$
                 could not authenticate .*? \(/<HOST>:[0-9]*\) for SSH using the supplied password$
    ignoreregex =
Then edit `jail.conf` to add "gitblit" service (Debian: `/etc/fail2ban/jail.conf`). For example:
    [gitblit]
    enabled = true
    port = 22
    port = 443,29418
    protocol = tcp
    filter = gitblit
    logpath = /var/log/gitblit.log
Restart fail2ban to apply (Debian: `/etc/init.d/fail2ban restart`).
Reload fail2ban config to apply (`fail2ban-client reload`).
Check the status of the gitblit fail2ban jail with `fail2ban-client status gitblit`
src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
@@ -657,11 +657,11 @@
        user.password = "password";
        users.updateUserModel(user);
        assertNotNull(auth.authenticate(user.username, user.password.toCharArray()));
        assertNotNull(auth.authenticate(user.username, user.password.toCharArray(), null));
        user.disabled = true;
        users.updateUserModel(user);
        assertNull(auth.authenticate(user.username, user.password.toCharArray()));
        assertNull(auth.authenticate(user.username, user.password.toCharArray(), null));
        users.deleteUserModel(user);
    }
src/test/java/com/gitblit/tests/GitBlitTest.java
@@ -176,7 +176,7 @@
    @Test
    public void testAuthentication() throws Exception {
        assertTrue(authentication().authenticate("admin", "admin".toCharArray()) != null);
        assertTrue(authentication().authenticate("admin", "admin".toCharArray(), null) != null);
    }
    @Test
src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java
@@ -200,43 +200,43 @@
    public void testAuthenticationManager()
    {
        MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
        UserModel user = auth.authenticate("user1", "pass1".toCharArray());
        UserModel user = auth.authenticate("user1", "pass1".toCharArray(), null);
        assertNotNull(user);
        assertEquals("user1", user.username);
        user = auth.authenticate("user2", "pass2".toCharArray());
        user = auth.authenticate("user2", "pass2".toCharArray(), null);
        assertNotNull(user);
        assertEquals("user2", user.username);
        // Test different encryptions
        user = auth.authenticate("plain", "passWord".toCharArray());
        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());
        user = auth.authenticate("crypt", "password".toCharArray(), null);
        assertNotNull(user);
        assertEquals("crypt", user.username);
        user = auth.authenticate("md5", "password".toCharArray());
        user = auth.authenticate("md5", "password".toCharArray(), null);
        assertNotNull(user);
        assertEquals("md5", user.username);
        user = auth.authenticate("sha", "password".toCharArray());
        user = auth.authenticate("sha", "password".toCharArray(), null);
        assertNotNull(user);
        assertEquals("sha", user.username);
        // Test leading and trailing whitespace
        user = auth.authenticate("trailing", "whitespace".toCharArray());
        user = auth.authenticate("trailing", "whitespace".toCharArray(), null);
        assertNotNull(user);
        assertEquals("trailing", user.username);
        user = auth.authenticate("tabbed", "frontAndBack".toCharArray());
        user = auth.authenticate("tabbed", "frontAndBack".toCharArray(), null);
        assertNotNull(user);
        assertEquals("tabbed", user.username);
        user = auth.authenticate("leading", "whitespace".toCharArray());
        user = auth.authenticate("leading", "whitespace".toCharArray(), null);
        assertNotNull(user);
        assertEquals("leading", user.username);
    }
@@ -323,55 +323,55 @@
    {
        UserModel user = null;
        MS.put(KEY_SUPPORT_PLAINTEXT_PWD, "true");
        user = auth.authenticate("user1", "".toCharArray());
        user = auth.authenticate("user1", "".toCharArray(), null);
        assertNull("User 'user1' falsely authenticated.", user);
        user = auth.authenticate("user1", "pass2".toCharArray());
        user = auth.authenticate("user1", "pass2".toCharArray(), null);
        assertNull("User 'user1' falsely authenticated.", user);
        user = auth.authenticate("user2", "lalala".toCharArray());
        user = auth.authenticate("user2", "lalala".toCharArray(), null);
        assertNull("User 'user2' falsely authenticated.", user);
        user = auth.authenticate("user3", "disabled".toCharArray());
        user = auth.authenticate("user3", "disabled".toCharArray(), null);
        assertNull("User 'user3' falsely authenticated.", user);
        user = auth.authenticate("user4", "disabled".toCharArray());
        user = auth.authenticate("user4", "disabled".toCharArray(), null);
        assertNull("User 'user4' falsely authenticated.", user);
        user = auth.authenticate("plain", "text".toCharArray());
        user = auth.authenticate("plain", "text".toCharArray(), null);
        assertNull("User 'plain' falsely authenticated.", user);
        user = auth.authenticate("plain", "password".toCharArray());
        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());
        user = auth.authenticate("crypt", "".toCharArray(), null);
        assertNull("User 'cyrpt' falsely authenticated.", user);
        user = auth.authenticate("crypt", "passwd".toCharArray());
        user = auth.authenticate("crypt", "passwd".toCharArray(), null);
        assertNull("User 'crypt' falsely authenticated.", user);
        user = auth.authenticate("md5", "".toCharArray());
        user = auth.authenticate("md5", "".toCharArray(), null);
        assertNull("User 'md5' falsely authenticated.", user);
        user = auth.authenticate("md5", "pwd".toCharArray());
        user = auth.authenticate("md5", "pwd".toCharArray(), null);
        assertNull("User 'md5' falsely authenticated.", user);
        user = auth.authenticate("sha", "".toCharArray());
        user = auth.authenticate("sha", "".toCharArray(), null);
        assertNull("User 'sha' falsely authenticated.", user);
        user = auth.authenticate("sha", "letmein".toCharArray());
        user = auth.authenticate("sha", "letmein".toCharArray(), null);
        assertNull("User 'sha' falsely authenticated.", user);
        user = auth.authenticate("  tabbed", "frontAndBack".toCharArray());
        user = auth.authenticate("  tabbed", "frontAndBack".toCharArray(), null);
        assertNull("User 'tabbed' falsely authenticated.", user);
        user = auth.authenticate("    leading", "whitespace".toCharArray());
        user = auth.authenticate("    leading", "whitespace".toCharArray(), null);
        assertNull("User 'leading' falsely authenticated.", user);
    }
src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
@@ -240,23 +240,23 @@
    @Test
    public void testAuthenticationManager() {
        UserModel userOneModel = auth.authenticate("UserOne", "userOnePassword".toCharArray());
        UserModel userOneModel = auth.authenticate("UserOne", "userOnePassword".toCharArray(), null);
        assertNotNull(userOneModel);
        assertNotNull(userOneModel.getTeam("git_admins"));
        assertNotNull(userOneModel.getTeam("git_users"));
        assertTrue(userOneModel.canAdmin);
        UserModel userOneModelFailedAuth = auth.authenticate("UserOne", "userTwoPassword".toCharArray());
        UserModel userOneModelFailedAuth = auth.authenticate("UserOne", "userTwoPassword".toCharArray(), null);
        assertNull(userOneModelFailedAuth);
        UserModel userTwoModel = auth.authenticate("UserTwo", "userTwoPassword".toCharArray());
        UserModel userTwoModel = auth.authenticate("UserTwo", "userTwoPassword".toCharArray(), null);
        assertNotNull(userTwoModel);
        assertNotNull(userTwoModel.getTeam("git_users"));
        assertNull(userTwoModel.getTeam("git_admins"));
        assertNotNull(userTwoModel.getTeam("git admins"));
        assertTrue(userTwoModel.canAdmin);
        UserModel userThreeModel = auth.authenticate("UserThree", "userThreePassword".toCharArray());
        UserModel userThreeModel = auth.authenticate("UserThree", "userThreePassword".toCharArray(), null);
        assertNotNull(userThreeModel);
        assertNotNull(userThreeModel.getTeam("git_users"));
        assertNull(userThreeModel.getTeam("git_admins"));
@@ -269,10 +269,10 @@
        settings.put(Keys.realm.ldap.username, "");
        settings.put(Keys.realm.ldap.password, "");
        UserModel userOneModel = auth.authenticate("UserOne", "userOnePassword".toCharArray());
        UserModel userOneModel = auth.authenticate("UserOne", "userOnePassword".toCharArray(), null);
        assertNotNull(userOneModel);
        UserModel userOneModelFailedAuth = auth.authenticate("UserOne", "userTwoPassword".toCharArray());
        UserModel userOneModelFailedAuth = auth.authenticate("UserOne", "userTwoPassword".toCharArray(), null);
        assertNull(userOneModelFailedAuth);
    }
src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java
@@ -65,7 +65,7 @@
    @Test
    public void testAuthenticationManager() throws Exception {
        AuthenticationManager auth = newAuthenticationManager();
        UserModel userModel = auth.authenticate("RedmineAdminId", "RedmineAPIKey".toCharArray());
        UserModel userModel = auth.authenticate("RedmineAdminId", "RedmineAPIKey".toCharArray(), null);
        assertThat(userModel.getName(), is("redmineadminid"));
        assertThat(userModel.getDisplayName(), is("baz foo"));
        assertThat(userModel.emailAddress, is("baz@example.com"));