To the best of my knowledge this can't be done using form-based authentication.
I think this is a real pain and is an oversight of the JAAS specification; there are loads of situations when you might want to control when the logon form appears (to always assume you want it displayed at the last minute is a bit restrictive). So if anyone knows any better please correct me!
Anyway, there seems a simple programmatic workaround to me: log the user on programmatically from a custom-written servlet; which doesn't post to j_security_check but manually captures a username / password pair and uses a LoginContext to log the user on. This means you've got some security coding to do but not much. You can then display this servlet whenever you want.
One solution is to use a JSP as an initial welcome page and create a dummy secured EJB. This initial JSP page will create an instance of this secured EJB. If the user has not been authenticated yet, the container, still configured with form-based, will bring up my custom logon page.
Don't if it works because I have not tried it yet. Anyone has any suggestions?
> ... and uses a LoginContext to log the user
> on. This means you've got some security coding to do
> but not much.
How exactly is this done? I mean using a LoginContext to log the user on?
Thanks for that - I see how it works now. Its probably worth mentioning that you have to contact the server's login module in order to kick off the declarative authentication mechanism. I'm guessing the way to do this would be to simply make a dummy ejb call.
you don't need to code the security calls yourself, or even reference a secured ejb. just secure your entire web app or just a welcome page or something. check out web.xml and jboss-web.xml for specifying roles, security-constraints, and security-realms.
then they get a login prompt as soon as they hit your first page. no dummy ejb's or logincontexts required.
just be sure not to secure your login page and any images/css/etc that it uses.
This is an excellent idea. Thanks!
In the case where one is using form-based authentication(j_security_check), is it tomcat which undertakes to perform the job of a ClientLoginModule?
If so, where does tomcat find out what client login modules to use? How does tomcat know whether or not to contact the server module?
I'm not sure I completely understand your question. But let me try to explain how form based authentication works.
First you specify all elements of your security realm in your config files : where tomcat/catalina can find the info about your users and their roles, the resources to be protected, the user roles that have access and your custom login and error pages. This is mainly done in web.xml, catalina server.xml and/or jboss auth.conf.
When a client requests a resource (page), catalina checks if it is protected. If the resource is protected, it checks if the user has an appropriate role and grants or denies access accordingly. When no user is logged in yet, catalina stores the request and returns your login page. The action of that page is j_security_check and catalina authenticates the user and retrieves the user's roles from the appropriate datasource. It then continues to process the original request.
What you call "the server module" is in fact a "valve" designed to check security before returning resources to the client. The valve is called for every request but of course the flow of the process depends on a user already being authenticated or not and having an appropriate role or not.
You can learn a lot more about this from the catalina source (mainly the packages authenticator and realm).
Hope this helps,
The way you describe form-based authentication is pretty much the way I understand it but let me see if I can be a bit clearer in what I'm struggling with.
My system: Tiles+Struts1.0, tomcat323+jboss241a, jdk131_01, linux.
I have setup form-based authentication as you you describe however with a slight difference. In my app I'd like the anonymous user (i.e. someone who has never registered or has simply chosen not to log in) to be able to receive 'anonymous' functionality - so he can find the site to be useful but wherever he goes he will be reminded of the benefits to registering as a member of the site. He only gets shown a login form when he specifically asks for one. I have set this up already and it is working.
Users who have registered will be able to login(from a direct link to the login form - i.e. they wont get any screens suddenly pop up unexpectedly) and gain access to their profile functionality. (registration process will include a choice of profile - for customized presentation purposes and general authorization.e.g. a logged-in user is a customer or a supplier. If they are a supplier they might be an agent or a direct supplier etc.)
Now we know that tomcat is able to log someone onto the site using the form-based authentication mechanism and once the user is logged on, we can write servlet code(I haven't even started trying to apply access restrictions to the ejbs. I'd like to leave that to one side for now.) to query the Subject and call methods like isCallerInRole(). But what if the user is anonymous. If the user has not logged in, we still want to apply logic which comes under the header of authorization. But tomcat will only return null when we say getUserPrincipal().
So in Struts and Tiles, I would love to be able to say :
(simplified for explanation purposes)
But we can't do that because an anonymous user does not belong to a role! (he is just a poor old null:-( )
If I understood the mechanics of the tomcat form-based authentication process, I might be able to create an elegent work-around to this problem. Maybe I could manually log an anonymous user on and assign him a role of say, 'anonymous'!
This is why I am trying to understand how tomcat logs a user in. Does it use the client/auth.conf? Does it use its own client module? Does it even need a clientside auth.conf module if there is no ejb communication involved? Does it communicate with the server's auth.conf login module?
These are the kind of questions which may sound silly to someone who already knows how it works but the info is not really easy to come by without devoting huge wads of time to going through the actual code its self.
Having said that I'm not looking for someone to write my application for me - just a few pointers at least to get me going.
A similar post was almost answered:
I have tried to manually log a user in(using your suggested method above, Wouter) but I must be missing something because a still get null from getUserPricipal().
Excuse the length of the message - hope you're still here:-)
Any further thoughts on the topic much anticipated!
The person who wrote the "almost answered" link you referenced was, as they suggested, incorrectly making the unauthenticatedIdentity=rolename.
They should have been setting
So set up a user with username of "nobody" in the database (or whatever) and the role "anonymous". Then set unauthenticatedIdentity=nobody. If you then secure your entire web site, but allow access to all users with the "anonymous" role for those areas they don't need to be logged in on to access.
I *think* this will work, but have never tried it, I'm afraid. Using this technique you may be forced to manually control when the logon page appears, because I'm not sure if Tomcat pops up the logon page when you access a *more* secured area than your current roles allow (you may just get a 403 Access Denied error). But by the sound of things you are doing this anyway.
Tomcat 4.0.1 uses the realm you specify in the jboss-web.xml file, and uses the corresponding domain as set up in the catalina/auth.conf. Sorry I can't help on the Tomcat 3.2 config. The jboss-web.xml has an entry something like:
Hope this helps more than confuses you. Sorry I couldn't take more time to be clearer.
I tried the authenticatedIdentity=nobody with 'nobody' being a principal id in the db and belonging to the 'user' role. I secured all access (except to the splash page which does the loginContext 'manual' login) under the 'user' role.
I'm sad to say it hasn't worked. I get User 'nobody' authenticated. when I do the manual login and then I call request.getUserPrincipal() which returns null.
I have even followed the loginContext instantiation with a dummy ejb call but alas - no cigar!
I'm not sure whether I should be duplicating whatever it is tomcat does for its j_security_check. I know tomcat is definately doing something to update the request with the principal and this is the part I'd like to know how to duplicate.
extract from ejb-jar.xml:
My realm is set up correctly - enough for form-based auth to work anyway:
as you suggested.