Sorry for the late reply, you probably have already found a solution for this (if so, let us know!), but here is a suggestion out of the box...
This will only work if you use form-based login, and it's not a really super-beautiful solution, but i think it's appserver independent and at least it's very simple. I just implemented it in my own app to try it within 15 minutes. :)
Assuming you are using form-based login and have a login JSP, use code along these lines to count the number of failed login attempts and take some special action when it reaches some treshold:
(login.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="
http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<c:choose>
<c:when test="${empty login_failed}">
<p>Please enter your credentials.</p>
</c:when>
<c:otherwise>
<%
// At this point, login failed. Store the amount of failed attempts in the
// session and possibly take some action when it exceeds some threshold.
String LOGIN_ATTEMPTS = "failedLoginAttempts";
int FAILURE_THRESHOLD = 3;
// First get the current amount of failed attempts from the session, if any
int failedAttempts = 0;
Object attempts = request.getSession().getAttribute(LOGIN_ATTEMPTS);
if (attempts instanceof Integer)
failedAttempts = ((Integer) attempts).intValue();
// Now increase the number
failedAttempts++;
// Store the increased number in the session
request.getSession().setAttribute(LOGIN_ATTEMPTS, new Integer(failedAttempts));
if (failedAttempts > FAILURE_THRESHOLD) {
// Do some smart things here, such as special logging of IP address...
%>
<p class="login-failed">Too many failed logins. Your IP address was logged.</p>
<%
}
else {
%>
<p class="login-failed">Login failed, please try again.</p>
<%
}
%>
</c:otherwise>
</c:choose>
<form method="post" action="j_security_check">
<div class="field username mandatory">
<label for="username">Username *</label>
<input id="username" name="j_username" type="text" class="text"
value="${username}" />
</div>
<div class="field password">
<label for="password">Password</label>
<input id="password" name="j_password" type="password" class="password"
value="${password}" />
</div>
<div class="buttons">
<input type="submit" id="login" class="button ok submit" value=" Login " />
</div>
</form>
</body>
</html>
This is my actual login.jsp, but the attempt counting I added just now for testing my solution. It's working. :)
I am actually using a servlet that uses
request.getRequestDispatcher("/WEB-INF/jsp/auth/login.jsp").forward(request, response)
to forward the request to the JSP for rendering so actually it would make a lot more sense to put the counting code in there, but the above method will also work if you are not using a servlet between it and are using JSP directly.
Just for reference, here is the login config in web.xml:
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/auth/login</form-login-page>
<form-error-page>/auth/login?error=true</form-error-page>
</form-login-config>
</login-config>
As you can see I am using the same file both for normal login as for the error page, just adding the parameter error=true in case of an error. This is the parameter I am checking for in the JSP.
Any variation of this can be dreamed up but the moral of the story is that I think it's easiest to keep the counting and logging of IP stuff out of the loginmodule and just use the results of your login module indirectly through the error page. :)
[Message sent by forum member 'stijn_de_witt']
http://forums.java.net/jive/thread.jspa?messageID=470343