I found out what was happening, sort of: the thread that's creating my InitialContext just silently dies. I don't get it. The thread itself collapses. I put:
InitialSystem.out.println("start"); Context context = new InitialContext(properties); System.out.println("done.");
I see the "start" but not the "done". The thread just ends. I even replaced the "done" with System.exit(1) and that doesn't get called.
This is a bug in Java itself. A thread should not just die silently like that. But aside from that I'm mystified about what to do here.
And I found out the problem: The thread died because some jar wasn't in the path. This is bad for a thread to die silently, and it is a bug in Java, but oh well, I got that fixed.
Now I have the whole thing working as long as the password is correct for the login. This is big progress. But when the password is incorrect, I get:
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at $Proxy0.time(Unknown Source) at mypackage.CLIConnectivityTest.authorizedTest(CLIConnectivityTest.java:59) at mypackage.CLIConnectivityTest.main(CLIConnectivityTest.java:70) Caused by: java.lang.ClassNotFoundException: [Ljava.lang.StackTraceElement; at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) .............
How should my code handle this? Should I really catch UndeclaredThorwableExceptions all over the place? Surely there must be a more specific "you are not authorized" type of exception that could be thrown?
This system is madenning. Who could write a whole security infrastructure but not provide a way for a user to do a simple username / password login like people have been using for the past several decades? All I want is to be able to log in and use JNDI to look up remote objects, but if the password was incorrect it should have some documented result when I call lookup. Instead it throws an undocumented exception. Is this stuff in production use anywhere? What else is needed to get it to work?
Ok, now I am finding out more: it seems like the security check doesn't happen until a secured method is invoked, and if the security check fails, it just throws an exception. This seems ridiculous, but that's what I'm finding in docs like this:
Could this possibly be correct? There's no method to just log in, but I have to invoke some method and look for an undocumented exception?
My conclusion so far:
To do a login, first create an InitialContext using a plain old org.jnp.interfaces.NamingContextFactory as the initial context factory. On the server side, have a bean called "LoginCheck" or something, which takes a username and password as args, and returns boolean. On the client side, if that bean returns true, THEN it is time to create another InitalContext but this time using a JndiLoginInitialContextFactory, storing username and password credentials in it. Then everything is good to go.
If this really is the only way to do it, that is retarded, and it's probably the fault of JAAS. No matter how powerful the thing is, if it doesn't provide a reasonably good way for clients to be able to log in and display back to the user, "your password was incorrect", the whole thing is junk. Yes it can be used, and I like the fact that I can put annotations on my beans to enforce roles on them, but how hard could it be to get this thing right?
And looking through the examples, it does indeed look like the "right" thing to do is to just set up the InitialContext, not knowing if the password is correct or not, and then throw an exception on remote method invocation if it isn't correct. Yippee!
Am I the only one who things this is a awful design decision, presumably made by Sun?