3 Replies Latest reply on Mar 6, 2017 12:59 PM by Sébastien Andre

    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.