This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

Spring Security, UserDetailsService, Load balancer, Session State

Sep 28th, 2011, 03:42 PM

Alright so first using Spring 3.0 and Spring Security 3.0.

First problem is that we are using a load balancer in our production environment and I've been told that we will not be using sticky sessions in tomcat. I've been looking for most of today trying to see if there is anything that could help me out. Have yet to find anything. The problem is that we use a custom authentication manager and filter when users log in to the system. I was going to use the remember me functionality but then trying to find on how to create a custom User details service to work with our custom autherntication manager is drawing a blank.

The way everything currently works is that a user logs in, the authentication manager sends the data over to a userservice class that encrypts the password with an attached key that then gets sent to Cold Fusion template that returns back the data on the user. Then the data returns gets processed by the service and then sent back to the authentication manager where it assigns the roles and sets the authentication based off the processed data. Then the filter is called and adds extra information for the webapp to use while the user is logged in. After everything is successful the user is redirected to the home page.

So everything works with a single box, user logs in and can use the site not problem. When its on the load balance the session is of course being invalidated since it's jumping between different boxes. The solution I came up with was to use remember me, except that I know I'm supposed to write a custom user detail service since we are using custom authentication classes. Now the only thing is I don't know exactly how to go about that or what needs to even be passed in to the user details class so that remember me works. If anyone can help me that would be great, because as of right now I'm at a loss. If anyone has any other ideas that could work that would be great as well. The more information the better.

The problem is that we use a custom authentication manager and filter when users log in to the system. I was going to use the remember me functionality but then trying to find on how to create a custom User details service to work with our custom autherntication manager is drawing a blank.

So long as you have a way to obtain the user principal, user password (optional), and roles given a username this should be pretty straight forward. If you do not have a way of doing this, you cannot really implement the UserDetailsService.

The solution I came up with was to use remember me, except that I know I'm supposed to write a custom user detail service since we are using custom authentication classes.

Using rememberme will require a hit to your UserDetailsService every time a different session is established (i.e. every time a user is routed to a different Tomcat instance). Depending on the UserDetailsService implementation, this can (and likely will) be quite costly from a performance perspective. It is better to try to allow the container to manage the session rather than creating your own session management.

Now the only thing is I don't know exactly how to go about that or what needs to even be passed in to the user details class so that remember me works. If anyone can help me that would be great, because as of right now I'm at a loss. If anyone has any other ideas that could work that would be great as well. The more information the better.

You really are going to be better off setting up the cluster to use sticky sessions. There are likely other reasons you will be using session which will also be impacted by this problem. For example, if you use the PRG a common way to deal with passing messages to error pages is to use the session. Spring Security does this when dealing with errors (i.e. a failed login). That isn't to say you cannot work around this, but the more you work around vs use things the way they are intended the more difficult it will be.

If I were you and I absolutely could not use sticky sessions, I would look into writing a custom SecurityContextRepository. This would allow you to save/retrieve the SecurityContext using something other than session. I would really be cautious doing this because security is a difficult thing (even the experts have a difficult time getting it right). Also keep in mind that this is called for every request, so it should perform really well otherwise your application will not perform.

PS: You may want to update to the latest Spring and Spring Security to avoid a number of security vulnerabilities that have been fixed.

So long as you have a way to obtain the user principal, user password (optional), and roles given a username this should be pretty straight forward. If you do not have a way of doing this, you cannot really implement the UserDetailsService.

Using rememberme will require a hit to your UserDetailsService every time a different session is established (i.e. every time a user is routed to a different Tomcat instance). Depending on the UserDetailsService implementation, this can (and likely will) be quite costly from a performance perspective. It is better to try to allow the container to manage the session rather than creating your own session management.

Yet again nothing I can do. All I can say is that as far as I know we are using apache, tomcat, with load balance and AJP. How it's all connected together is something I don't know (once I do know I'll edit this). Does anyone know of someone or some documentation that has done this decently?

You really are going to be better off setting up the cluster to use sticky sessions. There are likely other reasons you will be using session which will also be impacted by this problem. For example, if you use the PRG a common way to deal with passing messages to error pages is to use the session. Spring Security does this when dealing with errors (i.e. a failed login). That isn't to say you cannot work around this, but the more you work around vs use things the way they are intended the more difficult it will be.

If I were you and I absolutely could not use sticky sessions, I would look into writing a custom SecurityContextRepository. This would allow you to save/retrieve the SecurityContext using something other than session. I would really be cautious doing this because security is a difficult thing (even the experts have a difficult time getting it right). Also keep in mind that this is called for every request, so it should perform really well otherwise your application will not perform.

I knew this was not going to be a walk in the park, looks like I have my work cut out for me. Question is now is there anyone who might have some resources that could lead me to the right track. Especially with writing a custom SecurityContextRepository. I was thinking as well couldn't I try to use session cookies somehow? Or with the current way does that not seem possible?

Comment

They don't want to store sessions server side. Part of our security protocol. Nothing I can do about it.

Just because you are not using sticky sessions doesn't mean that is going to prohibit putting things in session. It may deter developers from using it (since it makes it effectively useless), but values can still be placed in the session. Also, I am curious why this would be a security measure. If your application needs a session (which it appears like it does to manage the user), then in all likely hood writing your own implementation to manage session will be less secure than something that has been around for a long time, well tested, used by many more users, etc.

Yet again nothing I can do. All I can say is that as far as I know we are using apache, tomcat, with load balance and AJP. How it's all connected together is something I don't know (once I do know I'll edit this). Does anyone know of someone or some documentation that has done this decently?

This is not really the best place to look for that information. I can tell you the tomcat docs have pretty good information on clustering. If you have trouble please consult their forums.

I was thinking as well couldn't I try to use session cookies somehow? Or with the current way does that not seem possible?

The session cookie is used in the default implementation, but that will not work with out using sticky sessions. Technically you could enable session replication so that each node recognizes the other's session, but without sticky sessions the replication would have to occur so frequently it would cause a significant impact on performance.