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.

AnnouncementAnnouncement Module

Collapse

No announcement yet.

Forcing authenticated user to perform task before proceedingPage Title Module

Forcing authenticated user to perform task before proceeding

Jun 16th, 2005, 10:04 PM

Hi:

I've been trying to figure out how to do something using Acegi (0.8.2) and still it escapes me. The simplest case is that once a user successfully authenticates, I want to send them to a license agreement page. Upon accepting the agreement, they can access the rest of the application, otherwise they can't do much but logout.

The Authenticattion (principal) will maintain this state (persisted in db). I need a successful authentication to get the Authentication and I want to stymie any attempts to access anything but the license agreement. So, it does not make sense to try to do this with the authentication manager. I could throw an exception, and setup the properties (exception class to page) so the user is redirected to the license page, but then they are basically unauthenticated (context set to null). Once they agree, I don't want to have them authenticate again. Also, I don't want them entering some other URL to bypass the license page.

The SecurityEnforcementFilter looks like a good spot, but once again throwing an exception to the authentication manager, will null the context. The access decision manager looks like another hook, but throwning AccessDeniedException will result in a forbidden being returned. I'd rather have them sent to the license page.

I guess I want the Authentication to remain in the context, yet for each request, send them to the license page if they've not yet accepted it. I have a similar need for enforcing concurrent sessions, and give the user the ability to terminate another session (one where they forgot to logout in another office say), in order to proceed with the current one. Again, the user has authenticated, I just want to get in their face until they've made the decision to either terminate the other session, or decline to do so, and then be logged out of the current session.

Perhaps I have to make a new filter to add in the chain between the authentication filter and the security enforcement filter? Say, MakeUserDoTasksFilter or something, and in a similar manner have a provider manager invoke managers and direct the user according to any exceptions thrown (or URL returned). This way the user will remain authenticated, but not be able to roam freely.

Wouldn't it be easier if you assign them roles (or what Acegi called GrantedAuthority)? For example, registered users that have not accepted the license agreement will have a "registered" role/authority. Once they register, they are upgraded to have an "authorized" role/authority.

Then all you need to do is configure all "registered" users to go to the license agreement page if they try to access an authorized page.

Just an idea,
Ben

Comment

IMHO I don't think this is a security related solution, its an application one. The requirement is that the user must acccept the license aggreement before using any other portion of the application. All requests subsequent to login must enforce this rule. It appears to be a workflow related requirement.

Acegi will make sure the user logs in, so there are no issues there. The next step is to intercept each request to send the user to the license page if they have not done so. To keep it an application responsibility I think you have at least these possibilties

1. Create a new filter (as u suggested).
2. Do the check in the MVC. If you are using Spring, then create in the Controller. Perhaps create an abstract class with a pre-processing hook. If you are using Sruts, then the same idea, but with the Struts Action.
3. If you are using Struts, you can create your own RequestController and manage it from there. There's a pre-processing hook in there as well.
4. Create an AOP interceptor. This is another variation of #2.

In all cases, once the user has passed through the license page, its recorded in the database and recorded in the HTTP session. On subsequent requests, it checks the HTTP session flag. If its not there, it checks the DB. If its in the DB then place the flag in the session. You could tweak this a little to avoid repeated SQL calls when its not there on repeated attempts. Just my 2 cents

Comment

Thank you very much for the great suggestions. At this time, I will have read-only access to the role store, so I cannot modify a user's role after accepting the agreement. Also, the application at this time is a bit of a mishmash of legacy directly accessed JSPs, servlets plus some Spring HttpInvoker usage in the newer code.

It seems like some kind of application rules enforcement filter may be called for then. With it appearing after the AuthenticationProcessingFilter the rules filter will be able to easily access the Authentication object and HTTP session.

Borrowing the ProviderManager mechanism with its authentication managers, the rules filter can be easily configured to deal with today's problems as well as tomorrow's. In the same vein as the AbstractProcessingFilter's unsuccessfulAuthentication method, exception classes can be mapped to URLs for redirection.