5 Replies Latest reply on Nov 30, 2017 5:15 AM by Darran Lofthouse

    Remote EJB (using remote-naming) with JAAS authentication (for secured ejb)

    Sébastien Andre Newbie

      Hi,

       

      I'm migrating a standalone java application that calls ejb on J2EE server for now calling EJBs on a WildFly 9.0.2 J2EE server (maybe Widfly 10 for customers using java 8+)

       

      The java application calls EJBs and use JAAS for authentication.

      On the server side, we use the SessionContext.getCallerPrincipal() for handle our in-app session mechanism.

       

      At this time, the client side seems to be correctly authenticated (i have a JAAS Subject)

      but on the ejb, when i call SessionContext.getCallerPrincipal() , i have always "anonymous"

       

      I have  to say that the ejb call succeed but without any caller identity information

       

      The subject on the client side looks like

        Objet :

        Principal : 4628796b-723f-42b6-b14d-8a88444fed02

        Principal : Roles(members)

        Principal : CallerPrincipal(members:4628796b-723f-42b6-b14d-8a88444fed02)

        Principal : username

       

       

      I resume here relevant code that i use:

       

      For the JNDI lookup, i use this code:

        private static synchronized javax.naming.Context initClientContextJNDI() {

          Properties props = new Properties();

          try {

              // java.naming.factory.initial

              props.put( Context.INITIAL_CONTEXT_FACTORY , "org.jboss.naming.remote.client.InitialContextFactory" );

            

              // java.naming.provider.url

              props.put( Context.PROVIDER_URL , "http-remoting://localhost:8081" );

            

              // java.naming.factory.url.pkgs

              props.put( "jboss.naming.client.ejb.context" , true );

               

              return new javax.naming.InitialContext(props);

          }

          catch(Exception e){ e.printStackTrace(); }

          return null;

      }

       

       

      For the JAAS authentication, i use this code :

       

          System.setProperty("java.security.auth.login.config", new File("xxxxxx\\wildfly9.config").getAbsolutePath() );

          ApplicationCallbackHandler handler   = new ApplicationCallbackHandler();

          LoginContext  loginContext = new LoginContext( "application" , handler );

          loginContext.login();

          Subject subject = loginContext.getSubject();

          System.out.println("Authentification:" + subject );

       

      The ApplicationCallbackHandler can fill credentials for callbacks NameCallback and PasswordCallback

       

      The wildfly9.config giving the JAAS login context configuration is like;

       

      application {

          // Login Module to use custom authentication

          mycie.util.jaas.PasswordLoginModule required;

       

          // Login Module to use for WILDFLY Authentication

          org.jboss.security.ClientLoginModule required;

      };

       

      The PasswordLoginModule extends AbstractServerLoginModule and set

      • a SimplePrincipal with a unique session id
      • a SimpleGroup named "Roles"  (found this from some documentation)

       

      On the server side, my EJB is configured as follow:

       

      @Stateless

      @Local(TestLocal.class)

      @Remote(Test.class)

      @PermitAll

      @SecurityDomain(value="mycie")

      public class TestBean implements Test , TestLocal {

       

           private static final double TX = 6.55957d;

       

           @TransactionAttribute(TransactionAttributeType.REQUIRED)

          public double euroToFranc(double euro) {

               System.out.println("caller: " + getSessionContext().getCallerPrincipal() );

               return euro * TX;

          }

      }

       

      I set the @PermitAll for enable SecurityInterceptor (i readed that from EJB 3.1 specs)

      But from some jboss/wildfly documentations, i readed that we should set the @SecurityDomain (i tried with or without it)

       

      That where my knowledge in wildfly limit me. i'm thinking i may have configuration issues related to the security-domain

       

      I created a security-realm like this:

       

           <security-realm name="MyCieRealm">

                      <authentication>

                             <jaas name="MyCie"/>

                      </authentication>

           </security-realm>

       

      In the subsystem urn:jboss:domain:ejb3:3.0 , the http-remoting-connector didn't specify any security-realm

      • if i set one, it's shared by the remote-naming when i perform JNDI. But i didn't want credentials for the JNDI lookup.

       

      In the subsystem urn:jboss:domain:security:1.2, i created a security-domain:

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

              <authentication>

                  <login-module code="Remoting" flag="optional">

                       <module-option name="password-stacking" value="useFirstPass"/>

                   </login-module>

                   <login-module code="mycie.util.jaas.CustomLoginModule" flag="required" module="mycie_domain"/>

               </authentication>

         </security-domain>

       

      This security-domain is a random try from some code snipped found on the web but i didn't understand what i should do here !!!

      (i created a module mycie_domain with small jar and a small CustomLoginModule accepting the authentication, but it doesn't seems to be used because i  set a breakpoint and never be suspended on these code)

       

      I'm a newbie in WildFly, i tried to be the most complete as possible for giving you efficients informations.

      If you need some other kind of informations, don't hesitate.

       

      Any help are welcome

       

      Best regards,

      Sébastien.

        • 1. Re: Remote EJB (using remote-naming) with JAAS authentication (for secured ejb)
          Sébastien Andre Newbie

          Hi,

           

          Following this article JBoss AS 7 : Remote EJB Authentication Howto

          I'm be able to do a simple authentication from the client and have the propagated identity on SessionContext.getCallerPrincipal().

           

          But this design did'nt fit well in my case because:

          • Credentials have to be set inside the InitialContext with theses properties (on the client side)
            • java.naming.security.principal
            • java.naming.security.credentials
          • It didn't use jaas on the client side for performing the authentication
            • I want to use a custom login module (on the client side) performing the authentication (calling an ejb for the auth process)
          • I don't want to secure the jndi lookup, i want to be able to lookup ejb ref.

           

          Any idea ?

           

          • 2. Re: Remote EJB (using remote-naming) with JAAS authentication (for secured ejb)
            Sébastien Andre Newbie

            After many tries, i did some progress.

             

            On the client side:

            - Use a custom login module on the client side that perform a custom authentication (for now it did nothing real)

            - Use the ClientLoginModule from jboss

             

            On the server side:

            - Use a custom JAAS login module linked to the security-domain used by our ear

             

            on the server, the configuration is like this:

              <security-realm name="OurApplicationRealm">

                   <authentication>

                        <jaas name="OurApplicationJAASDomain"/>

                   </authentication>

              </security-realm>

             

             

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

                   <authentication>

                        <login-module code="Remoting" flag="optional">

                             <module-option name="password-stacking" value="useFirstPass"/>

                        </login-module>

                        <login-module code="mycie.util.jaas.ServerCustomLoginModule" module="mycie.util.jaas" flag="required"/>

                    </authentication>

              </security-domain>

             

            One another important things was to remove the security-realm on this line:

             

               <http-connector name="http-remoting-connector" connector-ref="default" />

             

            The ServerCustomLoginModule is bundled in a module in modules/layers/base/mycie/util/jaas/main as follow:

            • A jar file "MyCieJAASDomain.jar"
            • a module.xml file with this contents:

             

              <module xmlns="urn:jboss:module:1.3" name="mycie.util.jaas">

               <resources>

                  <resource-root path="MyCieJAASDomain.jar"/>

                </resources>

                <dependencies>

                   <module name="org.picketbox"/>

                   <module name="javax.api"/>

                </dependencies>

              </module>

            Now, the ServerCustomLoginModule is called but when a inspect the CallbackHandler with a NameCallback, PasswordCallback, SecurityAssociationCallback and ObjectCallback it is always refering to such anonymous credentials.

            I was thinking that the server login module will receive such informations taking from the ClientLoginModule ?

             

             

            If someone know what is the issue, i would be very happy to share the solution

             

            Best regards,

            Sébastien.

            • 3. Re: Remote EJB (using remote-naming) with JAAS authentication (for secured ejb)
              Sébastien Andre Newbie

              So,

               

              i'm always working on this stuff. At this time i didn't found a way that allow me to migration from my previous EE server to wildfly.

               

              In my last attempt, i did:

               

              <http-connector name="http-remoting-connector" connector-ref="default" security-realm="myAppRealm" />

               

              The realm is configured as follow:

               

                  <security-realm name="myAppRealm">

                      <authentication>

                           <jaas name="myAppDomain"/>

                      </authentication>

                   </security-realm>

               

              And the security-domain as follow:

               

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

                    <authentication>

                       <login-module code="Remoting" flag="optional">

                           <module-option name="password-stacking" value="useFirstPass"/>

                       </login-module>

                       <login-module code="mycie.util.jaas.ServerLoginModule" module="mycie.util.jaas" flag="required"/>

                     </authentication>

              </security-domain>

               

              On the client side, i use remote-naming as follow without using JAAS:

               

                  Properties props = new Properties();

                  try {

                      // java.naming.factory.initial

                      props.put( Context.INITIAL_CONTEXT_FACTORY , "org.jboss.naming.remote.client.InitialContextFactory" );

                    

                      // java.naming.provider.url

                      props.put( Context.PROVIDER_URL , "http-remoting://localhost:8081" );

                    

                      // java.naming.security.principal

                      props.put(Context.SECURITY_PRINCIPAL, "mylogin" );

                    

                      // java.naming.security.credentials

                      props.put(Context.SECURITY_CREDENTIALS, "mypassword");

                    

                      props.put( "jboss.naming.client.ejb.context" , true );

                   

                      // will use PLAIN SASL mechanism.... O_o

                      props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS"    , "false" );

                      props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT"    , "false" );

                      props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS" , "JBOSS-LOCAL-USER" );

               

                      javax.naming.Context ctx = new javax.naming.InitialContext(props);

                      return ctx;

                  }

                  catch(Exception e){ e.printStackTrace(); }

                  return null;

               

               

              So, the authentication works, my JAAS module on the server is called like a charm.

              But:

              • I did'nt found a way to configure the client and/or the server to use another SASL mechanism than PLAIN
                • If i remove the NOPLAINTEXT property, the authentication fails with "No SASL mechanism found"
              • I didn't find anyway to  disable SASL.

               

              • My java client, must call EJBs with differents credentials. At this time with the previous EE server, i bound a SecurityContext to the caller thread before calling an EJB method.
                With Wildfly, I tried to have by example 2 InitialContext using 2 differents credentials, I  lookup 2 EJB ref from theses InitialContext and perform method invocation.
                But as soon as i lookup the second EJB ref from the second InitialContext, it seems to break the context for the first ref. If i call a method on the first ref i have a EJBCLIENT000025: No EJB receiver available for handling... (i have the same result if lookup are done in differents threads)
              • At the end, i would disable SASL and use an authentication method on the client side that allow me to register a kind of a SecurityContext to the caller thread in order to select the credentials to use. Is it a way to achieve this ? i looked about SecurityClient.setSimple(....) but didn't find a way to work with because as long an SASL layer is involved, i must set credentials on the InitialContext and in this case it seems to take precedence over the SecurityClient.setSimple(...)

               

              Any advice are welcome, it's starting to killing me...

               

              Best regards,

              Sébastien.

              • 4. Re: Remote EJB (using remote-naming) with JAAS authentication (for secured ejb)
                Irfan Ali Dogar Newbie

                Hi Sebastien,

                 

                I was facing a similar issue with my custom security domain and dynamic username / password. I was able to resolve it by doing jaas login and adding following configuration in my custom security domain:

                <login-module code="org.jboss.security.ClientLoginModule" flag="required" > 

                <module-option name="multi-threaded" value="true"/>

                <module-option name="restore-login-identity" value="true"/>

                </login-module>



                • 5. Re: Remote EJB (using remote-naming) with JAAS authentication (for secured ejb)
                  Darran Lofthouse Master

                  Please never ever add the ClientLoginModule to a security domain that is used for securing a deployment, this login module works by pushing to a stack and without a logout the pop does not happen - for some in container scenarios where RunAs is also in use this can lead to undesirable effects if the stack is out of alignment.

                   

                  Also if you are ever using LoginContext.login for the ClientLoginModule the remaining code must be wrapped in a try / finally to ensure logout is called before the call returns up the call stack.