views:

3779

answers:

5

hello,

I'm trying to integrate Spring Security in my web application. It seems pretty easy to do as long as you integrate the whole process of authentication and authorization.

However, both authentication and authorization seem so coupled that it's being very time-consuming for me to understand how I could split these processes, and get authentication independently of authorization.

The authentication process is external to our system (based on single sign-on) and this cannot be modified. Nevertheless, once the user succeeds this process, it's loaded in the session, including roles.

What we are trying to achieve is to make use of this information for the authorization process of Spring Security, that's to say, to force it to get the roles from the user session instead of picking it up through the authentication-provider.

is there any way to achieve this ?

thanks!

+2  A: 

Yes, it's possible. Spring Security (like most of the rest of Spring) is interface-driven so that you can plug in your own implementations selectively for different parts of the framework.

Update: Spring's authorisation and authentication mechanisms work together - the authentication mechanism will authenticate the user and insert various GrantedAuthority instances in the security context. These will then be checked by the authorisation machinery to allow/disallow certain operations.

Use nont's answer for the details on how to use pre-existing authentication. The details of how you get the details from your session (e.g. roles ) will of course depend on your specific setup. But if you put in the GrantedAuthority instances derived from the roles pre-populated in your session by your SSO system, you will be able to use them in your authorisation logic.

From the reference documentation (slightly edited, with my emphasis):

You can (and many users do) write their own filters or MVC controllers to provide interoperability with authentication systems that are not based on Spring Security. For example, you might be using Container Managed Authentication which makes the current user available from a ThreadLocal or JNDI location. Or you might work for a company that has a legacy proprietary authentication system, which is a corporate "standard" over which you have little control. In such situations it's quite easy to get Spring Security to work, and still provide authorization capabilities. All you need to do is write a filter (or equivalent) that reads the third-party user information from a location, build an Spring Security-specific Authentication object, and put it onto the SecurityContextHolder. It's quite easy to do this, and it is a fully-supported integration approach.

Vinay Sajip
but is it necessary to configure an AuthenticationProvider ?
markitus82
Yes but that doesn't have to be a different object then the authorization provider: You can create a class that implements both (since your SSO system seems to give you both as well).
Aaron Digulla
the thing is that the login form (authentication ) in my app is carried out by external systems. all I have is the user session, and user is already authenticated. I'd like to know how I could get the userId and roles from the session in order to use Spring Authorization.
markitus82
You have to ask the userid and roles to the external system that did the athentication.
rodrigoap
+1  A: 

Hi. The server that handles the authentication should redirect the user to the application passing to it some kind of key (a token in CAS SSO). Then the application use the key to ask to the authentication server the username and roles associated. With this info create a security context that is passed to the authorization manager. This is a very simplified version of a SSO login workflow.
Take a look to CAS SSO and CAS 2 Architecture.
Tell me if you need more information.

rodrigoap
+4  A: 

If your authentication is already done using an SSO service, then you should use one of spring security's pre-authentication filters. Then you can specify a UserDetails service (possibly custom) that will use the pre-authenticated user principle to populate the GrantedAuthority's

SpringSecurity includes several pre-authentication filters including J2eePreAuthenticatedProcessingFilter and RequestHeaderPreAuthenticatedProcessingFilter. If you can't find one that works for you, its also possible, and not that hard to write your own, provided you know where in the request your SSO implementation stuffs the data. (That depends on the implementation of course.)

Just implement the Filter interface and do something like this in the doFilter method:

public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws IOException, ServletException {

     HttpServletRequest req = (HttpServletRequest) request; //principal is set in here as a header or parameter. you need to find out what its named to extract it

     if (SecurityContextHolder.getContext().getAuthentication() == null) {
      Authentication auth = doAuthentication(req); //in here, get your principal, and populate the auth object with the right authorities
      SecurityContextHolder.getContext().setAuthentication(auth);
     }
     chain.doFilter(request, response);
    }
nont
hi nont, i've been working on this. Your answer is very helpful, although now I have to postpone this issue for a few days. I'll be back to it and let you know how things go. thx!
markitus82
your welcome. good luck!
nont
+1  A: 

we have had the same requirement where we had to use spring security for authorization purpose only. We were using Siteminder for authentication. You can find more details on how to use authorization part of spring security not authentication here at http://codersatwork.wordpress.com/2010/02/13/use-spring-security-for-authorization-only-not-for-authentication/

I have also added source code and test cases at http://code.google.com/p/spring-security-with-authorization-only/source/browse/

Saurabh
A: 

I am trying to understand CAS authentication with our own Authorization and was getting confused since the User object in Spring Security always expects the password to be filled in and we don't care about that in our scenario. After reading Surabh's post, it seems that the trick is to return a custom User object without the password filled in. I will try that out and see if it works in my case. Hopefully no other code in the chain will be expecting the Password in the User object.

SinusRhythm