Archive for the ‘Aleksa's Blog’ Category

Acegi Concurrent Login

Thursday, May 8th, 2008

It is a security requirement for most web sites to disable concurrent logins, so users cannot login from different machines using same login details.

Let’s see how to enable this functionality with Acegi Security.

Firstly, add org.acegisecurity.concurrent.SessionRegistry implementation bean to your security context:

<bean id="sessionRegistry" class="org.acegisecurity.concurrent.SessionRegistryImpl" />

We are using default Acegi implementation org.acegisecurity.concurrent.SessionRegistryImpl.

Next, define the org.acegisecurity.concurrent.SessionController bean:


    <bean id="sessionController" class="org.acegisecurity.
           concurrent.ConcurrentSessionControllerImpl">
        <property name="exceptionIfMaximumExceeded" value="true"/>
        <property name="maximumSessions" value="1" />
        <property name="sessionRegistry" ref="sessionRegistry"/>
    </bean>

As you can see, it takes sessionRegistry property, as well as two additional properties maximumSessions and exceptionIfMAximumExceeded.
maximumSessions says how meny concurrent login sessions are allowed (in our case just one)
if exceptionIfMAximumExceeded property is set to true, exception will be thrown every time the user tries to login concurrently. You can check this exception in your login controller and display user with a message.
Otherwise, if exceptionIfMAximumExceeded property is set to false, exception will NOT be thrown. If user tries to login concurrently, he will be allowed, but his last login session (before the concurrent one) will be invalidated.

Last step is to add sessionController property to your ProviderManager bean:

     <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
		<property name="providers">
			<list>
				<ref local="daoAuthenticationProvider"/>
			</list>
		</property>
        <property name="sessionController" ref="sessionController"/>
    </bean>

And you’re ready to run.

Some users have encountered problems with concurrent logins: If a user logs out, and then tries to log in again, the ConcurrentLoginException is thrown, so user cannot log in again. This happens when Acegi logout does not remove the session data for the user that has been logout out (before his login session has expired)
In order to fix this, you can manually clear the authentication session for the user that’s logged out:

public void logout() {
        SecurityContext context = SecurityContextHolder.getContext();
        if (context == null) return;
        Authentication authentication = context.getAuthentication();
        if (authentication == null) return;
        String sessionId = SessionRegistryUtils.obtainSessionIdFromAuthentication(authentication);
        this.sessionRegistry.removeSessionInformation(sessionId);
}


You will also need this code to be run when Acegi session gets unpublished.
For this implement org.acegisecurity.ui.session.HttpSessionEventPublisher, and configure listener for it in your web.xml:

public class MyHttpSessionEventPublisher extends HttpSessionEventPublisher {
    private static final Log logger = LogFactory.getLog(MyHttpSessionEventPublisher.class);
    private UserContext userContext;

    public void sessionDestroyed(HttpSessionEvent event) {
        logger.info("unpublishing session");
        if (userContext == null) {
            this.userContext = lookupBean(
                        WebApplicationContextUtils.
                             getWebApplicationContext(
                              event.getSession().getServletContext()),
                       "userContext",
                       UserContext.class);
        }

        this.userContext.invalidate();
        super.sessionDestroyed(event);
    }

    private  T lookupBean(final ApplicationContext applicationContext, final String beanName, final Class c) {
        //noinspection unchecked
        return (T) applicationContext.getBean(beanName, c);
    }
}

In web.xml you will have:

<listener>
        <listener-class>net.cakesolutions.service.security.acegi.BimHttpSessionEventPublisher</listener-class>
</listener>


And you’re ready to go.

Hope this article has helped anyone in configuring concurrent logins with Acegi Security.

Email Header Injection security

Thursday, May 8th, 2008

If you web application sends emails based on information entered in the form, you should pay attention to the possibility of Email header injection attack.
Email header injection attack is based on flaws in the email protocol. Headers in the MIME message are recognized by SMTP servers by the line feed ([LF]). So typical email message looks like this:

[LF]to: recipient@domain.com
[LF]Subject: recipient@domain.com
[LF]Content type: recipient@domain.com
[LF]Message body

Now if a user can enter recipient email in the form he/she can do something like this:

recipient email: johndoe@serbiancafe.com%0Asubject:this is new even subject.

%0A is actually line feed.
Now, it will depend from SMTP server and email client which subject will it show, some use first one, some the lates one, some append all subjects to email.

Malicious user can change any header of your message this way, to, cc, bcc fields, content-type, even the actual message.

Message body can be changed in the same way, only without the header name. But note that body added like this will be PREPENDED to the email message. So if someone uses your email form to send an email message with new body he/she can enter the follwing in the available form filed (in our case recipient address):

recipient email: johndoe@serbiancafe.com%0Asubject:this is new even subject.%0AThe Spam message body, you didnt want this, but it will come to your inbox

And without knowing it, your ‘email this page to a friend’ form will become the source of spam!

Now how to resolve this issue?
You shpuld check all the fields that are available for user input in your email form for and characters (’\n’ and ‘\r’ in your java code).

You have two approaches available. You can either:
1. reject to send any email that contains any of these characters (recommended)
2. remove the characters and send the email as it is

The java code that does this is very simple:


public static boolean isHeaderInjection(String value) {
if (value == null) return false;
if ((value.indexOf("\n") != -1 || value.indexOf("\r") != -1) || value.indexOf("%0A") != -1) {
return true;
}
return false;
}

Make sure to check all your email form fields, and you should be safe from this kind of attack.

My First Post

Wednesday, January 23rd, 2008

Finally my first post.

It comes after sleepless night watching Australian Open (Djokovic and Ivanovic joined Jankovic in the semis, and in style, was worth it:)).

Some interesting times ahead, with Pro Spring 2.5 book work nearing the end, and few new projects coming.

I am currently working on some JMX management on Weblogic 9.2, will keep you posted how it goes.

Hopefully this is just a start of regular blog posting for me.

See you soon!