First8 staat voor vakmanschap. Al onze collega’s zijn een groot aanhanger van Open Source en in het bijzonder het Java-platform. Wij zijn gespecialiseerd in het pragmatisch ontwikkelen van bedrijfskritische Java toepassingen waarbij integratie van systemen, hoge eisen aan beveiliging en veel transacties een belangrijke rol spelen. Op deze pagina vind je onze blogs.

Using SwitchUser functionality in Spring

If you are developing a website with external users, those users might require support. For the people providing support, it can be quite convenient to be able to log in as a user and see the application through their eyes. In this blog post we’ll visit some of the components Spring 3 provides to handle this kind of feature.

Switching user

In our application, a user can log in and edit properties for a company he is authorised for. The application uses Spring Security for that. The switch-user functionality (or su in unix terminology) is provided by Spring as a filter (SwitchUserFilter) which can be configured in your application.xml as follows:

We specify our own UserDetailsService since we have a list of users maintained a non-standard source. The bean definition also specifies two url’s, the switch and exit url, as well as a parameter. With these, we have now defined that a simple GET to /backoffice/sudo?user=someuser logs you in as someuser. Of course, we don’t want everyone to be able to do this. Only “ADMIN” users should be allowed to use this feature, so we have to protect that URL using standard Spring Security rules:

Note that the reverse switchUser (sundo) is protected by the role of the target user, otherwise we would get a permission denied when trying to go back.

Auditing

Spring implements this feature by changing the Authentication in the SecurityContext. The administrators authentication token in the SecurityToken is replaced with a token representing the target user. The authentication token has some authorities (also known as grants, roles, permissions, authorizations or whatever name your favorite framework uses). Of course, one authority is the ROLE_USER since, well, you are now a plain user. But, that is not all. Since you are actually pretending to be that user, you have an additional authority: ROLE_PREVIOUS_ADMINISTRATOR. This authority is of a different type (normally it would be something like SimpleGrantedAuthority,  nothing more than a wrapper around a String). This authority is of type SwitchUserGrantedAuthority and allows us to discover the original user.

We can use this for audit logging purposes for example. In our web.xml we’ve defined a filter which adds context for log lines using MDC (mapped diagnostic context). Here we can add the logged in user (and the actual user behind it if somebody sudo’ed). So we define a filter:

And in that filter we add some context for the user:

You can now use these context properties in your logging framework, e.g. you can define a log4j console appender like this:

which could log something like this when an administrator is pretending to be a user:

Session cleanup

 A final thing to be aware of is that if an administrator switches to a user, he (or she) still keeps the same HttpSession. If the administrator switches regularly between users, some information might leak between sessions. In our example, users can switch between companies for whom they are authorized to do some work. By default no company is selected (currentCompanyId == null) and if they have selected a company, it is validated once, it is stored in a session scoped bean. From then on, it is assumed that that user has access to that company. So this is something that we don’t want to leak when an administrator switches users. The bean might look like this:

So we need to reset this bean whenever a user switch happens. For this, we can register an ApplicationListener that listens to switch user events:

Note: you might run into trouble here: the userAccountSession is, well, session scoped. So you might need run into an error like below:

This can be fixed by adding the RequestContextListener to web.xml which exposes the web layer’s request context to other layers:

With this, you should have a properly configured sudo functionality.

Read more: