Jul 11th, 2005, 04:36 PM
ACEGI Security and Web Services
We are building an application that will consist of a rich Java client (Java WebStart) that calls web services (Apache Axis) implementing the bulk of the business logic. We are investigating ACEGI Security as one possible framework upon which to base our web services security.
The documentation seems to suggest using HTTP authentication (i.e. user and password passed in HTTP headers), but we wish to be compliant with WS-Security which passes user names and passwords in SOAP headers rather than HTTP headers. Also, there appears to be some reliance on an HTTP session. Our web services are stateless and we do not currently use HTTP sessions (which are per web service anyway in Axis), but we would like to avoid reauthenticating the user every time a web service is called if at all possible. We initially planned to do our own session management (of a sort) by generating a token when the user initially authenticates via some authenticate() web service and caching that token along with the username for comparison on subsequent web service calls. We also had plans to put some expiration period on the token to force reauthentication after some period of time (or possibly inactivity). But this was all prior to considering ACEGI and I'm now trying to evaluate what needs to change.
I have the following questions for starters.
1) How do I get the authentication token into the secure context? It looks like I can't use any of the provided implementations. Do we need to write our own SOAPProcessingFilter to extract the username and password from the SOAP header and set the Authentication token in the context?
2) How do I prevent the need to reauthenticate every time? Can I still use a sort of application provided session by rewriting my own filter that does something similar to what HttpSessionContextIntegrationFilter does (i.e. copy the context to and from the context holder at the start and end of each request)?
Assuming I'm on the right track on both of these, has anyone else done this already? Is any work under way or has any consideration been given to supporting sessionless web services and/or ws-security more directly in a later release? If I do need to 'roll my own', any idea how big the job might be? Thanks in advance.
Jul 12th, 2005, 11:20 AM
I am also involved in a Web Services project where we need to apply security. I'd be interested in responses to this too.
Jul 13th, 2005, 01:46 AM
Re: ACEGI Security and Web Services
Exactly. You need to extract the "credentials" out of somewhere, which is the role of an "authentication mechanism" in Acegi Security. All of our authentication mechanisms are implemented as a XXXXAuthenticationProcessingFilter, such as DigestAuthenticationProcessingFilter etc. So use them as a guide. All they have to do is construct an Authentication request object, pass it to an AuthenticationManager, if successful associate the returned Authentication with the ContextHolder, and if unsuccessful relaunch the AuthenticationEntryPoint or take some other appropriate action to inform the requestor that there was a problem.
Originally Posted by bbailey
Acegi Security does not require HttpSessions to be used. You can reauthenticate each time with say BASIC or Digest authentication and set HttpSessionContextIntegrationFilter.allowSessionCr eation = false.
Originally Posted by bbailey
If you wanted to use some other Map or whatever to store the Authentication associated with a given remote service, you are free to emulate the behaviour of HttpSessionContextIntegrationFilter.
Unfortunately I am not aware of anyone who has done this yet. If you get it working, please feel free to post your code and tests to JIRA and I'll be pleased to include it in CVS.
Jul 13th, 2005, 11:47 AM
Thanks, Ben, for your comments.
Just a few more thoughts that come out of discussions we've been having here on this topic. I'd be interested in any further comments anyone may have regarding the approaches we are exploring. Some of this is just me thinking aloud; my hope is that if I have flaws in my logic, someone will point them out to me.
The typical response to an authentication failure is to redirect the client to the authentication entry point (e.g. a login page). But I'm not certain that I know what that means exactly in the web services case since the client often won't be a browser capable of displaying the page to a user. And in the case of web services, I don't believe a redirect would be honored (i.e. the Axis client will expect a SOAP response of some sort).
It seems to me that what we really need is simply to return a SOAP fault message to the client indicating that access has been denied. Normally, this would be done by just raising an Axis fault within the web service or inside an Axis handler, but in this case, if we are doing the security via web filters, Axis won't even have been entered yet and raising any Axis fault won't have the desired effect. So we are thinking of just sending a canned SOAP fault message as the response rather than doing a redirect as is the case for the existing filters. Would this present any problems?
As a historical note, this failure case didn't present a problem before we considered using ACEGI Security because all of the extraction of the login and credentials, creation of the sessionid, etc. was taking place in Axis handlers rather than web filters. We could just raise AxisException in the handler and let Axis take care of generating the SOAP fault message.
This caused us to consider another possibility; that is, not use web filters but reproduce the same logic inside Axis handlers. However, my instincts tell me this is tantamount to writing a whole new type of interceptor since all of the authentication, authorization, run-as logic, etc. would have to be reimplemented to work in the Axis handler case. This seems too much for an ACEGI newbie like myself to consider. Any thoughts on whether this would be possible and how much work it might involve?
Finally, we considered whether method interception might be used, but the AOP Alliance method interceptor approach seems a poor fit since it requires that the objects being secured be instantiated and proxied by Spring. In our case, the objects in question (the implementaiton classes for the web services) are loaded by Axis; we don't have direct control over when or how they are instantiated. One possibility would be to extract the business logic into beans that are instantiated by Spring and have the web service implementation classes simply delegate to these beans; the security could then be applied to the beans rather than the web service classes. But this is probably a lot of rework for us so we'd prefer not to go this route unless there isn't any other option.
The AspectJ interceptor was also discussed briefly as a way of working around our lack of control of when the web services implementation classes get loaded since it theoretically should not care how the objects get instantiated. But as a newbie, I'm not yet comfortable enough with AspectJ in combination with Spring/ACEGI to fully digest how this might work. Any thoughts on whether this might be an appropriate avenue to investigate?
I know this is a lot so I'll stop. I'm not expecting detailed answers to all the problems I've posed. Just hoping some other folks can chime in on where I got it right and wrong and suggest any other options I may not have considered. Thanks in advance for any help you can provide.
Jul 23rd, 2005, 05:50 AM
I have not attempted to implement a SOAP handler with Acegi Security, but your understanding of the inner workings of Acegi Security is good from the background and detail of your questions.
If you stayed with the SecuityEnforcementFilter and using filters as an authentication mechanism, a custom AuthenticationEntryPoint could probably send back a SOAP reply indicating the error. Although, in consideration of the remainder of your requirements, it would probably be easiest to hook more tightly into Axis itself. There are two real requirements:
1. For an Axis handler to build an Authentication object and put it in the SecurityContextHolder (ContextHolder in 0.8.3 and below). This basically means Axis must "act as an authentication mechanism".
2. Find a way for an Axis handler to stop a request, call AbstractSecurityInterceptor.beforeInvocation(), then proceed with the request, and then AbstractSecurityInterceptor.afterInvocation(). What I am essentially proposing is you write your own interceptor. It's very easy if you have a way of stopping the handling of the request mid-stream, checking security, then proceeding.
This week I'm off to sunny Brisbane on a consulting gig where I need to look at SOAP security in depth. So I might be in a position to provide more concrete thoughts in a few more days. Did you have a particular need to use Axis, or are you open to alternative SOAP server implementations?
Dec 22nd, 2005, 03:11 PM
This is almost exactly the same situation I’m encountering. I will be using SOAP BASIC authentication in my service. I think this is what I need to do, please correct me if your experiences are different. Note that I'm an ACEGI noob, but I would like to resuse as much of the existing framework as I can.
1. Add a handler to AXIS that authenticates with ACEGI security using SOAP BASIC and throws a SOAP exception in the event of a failure.
2. This is where it gets tricky for me. We will publish a standard service, but each user could connect to different back end logic. As a result, I was thinking I could subclass UserDetails and add a “Business Provider”. Once the user is authenticated, I can then pull the existing business provider from their details.
3. This is where I’m most confused. All of the different business logic must implement the same interface so calling the provider is not an issue. How can I retrieve the name of the business provider in the web service servlet? Note that I am extending Spring’s org.springframework.remoting.jaxrpc..ServletEndpoi ntSupport in my web service servlet.
Any guidance/advice would be greatly appreciated