For my JSF 2.3 application, I use form login in to authenticate user (against LDAP). The container is Liberty server.
This is all working fine.
However, I am trying to implement user lockout after 3 failed login attempts and I am not sure how to do that.
My application uses j_security_check and I have login.xhtml as:
<!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"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:myapp="http://java.sun.com/jsf/composite/myapp">
<ui:composition template="/WEB-INF/myapp-sidebar.xhtml">
<ui:param name="title" value="#{uir['login.title']}" />
<ui:define name="sidebar">
<form action="j_security_check" method="post">
<!-- user name -->
<div class="form-group">
<h:outputLabel for="userName" value="#{uir['userName.label']}" />
<h:inputText autofocus="autofocus"
cols="#{uir['userName.input.length']}" id="j_username"
maxlength="#{uir['userName.input.length']}" name="j_username"
styleClass="form-control input-sm">
<f:attribute name="autocomplete" value="off" />
</h:inputText>
</div>
<!-- password -->
<div class="form-group">
<h:outputLabel for="password" value="#{uir['password.label']}" />
<h:inputSecret cols="#{uir['password.input.length']}"
id="j_password" maxlength="#{uir['password.input.length']}"
name="j_password" styleClass="form-control input-sm">
<f:attribute name="autocomplete" value="off" />
</h:inputSecret>
</div>
<div class="btn-group-vertical btn-group-sm btn-block">
<input class="btn btn-primary btn-active" type="submit"
value="#{uir['login.label']}" />
</div>
</form>
<script type="text/javascript">
window.onload = function() {
document.getElementById('j_username').focus();
}
</script>
</ui:define>
</ui:composition>
</html>
and in web.xml, I have
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/errorlogin.xhtml</form-error-page>
</form-login-config>
</login-config>
, and my errorlogin.xhtml is
<!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"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<ui:composition template="/WEB-INF/myapp.xhtml">
<ui:param name="title" value="#{uir['error.title']}" />
<ui:define name="content">
<h1>Login Error</h1>
<h2>Invalid user name or password</h2>
<p></p>
<h:link outcome="login">Return to login page</h:link>
</ui:define>
</ui:composition>
</html>
My current implementation is handling logins and logouts and login errors propertly. If user attempts to login and provides wrong credentials, the errorlogin.xhtml page will show.
However, I am trying to implement user lockout after user fails to successfully login 3 times in a row. User should be unlocked after X minutes to allow them to try logging in again.
How do I do that?
I solved this problem by implementing a service with LoadingCache
private LoadingCache<String, Integer> attemptsCache;
which would be an expirycache (expireAfterWrite()).
on successful login, cache would be invalidated
on failed login, cache would update its integer
on isLockedout, cache would check ints integer and based on its result return true or false
Then I provided a filter which would check if user isLockedOut in its doFilter() method and based on result call cache onSuccessful or onFailedLogin