my dog learned polymorphism*
The moose likes Tomcat and the fly likes pre or post filter j_security_check Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Products » Tomcat
Bookmark "pre or post filter j_security_check" Watch "pre or post filter j_security_check" New topic
Author

pre or post filter j_security_check

David Sheltby
Ranch Hand

Joined: Oct 19, 2011
Posts: 34
Hi, I need to execute some code either before or after authentication. I've read several posts online from people trying to get a filter working for j_security_check url's, but I haven't seen anyone achieve it with Tomcat; results seems to be container specific. The posts are all a few years old, so first I wanted to see if anything has changed in a few years and if it is in fact possible to capture a request for j_security_check with Tomcat 6?

If not (and that stills seems to be the case), then the alternative that I tried is this: POST the login form to a filter (or servlet) which will do any pre-authentication work, forward to j_security_check, then execute any post-authentication code. I can get this to work only if I use Response.sendRedirect("j_security_check?j_username="+username+"&j_password="+password")... forwarding to j_security_check does not trigger authentication. I'm not to keen on this approach since it exposes the username and password in the query string. Is there another approach?

thanks
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15960
    
  19

j_security_check is not an application function. It's a function of the J2EE security standard, and is automatically performed by the server - whether that server is Tomcat or not.

It is also not a URL in its own right. It will only be processed correctly in cases where the server determined that there was a need to authenticate a user.

To actually hook application code into the process, you'd have to break the J2EE security process and modify Tomcat itself. In plain English, you'd be making Tomcat an integral part of the application, rather than its proper role as container for applications.

The question is - what do you actually want to do in business terms? Rather than assume a particular technical solution, what would hooking into the authentication process actually accomplish for you? There are a number of tricks I can recommend - many of which are more or less independent of whether you're running Tomcat or WebSphere, but I'd need to know what you want to do.


Customer surveys are for companies who didn't pay proper attention to begin with.
David Sheltby
Ranch Hand

Joined: Oct 19, 2011
Posts: 34
Hi,

For the moment, I just need to look up a value in the database for the account that was just authenticated - an account activation status. I don't want to go down the road of checking this status for each request after being authenticated, so I wanted to tack it on to post-authentication process.

thanks for the help.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15960
    
  19

The normal approach for this problem is to make the account status be part of the authentication process. That's assuming the simple case, where you want to keep inactive accounts on file, but forbid them from doing a login. The clean way to do that is to make the status query part of the query. In SQL terms, that would mean that instead of the standard authentication test:


You'd add an extra selection:


Unfortunately, I don't think that any of the Tomcat stock database-based Realms offers this option, but fortunately, it's not very difficult to subclass one of them and do your own query. The LDAP Realm is more configurable in that regard, if you're using an LDAP server such as MS Active Directory for authentication.

The Realm validate() method, which is what does the authentication is a simple boolean go/no-go function and for the SQL above, it should return "true" if the query returns 1 and "false" if the query returns 0. Any other number would indicate that the database isn't properly set up, since a userid/password combination should be unique.

One thing which you may notice is that there's no way to return a "User Account Disabled" message. That's intentional. Good security never volunteers anything. If the user can't login, they should be contacting a security administrator. If that's too restrictive, there are ways to fake it, but they essentially involve allowing the login while forbidding any actual requests, and that's a potential security risk.

What is there's user information available at login that you'd like to keep available without going back to a database for each subsequent request? Say, for example, that your account status encompasses more states than just active/inactive (this isn't the same thing as security roles, however).

There are 2 ways to handle that. One is to sense login in a servlet filter and fetch the data when you detect the transition to logged-in state. The other is more devious and takes advantage of the fact that the authentication process of a Realm constructs an object that implements the UserPrincipal interface. It's therefore possible to piggyback additional account information on that object and cast the results of the request.getUserPrincipal() method to access them. If you do that, however, bear in mind that attempts to use any other Realm implementation will result in a ClassCastException and plan accordingly.
David Sheltby
Ranch Hand

Joined: Oct 19, 2011
Posts: 34
I think creating my own subclassed Realm sounds like a good approach. I'll give it a try.

Thanks!
David Sheltby
Ranch Hand

Joined: Oct 19, 2011
Posts: 34
Hi again,

A follow-up to this. I've subclassed the DataSourceRealm and overridden the authenticate method to suit our needs... works perfectly. However I also need to set a couple of session variables upon login and if possible I'd like to do this in the authenticate method. Is this possible? I can't find any way to access the session. At what point does the principal get cached/placed in the request?

If, as you state in your previous post I have to do something like detect a transition to a logged-in state, can you clarify this? What do mean by this?

thanks!
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15960
    
  19

The HttpSession and the UserPrincipal objects have no official relationship to each other. So don't expect to be able to access the HttpSession when authenticating. It may not even have been created yet, and the environment within the authenticate() method is not a good place to try and create one manually.

The HttpSession (as defined by its public interface) is an application-level object, whereas the UserPrincipal is a server-level object. There isn't any direct interrelationship between them and there isn't any event that gets fired at login time - in part because authenticate() isn't literally "login". If the user is running in a single-signon environment, login may have happened in some other app (or even in some other server).

All is not lost, however. A user who is not logged in will not have a userPrincipal in their HttpServletRequest object - it will be null. When the user has been logged in, however, that will change. To exploit that fact, create a ServletFilter and register it in the application. The filter checks the HttpSession object, and looks for a suitable user-defined token. If the token isn't found or the session isn't found, then the user isn't logged in. If the token is found in the session, the user is processing in a post-login request. However, if the token is null and the UserPrincipal is NOT null then the user has just logged in! Create the token and store it in the HttpSession (create the session, if required). Also create/store the other objects that you mentioned. viola!. You now have all your goodies. Pass the request on through the chain to be processed in the usual way.
David Sheltby
Ranch Hand

Joined: Oct 19, 2011
Posts: 34
So I've implemented all of the above and I have another requirement to complete which I need some input on. Is it possible to create my own UserPrincipal and add it to the "server" (not sure exactly where the UserPrincipal officially resides) to grant access to a specific type of user without them having to manually login - essentially logging in transparently from another system?

I was first thinking of creating an auto submit form which submitted to j_security_check to authenticate, but the way Tomcat works is for the user to first request a protected resource, and only then does the server complete authentication and redirects after if successful. Not sure how to get around this.

thanks!!
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15960
    
  19

Yes, although you don't have to do all that work.

The UserPrincipal is constructed by the Realm. Realms are plug-in security managers, and what you need is a Realm that supports Single Signon, a/k/a SSO. CAS is one such Realm implementation.

SSO works on the principle that if you log into any participant in the SSO Realm, you're considered logged into all of them.
David Sheltby
Ranch Hand

Joined: Oct 19, 2011
Posts: 34
I'm not sure SSO would be a solution. The other system requires a completely different login solution unrelated to the one I'm working on (and vice versa). I'm just creating a kind of internal back-door for these users, passing some user credentials from one system and to another - the major roadblock is adding the UserPrincipal and then redirecting to appropriate page after this transparent authentication takes place. Not sure how to do it without altering whats in place already.


Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15960
    
  19

"Transparently logging in from another system" (or application) is what SSO is all about.

Don't get too in love with "login". And by the way, "j_security_check" is neither a URL not a function, but more on that some other time.

The J2EE Container Managed Security infrastructure is about 2 things: authentication and authorization. Authorization involves role-checking after authentication, and I won't go into that for the moment. Login is just one means to an end: authentication.

Authentication is what's used to securely establish who the user is. This can be done via a login process, but if the Realm has access to an out-of-band authenticator (such as an SSO authority), then login isn't required. Conversely, if the user has no existing session with an OOB authenticator, the Tomcat server will check the webapp's web.xml to see what authentication method to use, and in the case of form-based authentication, the form definitions for login and loginfail, which Tomcat will then serve up and process (the application not only cannot control this, it isn't even aware it happened).

In the case of SSO, a little more help is required. There's no method in the standard Realm interface to check for "already logged in", so Tomcat supports an SSO Valve component that is part of the request process. This valve interfaces with the SSO security manager so that the login process won't be invoked if the user is already authenticated within the SSO system.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: pre or post filter j_security_check
 
Similar Threads
is there away of getting better control over j_security_check
Configuration of filter problem
j_security_check filter
Automatic authentication j_security_check
Redirect to original URL after login