After reading the JBoss book we purchased and the quick start guide, I've found that the ClientLoginModule doesn't actually authenticate anything. From the book:
"Note that this login module does not perform any authentication. It merely copies the login information provided to it into the JBoss server EJB invocation layer for subsequent authentication on the server."
I checked the source code and there is no jndi lookups going on, and according to the above quote, I'm assuming the ClientLoginModule doesn't access any server. To the best of my knowledge when an EJB remote interface is looked up from JNDI sometime later, there is something that "plugs in" the previously collected ClientLoginModule data into the server when calling the ejb methods (which is then intercepted by the SecurityInterceptor). Then the server actually executes the DatabaseServerLoginModule (or other, depending on your authentication store) using the information that was stored on the standalone client during initial execution of the ClientLoginModule. Since the DatabaseServerLoginModule is executed for every EJB method call declared to be secure, an authentication cache can be maintained to increase performance to prevent redundant authentications.
Am I correct in my assumptions? I don't believe the books are too clear on this subject.
And, if I'm assuming correctly, this means that there is no "instantaneous" authentication of a user from a standalone client. They are only "truly" authenticated when executing an ejb interface method (and they are authenticated every time they execute a method, unless using the cache).
Now, keeping the above information in the back of your mind, this is what I initially wanted to accomplish:
A standalone client is started, and the first thing they see is a login screen. Upon entering a username and password, and clicking enter or submit (or some other swing button), they should be told immediately if the username is valid, or if the password is incorrect for that username, or if their password has expired (and the gui subsequently redirects them to a password update page or something).
Now, according to the information on the ClientLoginModule, this would not be possible, since it doens't talk to the server to determine if the username is correct, etc.
So, is the best solution to create a "LoginManagerBean" EJB implementation that has methods that would tell me this information? Then the standalone client code would do a jndi lookup on this bean and execute all the methods it needs to determine that the user has authenticated properly. Finally, the ClientLoginModule would be executed with the username/password just authenticated. This would ensure calls to secure ejb methods on the server would operate as specified in the manual (ClientLoginModule -> SecurityInterceptor -> DatabaseServerLoginModule).
Can anyone verify if this is an optimal solution?
Thanks so much in advance for any replies,
> later, there is something that "plugs in" the
> previously collected ClientLoginModule data into the
> server when calling the ejb methods (which is then
> intercepted by the SecurityInterceptor).
> Am I correct in my assumptions?
Yes, this is correct. The thing that "plugs in" the security credentials is the ejb stub. It adds this info to the invocation (payload) on each remote ejb call.
> And, if I'm assuming correctly, this means that there
> is no "instantaneous" authentication of a user from a
> standalone client. They are only "truly"
> authenticated when executing an ejb interface method
> (and they are authenticated every time they execute a
> method, unless using the cache).
Again, this is correct.
> So, is the best solution to create a
> "LoginManagerBean" EJB implementation that has
> methods that would tell me this information?
Yep, this is the way to do it.
You can even simplify this by adding a security constraint to this bean, and doing a jaas login on the client upon (before) calling this bean. If you get a security exception, you know that the username/password was not correct. If the call returns succesfully, the user was authenticated succesfully. Consequently, the LoginManagerBean only needs one method, that does nothing ;-)
Thanks so much for clarifying, I sincerely appreciate it.
I have a slight variation on this scenario...
I have the exact same situation except that I have multiple threads running in the client, each potentially with a different user/password.
I'd like to know if the ClientLoginModule is capable of handling this situation. Can I login using JAAS/ClientLoginModule from within different threads of the same client JVM? If so, how does this work? With ThreadLocal or InheritableThreadLocal variables, perhaps?
I do not think the LoginContext is threadsafe, meaning you should have an instance of it per client thread that needs to login. By doing this, you guarantee each client thread its own "login scope".
Since the authentication information is copied into the EJB stub when the stub is created (i.e. via a remote or local Home lookup) and sent for every single method call to the EJB, you have to associate that stub instance with the same client thread that created it.
That is, for a thread that calls LoginContext.login() and then gets a remote/local handle to an ejb, the authentication information associated with that login call will be forever tied to the EJB remote stub returned from a lookup. That means, no matter what thread accesses that stub, the auth information associated with the stub when it was created won't change.
Any JBoss internal developers want to clarify/refute?
I had to solve the same problem (one JVM and lot lot dif. clients).
The first point is auth.conf configuration.
// jBoss LoginModule
The second one is running EJB method as ruquired Login Subject.
do this : Subject.doAs(your_login_subject, proxy); where proxy si you class that implements java.security.PrivilegedExceptionAction or java.security.PrivilegedAction (see api doc about these interfaces).
It works OK. I have still only one problem: I'm not able to serialize created Subject.