7 Replies Latest reply on Aug 27, 2013 8:21 AM by dlmiles

    Remote EJB invocation to clustered wildfly with JAAS

    faxe13

      Hi,

       

      We are facing serious troubles when trying to invoke secured EJB methods from remote EJB clients (in a standalone VM, no application server). What we are seeing is that the invocation on the first cluster node will contain the users principal and credentials witout any problem but the second node (invoked because of load balancing) will ony have the default-user $local as configred in the standalone-full-ha.xml for the ApplicationRealm.

       

      We are using Java 7 and the Alpha 4 version of wildfly using http-remoting. The cluster environment uses the standalone-full-ha.xml configuration with a custom security domain using the

      RemotingLoginModule. We have tried using remote naming as well as the EJB-Client API with the same effects.

       

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

        <authentication>

          <login-module code="org.jboss.as.security.remoting.RemotingLoginModule" flag="required">

            <module-option name="useFirstPass" value="true"/>

          </login-module>

        </authentication>

      </security-domain>

       

      Our Client code is very simple and looks as follows:

       

      Hashtable<String, Object> env = new Hashtable<String, Object>();

       

      env.put("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");

      env.put("java.naming.provider.url",    "http-remoting://localhost:8080,http-remoting://localhost:8180");

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

       

      env.put(Context.SECURITY_PRINCIPAL,   "aut");

      env.put(Context.SECURITY_CREDENTIALS, "aut1234#");

       

      InitialContext jndiCtx = new InitialContext(env);

       

      for (int i = 0; i<10; i++) {

        SecuredBeanRemote bean = (SecuredBeanRemote) jndiCtx.lookup(

                   "securedbean/SecuredBean!com.test.securedbean.SecuredBeanRemote");

        bean.test("text " + i);

      }

       

      The bean which gets deployed in a jar file is also very simple:

       

      @Stateless

      @Clustered

      @SecurityDomain("testdomain")

      public class SecuredBean implements SecuredBeanRemote {

       

                @Resource

                private SessionContext ctx;

       

                @PermitAll

                public String test(String text) {

                          System.out.println("received: " + text + " from " + ctx.getCallerPrincipal().getName());

                          return "xx" + text;

                }

      }

       

      @Remote

      public interface SecuredBeanRemote {

                public String test(String text);

      }

       

      The println on the first node will print "aut" as caller principal and the second node will print $local. We are able to reproduce that always the node that gets the first call will print the principal correctly. If we switch the nodes in the provider.url than the second node will get the first invocation and print the caller principal correctly and the first node will print $local.

       

      Is there anything we can do to get the caller principal propageted correctly on every node ?

       

      Another question that comes to our mind is if we should keep one InitialContext instance around for all server invocations of one client or create a new instance for each method call. In our tests we were getting "java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling" exceptions after about 90 invocations from one client when creating new instances so we decided to keep on instance. But if we are keeping the InitialContext instance we might have troubles providing different credentials for subsequent method calls and would need to synchronize on each call.

       

      Cheers, Gert

        • 1. Re: Remote EJB invocation to clustered wildfly with JAAS
          jaikiran

          You are using remote-naming approach for the EJB invocations. Don't use that, it doesn't have all the necessary support for EJB invocations like for example clustering related configurations. See this documentation on the details https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project.

           

          You can use scoped EJB client contexts in WildFly as explained here https://docs.jboss.org/author/display/WFLY8/Scoped+EJB+client+contexts and have a similar code like the one you have now. In the properties that you pass along to the JNDI context, remember to pass the cluster specific configurations.


          1 of 1 people found this helpful
          • 2. Re: Remote EJB invocation to clustered wildfly with JAAS
            faxe13

            Hi,

             

            Thanks for the quick response. The use of the EJB client solved my problem partially. I am now able to receive the caller principal on both nodes as long as is dont't restart one of the nodes during the run of my programm. If i do than the restarted node will again show me the default principal $local.

             

            Is this something that I could fix with a different config ?

             

            My jboss-ejb-config.properties loogs like that:

             

             

            endpoint.name=client-endpoint

            remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false

             

            remote.connections=one, two

             

            remote.connection.one.host=localhost

            remote.connection.one.port = 8080

            remote.connection.one.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

            remote.connection.one.username=aut

            remote.connection.one.password=aut1234#

             

             

            remote.connection.two.host=localhost

            remote.connection.two.port = 8180

            remote.connection.two.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

            remote.connection.two.username=aut

            remote.connection.two.password=aut1234#

             

             

            remote.clusters=ejb

            remote.cluster.ejb.clusternode.selector=org.jboss.ejb.client.RandomClusterNodeSelector

             

            Cheers, Gert

            • 3. Re: Remote EJB invocation to clustered wildfly with JAAS
              faxe13

              Hi,

               

              After some more investigations I discovered that not only setting user and pasword on each remote connection host (e.g. remote.connection.one.username=AUT) is required but also setting the username and password on the remote cluster itself (e.g. remote.cluster.ejb.username=AUT-CLUSTER). Here are the cluster properties I use at the momen additionally to the properties in my previous post:

               

              remote.clusters=ejb

              remote.cluster.ejb.clusternode.selector=org.jboss.ejb.client.RandomClusterNodeSelector

               

              remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=true

              remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false

              remote.cluster.ejb.username=AUT-CLUSTER

              remote.cluster.ejb.password=password

              remote.cluster.ejb.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER

               

              The effect is that before a cluster node restart I get AUT as caller principal in my EJB and after a cluster node restart I get AUT-CLUSTER as caller principal. This is a bit surprising but not a problem for me because setting both properties to the same value solves my problem.

               

              Regarding scoped beans I think the best approach in my case is to keep a scoped context per HTTP-Session in my web app and close it when the HTTP-Session is destroyed.


              Thanks for pointing me to the right direction.


              Cheers, Gert

              • 4. Re: Remote EJB invocation to clustered wildfly with JAAS
                jaikiran

                By the way, are those 2 nodes (one and two) part of the same cluster? If yes then you don't need to list both of them (unless you want to). You can just list either of them and that node will then act as a starting point for returning the cluster topology to the client.

                • 5. Re: Remote EJB invocation to clustered wildfly with JAAS
                  faxe13

                  Your right. Two nodes which are part of the same cluster. My tests have discovered exactly what you say. The cluster topology is propagated automatically to the client if it changes. Without setting the cluster username and password I always saw exceptions receiving the cluster topology.

                   

                  Thanks, Gert

                  • 6. Re: Remote EJB invocation to clustered wildfly with JAAS
                    jaikiran

                    Gert Kropiunik wrote:

                     

                    Without setting the cluster username and password I always saw exceptions receiving the cluster topology.

                     

                    Thanks, Gert

                    The cluster topology that gets sent down to the client will not include the username/password to use for connecting to the individual cluster nodes (for obvious reasons, since it's upto the client to know and use the correct username/password). The configurations in those properties are thus required on the client side to tell the EJB client API what credentials to use (either for the whole cluster or for individual nodes in the cluster) while connecting to those cluster nodes. That's what you just did by adding those cluster specific configurations and that's the reason why it works now.

                    • 7. Re: Remote EJB invocation to clustered wildfly with JAAS
                      dlmiles

                      Are you saying it is possible to discover the other node, when the node you configured is down (not on network) ?  Even after a reboot (or spin up, in respect of Amazon Web Service) of the client when no former contact with the server was made.

                       

                      So right now OP has 2 nodes configured, lets presume they are 2 nodes of a 2 node cluster.  If either node is down, it is easy to understand how the discovery of the other node is possible, without any former knowledge of the node configuration.

                       

                      So it is then suggested that it is only necessary to configure 1 node in the client config.  We can understand how this works and discovery is possible when the system is fully working and all nodes are up.  But what if the single host you configured is down ?

                       

                      What is the mechanism that discovery uses if only a single IP/port is provided (and that system is down) ?  I could understand if this IP address was a Virtual IP managed by the cluster, but presume in the OP example they run one server with default config and the other with a port offset +100 (so they work on same host).