> The thing that I realized is that once someone
> authenticates, I don't know how to programatically
> determine who they are in order to generate a dynamic
> page for them!
By the ejb specification, your ejb has access to the user who created it and the roles associated to this user, through the SessionContext (which gets passed to the bean upon creation), see
If you need more attributes, or if you need to use this information outside of an ejb, you will need to create an own class, which you could return in an additional method of your ejb (or create a new ejb dedicated to providing an instance of "user configuration")
Thanks jwkaltz for the post. Interesting, but thats EJB stuff. I think my original post is a bit unclear, so let me try to explain better.
Here's what I want to happen:
1) User tries to access a restricted page
2) JBoss/JAAS realizes that the user has not logged in, and moves to the form based authentication page.
3) The user logs in
4) JBoss/JAAS authenticates against the directory. Roles _AND_OTHER_USER_INFORMATION_ are pulled and put into a Session object.
5) Jetty serves the restricted page, now that the user has authenticated.
6) The page, a JSP, uses the information in the Session to generate dynamic content.
So I guess its really just #4 that I don't know how to do.
Right, if you have more user information than just id and role, you will need in any case to define a class for this and provide a mechanism to retrieve this info. I don't know of any "standard" way of doing this in J2EE.
I see 2 solutions:
- either you use a custom form, which posts the login information to your own handler. In this you can do anything you want, such as authenticate, get additional attributes and store them in the session. This is what I did.
- use the built-in mechanisms for authorization, but then provide an additional EJB for retrieving additional user information at any time. Your JSP can then call this to get the info it needs.
I hope that makes sense.
I think my last post can be ignored. After some more reading, I think what I really want is to be able to put custom properties on the Principal. These properties will be stored in the same place as username and roles (directory server). Is this possible?
We are currently doing this with MS Site Server, and would like to do it in Java.
If we can't do this, we are forced to do something silly like take the username from getRemoteUser() and make a trip to the database to determine that user's userID, or Zip Code, or whatever data we will be using to generate the pages.
haha thanks for the response, I was posting more info while you were posting too :)
thanks again! you answered my question (even though I still wish there was a better way!)
hey Wolfgang would you mind sharing the source to that custom authentication code you wrote?
Well I'm afraid the source code doesn't really apply to your case: we use Cocoon (instead of JSPs). But I'll try to explain what's going on:
what happens in Cocoon is, you match requests to "pipelines". In this pipeline you commonly do the following: execute some Java code (called Action), process an XSP (xml file combined with Java, sort of like JSP), then an XSL to render the GUI (HTML, PDF, or whatever).
So our login form posts to an URL "login". This is matched to a pipeline. So first it executes a Java class, say LoginAction : this does the Jaas Client-side login, then attempts to create an EJB called EJBUserInfo and call its method getUserInfo(), which serves two purposes:
- authenticate the user
- retrieve an object of type UserInfo, which contains whatever attributes you have about the user, which are stored wherever (in my case, LDAP).
- if this is OK, it creates an Http Session, and stores the UserInfo in the HttpSession. If not, the error will get an error page (or the login page again, with an error note).
All other requests are matched to pipelines, which first have an action, say "SessionCheck", which checks if an Http session exists for this request, and if there is a UserInfo in it. If there is, processing continues, and the XSP (or JSP) has access to the user attributes. If not, there is a redirect to the login page.
Of course I put all the session getting and checking stuff into framework components, so that the application itself has very little code about this (just one line actually).
Note that doing this means there are no automatic permission mechanisms on the servlet-side of your application, only on your EJB side. But this makes sense for us, because all access to business data is strictly via EJB. The servlet side only serves HTML, pictures, etc.
I hope that makes sufficient sense. It would be difficult to paste together relevant code, because it's in many different places (html, cocoon Java actions, XSP, framework ...). If it sounds complicated, don't be mislead: it's actually not complicated, especially since the servlet API provides a very easy way to check for HttpSession and to write attributes in the HttpSession. The only trick part is to be careful not to create session when you don't want to :
you should always call request.getSession(false), when you just want to check if there is an active session. Only call request.getSession(true) when you checked there is no session, and you want to create one.
(I think the servlet API should be clearer about this issue, creating sessions should not be taken lightly, it shouldn't just happen as side-effect)
Thanks for this. I understand most of what is going on but I have two questions:
1) When you say that LoginAction performs the JAAS login, do you mean by using the ClientLoginModule, or something similar?
2) Why are you authenticating separately at the web tier and ejb tier?
Also, what do you think of this approach:
What if I modify the LDAPLoginModule to return a second group of principals which are custom attributes for the user, and then retrieve these from the HTTPServletRequest (which is where the subject goes in JAAS right?) and use them to create the session object?
ion performs the JAAS
> login, do you mean by using the ClientLoginModule, or
> something similar?
exactly, just the JBoss client module, so that username & password get "bound" for the subsequent JBoss call.
> 2) Why are you authenticating separately at the web
> tier and ejb tier?
Actually I'm not authenticating in the web tier. The login action makes a call to a (secured) EJB. This will trigger authentication in the ejb tier. If that fails, a remote exception will occur (and the client should then figure out it's actually a security error, due to wrong password or whatever).
> Also, what do you think of this approach:
> What if I modify the LDAPLoginModule to return a
> second group of principals which are custom
> attributes for the user, and then retrieve these from
> the HTTPServletRequest (which is where the subject
> goes in JAAS right?) and use them to create the
> session object?
Yeah trying to work with the principals is the other approach, but I haven't played around with that. Do note that the HttpServletRequest actually has nothing to do with JAAS. JBoss probably uses it if you use JBoss' default authentication mechanims, but if you do it differently you will have to handle it yourself.
To sum it up, in my case I wanted to have a clear, physical separation between the web-tier and the ejb-tier. This means I'm not using an embedded servlet container, but a standalone one. Therefore I need (and want) to handle to authentication form and the HttpSession stuff myself.
To me this is a major reason to use JBoss, that I can do this. Basically I look at JBoss as our business service only, having nothing to do with servlets (in that sense, it's my CORBA Ersatz)
In products like Weblogic I'm not sure it's even possible to do that, because of their proprietary protocols between servlets and ejbs.
But of course the other, more integrated, approach may be more suitable for your purposes.
No, I think what you are saying is exactly what I need to be doing.
Just one more question:
When you handle authentication yourself, can you still have declarative authorization? If so, where do you store the Subject so that it travels around on requests and method invocations?
I have a similar question. Here's my theory, after thinking about it for a while:
There's not really any way to connect Web info (i.e. HttpSession data) to JAAS info. So what I was thinking is the following:
1. Create an MBean that stores info based on the username. Password, whatever that the HTTP Servlet API doesn't provide.
2. Override LDAPLoginModule and put the info into that MBean.
3. In your servlet(s) grab the MBean and get the extra user info out of the MBean.
This seems to be the easiest way to do it, that also keeps things nicely decoupled.
> When you handle authentication yourself, can you
> still have declarative authorization? If so, where
> do you store the Subject so that it travels around on
> requests and method invocations?
We're just talking about the web-tier side here, right ?
I'm not sure how to work out declarative stuff by yourself, but it must be possible (since JBoss is doing it). Myself I have no requirement for declarative stuff on the servlet side. For the rest (i.e. calls to the ejb tier), the credentials are rebound through the ClientLoginModule, so on the ejb side, everything is as usual.
...just my two-penneth...
Is it not possible to write a ServerLoginModule that creates a MyPrincipal (instead of SimplePrincipal) with the extra info in it. Then access this from both the Web and EJB tiers using request.getUserPrincipal() and xxxContext.getCallerPrincipal() ?
Are you allowed to get the Subject from the Thread and access the Principals (Groups) directly? If you are, then you could add your own Group (like Roles/CallerPrincipal) and store information there?
....just ideas, I have not looked into it!
There was some talk of something like this on here recently, but I was never able to get anything but a SimplePrinciple back. If anyone has been able to do this, please let me know!