jboss-5.1.0 - java.lang.IllegalArgumentException: callerSubject is null

Feb 27, 2012 at 2:53 PM
Edited Feb 27, 2012 at 3:05 PM

I have been using SPNEGO for single sign on, but need to support NTLM for IE when accessing over the internet as IE downgrades to NTLM instead of BASIC.

Using the Tomcat Single-SignOn Authenticator Valve, I am getting through [waffle.apache.NegotiateAuthenticator] successfully logged in user:, but then I get the following error:

[org.apache.catalina.connector.CoyoteAdapter] An exception or error occurred in the container during the request processing
java.lang.IllegalArgumentException: callerSubject is null
    at org.jboss.security.plugins.javaee.WebAuthorizationHelper.hasRole(WebAuthorizationHelper.java:125)
    at org.jboss.web.tomcat.security.SecurityAssociationActions$10.run(SecurityAssociationActions.java:363)
    at org.jboss.web.tomcat.security.SecurityAssociationActions$10.run(SecurityAssociationActions.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.jboss.web.tomcat.security.SecurityAssociationActions.hasRole(SecurityAssociationActions.java:359)
    at org.jboss.web.tomcat.security.JBossWebRealm.hasRole(JBossWebRealm.java:598)
    at org.apache.catalina.realm.RealmBase.hasResourcePermission(RealmBase.java:789)
    at org.jboss.web.tomcat.security.JBossWebRealm.hasResourcePermission(JBossWebRealm.java:475)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:507)
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:567)
    at org.apache.catalina.valves.RequestDumperValve.invoke(RequestDumperValve.java:151)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Thread.java:662)

Can anyone offer suggestions?

Also, If I were able to incorporate only enough waffle or jna to obtain the authenticated user's UPN when an NTLM token was encountered, my problems would be solved.  Can you suggest a way to do that?

Coordinator
Feb 27, 2012 at 3:47 PM

Each one of these application servers has its own way of implementing realms and other security stuff. So the Tomcat SSO valve is more-or-less specific for Tomcat. You can do one of two things:

  • Branch waffle and implement a JBoss specific valve that makes sure it's org.jsboss.security.plugins.javaee.WebAuthorizationHelper is happy. This has been done before for Tomcat, Spring Security, etc.
  • Try to use the Waffle filter implementation in front of all this mess. Then you should have everything you need already setup for you by the time it reaches JBoss.

You'll have to put your hands into Tomcat's SSO implementation to fallback to Waffle. It would probably be nice. IMO Tomcat implementing SSO is wonderful, except when it doesn't work (eg. NTLM), if I were you and since you're on Windows, I would get rid of it and use a Waffle filter.

Feb 27, 2012 at 6:37 PM

We aren't actually using Tomcat's SSO, but our own based on the sourceforge spnego libs.  Using the filter, I get logged in to the server but not my application.  I never get a Remote_User.

Coordinator
Feb 27, 2012 at 7:01 PM

You have to look at your application and how it pulls that user out of the currently logged in context. It's probably some custom code. The filter will set session's javax.security.auth.subject in doFilter (see http://waffle.codeplex.com/SourceControl/changeset/view/69234#1106359), so you should be able to retrieve it from there. It's a standard practice for auth filters.

session.setAttribute("javax.security.auth.subject", subject);
Feb 28, 2012 at 1:32 PM

Thank you, I can see the WindowsPrincipal in that attribute.  I didn't see in the code a method to obtain the UPN.  Is there a way to get that rather than domain\user?

Coordinator
Feb 28, 2012 at 2:30 PM

Scratch what I said :)

I think the only way you can get this is by invoking TranslateName or by impersonating the user first to call GetUserNameEx. The latter is a bad idea, because you may not have impersonation privileges. A signature for TranslateName would be a nice contribution to JNA.

I'd be curious to hear why you need the UPN.

Feb 28, 2012 at 7:27 PM

We use the UPN as the application user name, as this works with spnego. Technically, its user@REALM that we use, so its not always the UPN.

On another note, iIt seems that the negotiate sent by the browser for waffle isn’t the same as what it sends for spnego. Do you know why? I will get a wireshark trace of the tokens if needed.

Coordinator
Feb 28, 2012 at 7:45 PM

The problem with using a UPN (or any name) is that mary@domain got married and became jenny@domain and another mary@domain joined. You have to use the SID for all security-type stuff. The display name is for being pretty.

By "not the same", do you mean longer or shorter? Shorter ones are usually NTLM, longer ones Kerberos. If you're falling back to NTLM where Kerberos was working, make sure the SPN is properly setup. See FAQ.

Mar 7, 2012 at 2:02 PM

In response to you last question - it seemed that there were different NTLM tokens but what I actually saw were different stages of the NTLM response. 

I have a new question - once authentication has occurred, how can I force the NTLM handshake to be broken so that a POSTed form can be submitted without requiring further NTLM authentication?  It seems that IE will not POST after it has authenticated until this happens.  This problem arises when accessing a site from outside the domain as a user who exists in active directory, but is not a user in my application - think guest.  In this case, the user authenticates at the basic (NTLM) popup in order to get to the application's FORM login, where he enters his application credentials.  It is not sufficient to pass the AD user in as the application user because all guests word then operate as the same user.

Coordinator
Mar 7, 2012 at 3:21 PM

If the negotiation was NTLM, then you can't avoid it. It's by definition in the protocol - all POSTs will send a 0-length request first and need to re-negotiate.