3 Replies Latest reply on Dec 9, 2014 3:08 AM by Jérôme Blanchard

    How to use unauthenticatedIdentity when calling EJB from JAX-RS ?

    Jérôme Blanchard Newbie

      Hi,

       

      I have setup a small application that should be able to be accessed either as guest nor as an authentified user. Authentication is defined in a custom security domain in the standalone-full.xml.

      My application is packaged as an ear composed of :

      - an ejb module containing EJB, Entities, MDB, topics, etc...

      - a war module containing JAX-RS services that calls EJBs

       

      I want to handle the authentication using http header for allowing REST calls to provide custom credentials (tokens, certificates, etc...) but I don't want to enforce it (anonymous access allowed) and I want to override the unauthenticatedIdentity using "guest" instead of "anonymous".

      I have produced a small ServletFilter  that is able to parse HTTP headers (or wathever I want) to call the httpRequest.login() method.

      Problem is that when I call httpRequest.login(null, null) in the case of a guest call, I have an exception at the undertow layer...

       

      <security-domain name="mydomain" cache-type="default">

        <authentication>

          <login-module code="UsersRoles" flag="required">

            <module-option name="usersProperties" value="${jboss.server.config.dir}/mydomain-users.properties"/>

            <module-option name="rolesProperties" value="${jboss.server.config.dir}/mydomain-roles.properties"/>

            <module-option name="unauthenticatedIdentity" value="guest"/>

            <module-option name="hashUserPassword" value="false"/>

          </login-module>

        </authentication>

      </security-domain>

       

      Security Domains are defined in jboss-web.xml for the war module and into jboss-ejb3.xml for the ejb module.

       

      Authenticated access works perfectly.

      Anauthenticated access gives :

      - anonymous user if i don't call httpRequest.login() (AbstractServerLoginModule is never called)

      - login failed if i call httpRequest.login(null, null)

      javax.servlet.ServletException: UT010031: Login failed
          at io.undertow.servlet.spec.HttpServletRequestImpl.login(HttpServletRequestImpl.java:410) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
          at org.ortolang.prototype.rest.SecurityFilter.doFilter(SecurityFilter.java:43) [classes:]
          at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:56) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
          at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
          at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
          at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
          at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
          at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)

       

      At the EJB layer it seems that login(null, null) use the unauthenticatedIdentity (AbstractServerLoginModule is called) but at the undertow level, httpAuthentication fail

       

      My question is What is the best way to handle authentication into JAX-RS resources for propagating this authentication to the EJB layer and using the security domain defined into wildfly ?

      Is the JAX-RS resource should also be a SessionBean declaring SecurityDomain ?

      I'm a little bit confused with this obfuscation of JAAS traditionnal LoginContext usage...

       

      Thanks for any advice, jérôme.

        • 1. Re: How to use unauthenticatedIdentity when calling EJB from JAX-RS ?
          Wolfgang Knauf Master

          Hi Jérôme,

           

          did you ever find a resolution?

           

          "httpRequest.login(null, null)" will fail, because the Undertow code throws an exception in case of "null" parameters. See https://github.com/undertow-io/undertow/blob/master/servlet/src/main/java/io/undertow/servlet/spec/HttpServletRequestImpl.java

           

          I will ask your (and my) question on the Undertow mailing list, because I struggle with the "unauthenticatedIdentity" problem myself ;-)

           

          Best regards

           

          Wolfgang

          • 2. Re: How to use unauthenticatedIdentity when calling EJB from JAX-RS ?
            Wolfgang Knauf Master

            I got a response on the mailing list, but it does not help me much ;-).

             

            Although it's not directly what you asked, one thing which you may want to take into account is that in the web layer (via HttpServletRequest) the user/caller principal corresponding to the unauthenticated identity is always null. When using the EJBContext that same user/caller principal is something container specific (although contrary to the web layer never null).

             

            EJB is underspecified here (just as the run-as principal). Likewise, the way in which a security context established in the web layer propagates to EJB is not clear either. There's a vague paragraph about a security domain that should be consulted, which JBoss takes very literally (for secured beans it attempts to re-authenticate instead of propagating the established context), for non-secured beans it doesn't do this.

             

            Finally there are a couple of implementation differences between JBoss' native login modules and the Java EE standard JASPIC ones. For JASPIC you would call HttpServletRequest.authenticate() and the "login module" (SAM) would pass a null to the CallerPrincipalCallback in order to establish the unauthenticated identity.

             

            And after more questions ;-):

            Afaik the unauthenticated identity that's exposed to user code is a very unfortunate result of the fact that whoever wrote the first EJB spec thought it was a good idea to add the requirement "never null" to the return value of EJBContext#getCallerPrincipal.

            I'm sure it was done with the best intentions, but without also defining a constant that we can use to compare to (ie via a reference) OR an explicit "isCallerAuthenticated" method, this has been nothing but a world of hurt.

            The problem is that now there's no real good way to check if a user is authenticated in EJB. A null return would be a good method, but since that value is mysteriously not allowed the container has to use a regular principal. You should then compare the name of this principal to whatever the container has decided to use to determine if the user is authenticated or not.

            This is a recipe for disaster, since without reserving a name, any name the container chooses could be a valid name in the application domain. It just can't work this way.

            As a workaround some containers like JBoss offer the option to remap the name to something, should it clash.


            Best regards

             

            Wolfgang

            • 3. Re: How to use unauthenticatedIdentity when calling EJB from JAX-RS ?
              Jérôme Blanchard Newbie

              Hi,

               

              I've found a solution that might help, I'm using a second LoginModule : Identity which allows any login try to succeed for a specific principal : guest.

              In that way, first login module (UsersRoles) becomes sufficient and a second one (Identity) becomes necessary

              According to this configuration, I just have to call httpRequest.login("fake", "fake") and I'm logged in as "guest" in the EJB layer.

              If the account exists in the first login module (UsersRoles) it's handled at this point.

               

              The convenience is that the login call always succeed, if you call login("jerome", "wrongpassword") instead of having a login error, you still guest... but it's easy to manage.

               

              Best regards, Jérôme.