Then I remembered that fail2ban was installed on my server, which served that kind of purpose for ssh and various other systems. I tried to figure out a way to combine those two applications. Fail2ban reads the system's logs to determine if a connection must be bailed out or not.
So I modified sfDoctrineGuardPlugin to send messages in those logs. Each time that someone was using a wrong password, an entry in the log will be sent. For that, I had to modify plugins/sfDoctrineGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php .
if ($request->isMethod('post')) { $this->form->bind($request->getParameter('signin')); if ($this->form->isValid()) { $values = $this->form->getValues(); $this->getUser()->signin($values['user'], array_key_exists('remember', $values) ? $values['remember'] : false); // always redirect to a URL set in app.yml // or to the referer // or to the homepage $signinUrl = sfConfig::get('app_sf_guard_plugin_success_signin_url', $user->getReferer($request->getReferer())); return $this->redirect('' != $signinUrl ? $signinUrl : '@homepage'); } else { $values = $request->getParameter('signin'); openlog('mySystem', LOG_PID, LOG_AUTH); syslog(LOG_WARNING, sprintf('Failed password for %s from %s port 80 mySystem', $values['username'], $request->getRemoteAddress())); closelog(); } }
The diff :
--- BasesfGuardAuthActions.class-orig.php 2011-05-07 14:01:46.907823042 +0200 +++ BasesfGuardAuthActions.class.php 2011-03-12 11:07:26.107752306 +0100 @@ -41,10 +41,17 @@ // or to the homepage $signinUrl = sfConfig::get('app_sf_guard_plugin_success_signin_url', $user->getReferer($request->getReferer())); return $this->redirect('' != $signinUrl ? $signinUrl : '@homepage'); } + else + { + $values = $request->getParameter('signin'); + openlog('mySystem', LOG_PID, LOG_AUTH); + syslog(LOG_WARNING, sprintf('Failed password for %s from %s port 80 mySystem', $values['username'], $request->getRemoteAddress())); + closelog(); + } } else { if ($request->isXmlHttpRequest()) {
Now let's configure Fail2ban. I created I file called mySystem.conf in /etc/fail2ban/filter.d :
# Fail2Ban configuration file # # Author: Yoda-BZH # # $Revision: 728 $ # [INCLUDES] # Read common prefixes. If any customizations available -- read them from # common.local before = common.conf [Definition] _daemon = mySystem # Option: failregex # Notes.: regex to match the password failures messages in the logfile. The # host must be matched by a group named "host". The tag "<HOST>" can # be used for standard IP/hostname matching and is only an alias for # (?:::f{4,6}:)?(?P<host>[\w\-.^_]+) # Values: TEXT # #failregex = ^%(__prefix_line)s(?:error: PAM: )?Authentication failure for .* from <HOST>\s*$ # ^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$ failregex = ^%(__prefix_line)sFailed (?:password|publickey) for .* from <HOST>(?: port \d*)?(?: mySystem\d*)?$ # ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$ # ^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$ # ^%(__prefix_line)sUser .+ from <HOST> not allowed because not listed in AllowUsers$ # ^%(__prefix_line)sauthentication failure; logname=\S* uid=\S* euid=\S* tty=\S* ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$ # ^%(__prefix_line)srefused connect from \S+ \(<HOST>\)\s*$ # ^%(__prefix_line)sAddress <HOST> .* POSSIBLE BREAK-IN ATTEMPT!*\s*$ # ^%(__prefix_line)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$ # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex =
Make fail2ban use this filter in /etc/fail2ban/jail.conf
[mySystem] enabled = true port = 80 filter = mySystem logpath = /var/log/auth.log maxretry = 5
Now, just reload Fail2ban using /etc/init.d/fail2ban restart and that's it !
Nota: Yeah it would be better to override the executeSignin
method in a separate class, but I was a bit lazy.