PDA

View Full Version : Web Services programatic authentication


brodyaga
Sep 26th, 2004, 01:29 PM
We need to implement a secured web service, without passing credentials in every function call.

We expose the login function via web service.
It's implementation puts Authentication Object into the session

_endPointContext.getHttpSession().setAttribute(Htt pSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTIC ATION_KEY, authResult);

But in subsequent calls to web service we notice that the attribute value is missing from the session .(The key is still there).

During debuging session I noticed that it get removed by the filter.
After expirementing with the filter configuration we have discovered the minimum config that allows to reproduce it

<filter>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-class>net.sf.acegisecurity.ui.AutoIntegrationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

The question is why is the value removed from the session and how it can be avoided.
Thanks.

Ben Alex
Sep 26th, 2004, 05:13 PM
AutoIntegrationFilter, which usually delegates to HttpSessionIntegrationFilter, is responsible for:

1. Reading the HttpSession attribute
2. Writing it (the Authentication) to the ContextHolder
3. Proceeding with the filter chain
4. Reading the ContextHolder for the Authentication
5. Writing the Authentication to the HttpSession

During step 3 all classes interfacing with security should be doing so via the ContextHolder. In particular, AbstractSecurityInterceptor will re-validate any Authentication, refreshing GrantedAuthority[]s etc. We need to write it back to the HttpSession in step 5 because sometimes an AuthenticationProvider returns an Authentication that is fundamentally different from the original Authentication (eg the CasAuthenticationProvider).

Regarding your usage, I'd recommend you to use the standard web services pattern with Acegi Security instead:

- Present username and password with each request via the HTTP BASIC header
- If you've got a login form on the client and want to check the credentials are correct before setting all the client proxies with a correct username/password (for BASIC authentication), use the net.sf.acegisecurity.providers.rcp (there's also a class in Spring Rich which automates the setting up of the client proxies: org.springframework.richclient.security.RemotingSe curityConfigurer)

One bonus of this approach, aside from overcoming the problem you mentioned and using code maintained as part of the Acegi Security project, is that you need not worry about HttpSession maintenance across web services calls. The recommended approach is also highly efficient, as the authentication-related database hit each separate web services call may require is avoided via the UserCache used by DaoAuthenticationProvider (I'm assuming you're using DaoAuthenticationProvider).

brodyaga
Sep 27th, 2004, 03:38 AM
Thank you for your reply.

I'm still not clear about a few things.

I understand that you have to rewrite the object in the session
but it still doesn't explain why we get null instead of the valid object.


The other approach you've suggested will also require rewrite of our client code.
We have several clients on different platforms .Net and C++ so we'd
like to avoid it if we can.

So if you have other ideas or explanation for this I'd be glad to hear it.
Thanks.

Ben Alex
Sep 28th, 2004, 03:19 AM
Let me try to understand. You're writing an Authentication object directly to the HttpSession attribute keyed on HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHEN TICATION_KEY, but it gets set back to null by AutoIntegrationFilter at the end of each request?

That's the expected behaviour, as per my earlier response.

After re-reading your first post, the way I'd suggest you approach it is your "login" servlet sets the ContextHolder, not the HttpSession attribute. Then, as the "login" servlet is run within the filter chain of AutoIntegrationFilter, at the end of the AutoIntegrationFilter execution the ContextHolder contents will be copied to the appropriate HttpSession attribute. AFAICS it's a simple matter of you're setting the target location (HttpSession) when you should set the source location (ContextHolder), and then as expected the target gets overwritten with the source at the end of the filter chain.