Back Forum Reply New

Capturing login failures

mon.util.Md5PasswordEncoderquot; /gt;
lt;/propertygt;
lt;/beangt;

I don't there there is anything to configure here apart from the listener.  I'm using this at the minute with no problems.

Common Problem #3: How do I disable a user after a number of failed logins?
faq.html


Originally Posted by karldmooreI don't there there is anything to configure here apart from the listener.  I'm using this at the minute with no problems.

Common Problem #3: How do I disable a user after a number of failed logins?
faq.html

I've followed the instructions in the faqs.  When debugging the listener, I am only seeing ContextRefreshEvents and ServletRequestHandledEvents.  Did I perhaps happen to miss a configuration that turns on the authentication events?

Thanks for bearing with me here.

Is it possible to see the configuration?

I've got this and it works fine.

Code:
lt;bean class=quot;com.architecture.demo.business.ApplicationSecurityListenerquot;/gt;

Code:
package com.architecture.demo.business;

import org.acegisecurity.event.authentication.AuthenticationFailureBadCredentialsEvent;
import org.acegisecurity.event.authentication.AuthenticationSuccessEvent;
import org.acegisecurity.event.authorization.AuthorizationFailureEvent;
import org.acegisecurity.event.authorization.AuthorizedEvent;
import org..context.ApplicationEvent;
import org..context.ApplicationListener;

public class ApplicationSecurityListener implements ApplicationListener
{
public void onApplicationEvent ( ApplicationEvent event )
{
if ( event instanceof AuthorizedEvent )
{
AuthorizedEvent authorizedEvent = ( AuthorizedEvent ) event;
System.out.println ( quot;authorized:quot; + authorizedEvent );
}
else if ( event instanceof AuthorizationFailureEvent )
{
AuthorizationFailureEvent authorizationFailureEvent = ( AuthorizationFailureEvent ) event;
System.out.println ( quot;not authorized:quot; + authorizationFailureEvent );
}
else if ( event instanceof AuthenticationFailureBadCredentialsEvent )
{
AuthenticationFailureBadCredentialsEvent badCredentialsEvent = ( AuthenticationFailureBadCredentialsEvent ) event;
System.out.println ( quot;badCredentials:quot; + badCredentialsEvent );
}
else if ( event instanceof AuthenticationSuccessEvent )
{
AuthenticationSuccessEvent authenticationSuccessEvent = ( AuthenticationSuccessEvent ) event;
System.out.println ( quot;authSuccess:quot; + authenticationSuccessEvent );
}
else
{
System.out.println ( quot;undefined: quot; + event.getClass ().getName () );
}
}
}What all do you need to see? The -security.xml and the -servlet.xml files?

The applicationContext.xml file (or whatever its called) that contains your beans for acegi.

Solved it.

We have three different configuration .xml files: app-security.xml, app-servlet.xml, and applicationContext.xml.  I had the listener defined in the app-servlet.xml file apart from the security configs in app-security.xml.  

Upon debugging through the source code, I noticed that when it tried to post the event, it couldn't find an application listener to post to.  I got the hunch that perhaps it wasn't defined in the right place.  When I moved the listener def to app-security.xml, it worked like a charm.

Thanks for the guidance.

Not a problem, glad it worked!  I was really racking my brains as to why it wouldn't work.  I thought it should be simply.  Oh well, its working now .

So where exactly do you put the counting? It can't be in the EventListener, or... this is a global object, right? The counting has to be on the user level, and as long as he/she isn't properly logged in... how do you do it?

I created an event handler for login failure and success events.  When the listener picks one of these up, the handler either increments the failure count or resets it to zero on a success.  The key to making this work is insuring that you have the username in the authentication event so that it can be matched to the user info in the database (where the count is kept).

For example (code somewhat truncated):

Capture the passwordMismatchEvent with the listener:

Code:
public class SecurityListener implements ApplicationListener {

private SecurityHandlerHelper handleUtil;

public void setHandleUtil(SecurityHandlerHelper handleUtil) {
this.handleUtil = handleUtil;
}//passwordMismatchEvent is a securityEvent
public void onApplicationEvent(ApplicationEvent event) throws AuthenticationException {
if(isSecurityEvent(event)) {
handleUtil.populateHandlerMap();
SecurityHandler handler = handleUtil.getHandler(parseEventName(event));
if(handler == null) {logger.debug(quot;not a handled security event: quot; + event.getClass().getSimpleName());       }       else {       handler.execute(event);       }
}
}
Execute the handler:

Code:
public class PasswordMismatchHandler extends AbstractSecurityHandlerltasswordMismatchgt; {

@Override
public void execute(PasswordMismatch event) {
String source = event.getSource().getClass().getName();
logger.debug(quot;SECURITY LISTENER: Password mismatch.quot;);
logger.debug(quot;USERNAME: quot;  + event.getUsername());              //call the database and increment failed login counter thru normal service/domain layer
processFailedAttempt(event.getUsername());
handlePasswordExceptionCases(source, messages.getMessage(quot;errors.authentication.usernamePasswordInvalidquot;));
}

}
Originally Posted by kantornSo where exactly do you put the counting? It can't be in the EventListener, or... this is a global object, right? The counting has to be on the user level, and as long as he/she isn't properly logged in... how do you do it?

Probably in a database (assuming you want it to be persistent).
¥
Back Forum Reply New