8 Replies Latest reply on Nov 22, 2015 4:49 PM by fpezzati

    EJB jndi lookup with a custom login module

    fpezzati

      Hello,

       

      I'm using Wildfly-9.0.1.Final and I'm facing a strange problem, when I try to invoke an EJB using jndilookup I got this error on Wildfly's log:

       

      19:42:22,640 INFO  [it.bytebear.jaas.mongo.module.MongoLoginModule] (EJB default - 4) Initializing MongoLoginModule.

      19:42:22,640 INFO  [it.bytebear.jaas.mongo.module.MongoLoginModule] (EJB default - 4) login requested.

      19:42:27,347 INFO  [it.bytebear.jaas.mongo.module.MongoLoginModule] (EJB default - 4) check credentials for: jim with passwd: org.jboss.as.security.remoting.RemotingConnectionCredential@1f6a2a8c

      19:42:27,347 INFO  [it.bytebear.jaas.mongo.module.MongoLoginModule] (EJB default - 4) abort!

      19:42:27,349 ERROR [org.jboss.as.ejb3.invocation] (EJB default - 4) WFLYEJB0034: EJB Invocation failed on component UserServices for method public abstract java.lan

      g.String it.bytebear.web.mongo.UserServiceRemote.postUserA(): javax.ejb.EJBAccessException: WFLYSEC0027: Invalid User

              at org.jboss.as.ejb3.security.SecurityContextInterceptor$1.run(SecurityContextInterceptor.java:69)

              at org.jboss.as.ejb3.security.SecurityContextInterceptor$1.run(SecurityContextInterceptor.java:49)

              at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:97)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.as.ejb3.deployment.processors.EjbSuspendInterceptor.processInvocation(EjbSuspendInterceptor.java:53)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:66)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356)

              at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:634)

              at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356)

              at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)

              at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)

              at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:195)

              at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.invokeMethod(MethodInvocationMessageHandler.java:331)

              at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.access$100(MethodInvocationMessageHandler.java:69)

              at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler$1.run(MethodInvocationMessageHandler.java:202)

              at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)

              at java.util.concurrent.FutureTask.run(FutureTask.java:262)

              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

              at java.lang.Thread.run(Thread.java:744)

              at org.jboss.threads.JBossThread.run(JBossThread.java:320)

       

      As you can see password callback is returning this weird String value: org.jboss.as.security.remoting.RemotingConnectionCredential@1f6a2a8c. The EJB and the custom login works well. The EJB is exposed as a RESTful web service and I can access it as expected. This is my client, maybe there is something wrong in it:

       

      public class EjbClientTest {

       

        private Context jndiContext;

        private Properties jndiProperties;

       

        @Before

        public void init() {

        jndiProperties = new Properties();

        jndiProperties.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");

        jndiProperties.put("remote.connections", "default");

        jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,

        org.jboss.naming.remote.client.InitialContextFactory.class

        .getName());

        jndiProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "true");

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

        jndiProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS", "JBOSS-LOCAL-USER");

        jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");

        jndiProperties.put(Context.SECURITY_PRINCIPAL, "gino");

        jndiProperties.put(Context.SECURITY_CREDENTIALS, "strada");

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

        }

       

        @Test

        public void test() {

        try {

        jndiContext = new InitialContext(jndiProperties);

        UserServiceRemote usrv = (UserServiceRemote) jndiContext

        .lookup("/MongoWebTest/UserServices!it.bytebear.web.mongo.UserServiceRemote");

        System.out.println("Risultato: " + usrv.postUserA());

        Assert.assertTrue(true);

        } catch (NamingException e) {

        e.printStackTrace();

        Assert.fail();

        } catch (Exception e) {

        e.printStackTrace();

        Assert.fail();

        }

        }

      }

        • 1. Re: EJB jndi lookup with a custom login module
          jaysensharma

          Looks like you are mixing the  EJB Client API based lookup and the Remoting Based EJB Lookup code.

           

          Can you try with any of the following approach:

           

          1). remote-naming project based approach

          https://docs.jboss.org/author/display/WFLY8/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project

          Example:

           

                    Context context=null;
                    try {
                          Properties props = new Properties();
                          props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
                          props.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");   // NOTICE: "http-remoting" and port "8080"
                          props.put(Context.SECURITY_PRINCIPAL, "ejbuser");
                          props.put(Context.SECURITY_CREDENTIALS, "ejbuser@1");
                          props.put("jboss.naming.client.ejb.context", true);
                          context = new InitialContext(props);
                       System.out.println("\n\tGot initial Context: "+context);
                     } catch (Exception e) {
                          e.printStackTrace();
                     }
          
          
          

           

          See the complete code at: MiddlewareMagicDemos/Client.java at master · jaysensharma/MiddlewareMagicDemos · GitHub

           

           

          2). remote ejb client api based approach

          EJB invocations from a remote client using JNDI - WildFly 8 - Project Documentation Editor

           

          Example:  Can be seen in the following discussion : Re: EJB Remote Client - reconnect - how to

          and

          http://middlewaremagic.com/jboss/?p=2744

           

          Regards

          Jay SenSharma

          • 2. Re: EJB jndi lookup with a custom login module
            jaysensharma

            Even after changing the client code if you still face the same issue then can you please share more details about the custom login module which you created ?

             

            Also can you tell us from where the Output of your client execution is saying "check credentials for: jim with passwd: ",   I do not see that anywhere in your code you used the username as "jim" ?  (you seems to be trying to pass the username as "gino")

            • 3. Re: EJB jndi lookup with a custom login module
              fpezzati

              Hello Jay,

               

              "jim" or "gino" is simply a cut and paste problem. I did a couple of tests but the client'source is the same (except for "jim" ). I change the code as you suggest in your example (remote-naming approach) but I still get the same error, user is invalid and password looks like this:

               

              org.jboss.as.security.remoting.RemotingConnectionCredential@2fc53c91

               

              This is the client:

               

              public class EjbClientTest {

               

                private Context jndiContext;

                private Properties jndiProperties;

               

                @Before

                public void init() {

              jndiProperties = new Properties();

                jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,

                "org.jboss.naming.remote.client.InitialContextFactory");

                jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");

                jndiProperties.put(Context.SECURITY_PRINCIPAL, "gino");

                jndiProperties.put(Context.SECURITY_CREDENTIALS, "strada");

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

                }

               

                @Test

                public void test() {

                try {

                jndiContext = new InitialContext(jndiProperties);

                UserServiceRemote usrv = (UserServiceRemote) jndiContext

                .lookup("/MongoWebTest/UserServices!it.bytebear.web.mongo.UserServiceRemote");

                System.out.println("Risultato: " + usrv.postUserA());

                Assert.assertTrue(true);

                } catch (NamingException e) {

                e.printStackTrace();

                Assert.fail();

                } catch (Exception e) {

                e.printStackTrace();

                Assert.fail();

                }

                }

              }


              This is my custom login module:


              public class MongoLoginModule implements LoginModule {

               

                @Inject

                protected MongoDB mongoDb;

                protected Subject subject;

                protected Principal identity;

                protected boolean loginOk;

               

                private CallbackHandler callbackHandler;

                @SuppressWarnings({ "rawtypes", "unused" })

                private Map sharedState;

                @SuppressWarnings({ "rawtypes", "unused" })

                private Map options;

               

                private Logger log = LoggerFactory.getLogger(MongoLoginModule.class);

               

                public boolean abort() throws LoginException {

                log.info("abort!");

                subject = null;

                return true;

                }

               

                public boolean commit() throws LoginException {

                try {

                if (loginOk) {

                UserGroup userGroup = new UserGroup("Roles");

                userGroup.addMember(new RolePrincipal("userA"));

                subject.getPrincipals().add(userGroup);

                subject.getPublicCredentials().add(userGroup);

                log.info("commit!");

                return true;

                }

                log.info("login was not successful");

                } catch (Throwable e) {

                log.error("Error while committing.", e);

                }

                return false;

                }

               

               

                public void initialize(Subject subject, CallbackHandler callbackHandler,

                Map<String, ?> sharedState, Map<String, ?> options) {

                log.info("Initializing MongoLoginModule.");

                this.subject = subject;

                this.callbackHandler = callbackHandler;

                this.sharedState = sharedState;

                this.options = options;

                }

               

               

                public boolean login() throws LoginException {

                log.info("login requested.");

                NameCallback nameCallback = new NameCallback("username:");

                PasswordCallback passwordCallback = new PasswordCallback("password:", false);

                try {

                callbackHandler.handle(new Callback[]{nameCallback, passwordCallback});

                String username = nameCallback.getName();

                String password = new String(passwordCallback.getPassword());

                log.info("check credentials for: "+username+" with passwd: "+password);

                if(username.equals("gino") && password.equals("strada")) {

                loginOk = true;

                identity = new UserPrincipal(username);

                subject.getPrincipals().add(identity);

                subject.getPublicCredentials().add(identity);

                return true;

                }

                } catch (IOException e) {

                e.printStackTrace();

                } catch (UnsupportedCallbackException e) {

                e.printStackTrace();

                }

                return false;

                }

               

               

                public boolean logout() throws LoginException {

                if(subject != null && identity != null) {

                subject.getPrincipals().remove(identity);

                return true;

                }

                return false;

                }

               

                public Document getUserByName(String userName) {

                FindIterable<Document> results = mongoDb.getCollection().find(new Document("username", userName));

                return results.iterator().next();

                }

               

                public void getRoles() {

              // FindIterable<Document> results = mongoDb.getCollection().find(new Document("username", userName));

              // results.iterator().next().get

                }

              }


              Thanks for your reply.

              • 4. Re: EJB jndi lookup with a custom login module
                jaysensharma

                How are you deploying your custom module in WildFly ?  Also may be sharing the "urn:jboss:domain:security" subsystem configuration will also be good.

                 

                Looks like there is a very good article on which explains how to create MongoDB loging module by extending the "UsernamePasswordLoginModule"  it might give you a good idea.

                Configuring a MongoDB Login Module

                • 5. Re: EJB jndi lookup with a custom login module
                  fpezzati

                  This is my security-domain:

                   

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

                  <authentication>

                  <login-module code="it.bytebear.jaas.mongo.module.MongoLoginModule" flag="required">

                  <module-option name="mongodb.uri" value="mongodb://localhost:21017/test?collection"/>

                  </login-module>

                  </authentication>

                  </security-domain>

                   

                  My custom login module extends javax.security.auth.spi.LoginModule. There is something strange about this error. My EJB is also exposed as a RESTFul web service and I can correctly interact with it by http. By http everything works as expected, methods are protected by annotations which I can access when I login with correct credentials, "gino" and "strada". But, when I try to invoke methods by EJB client I got an "invalid user" and this strange password.

                  • 6. Re: EJB jndi lookup with a custom login module
                    jaysensharma

                    Just wanted to quickly check if you have also changed the "ApplicationRealm" to point to your own realm?  As your EJB Client is going to access the EJB over "http-remoting://localhost:8080"

                     

                            <subsystem xmlns="urn:jboss:domain:remoting:2.0">

                                <endpoint worker="default"/>

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

                            </subsystem>

                    • 7. Re: EJB jndi lookup with a custom login module
                      fpezzati

                      No I did not. I don't add any security-realm, just one security-domain the "MongoLoginRealm".

                      • 8. Re: EJB jndi lookup with a custom login module
                        fpezzati

                        Hello Jay. Finally I'm back again on this issue. I tried to change the ApplicationRealm this way:

                         

                        <security-realm name="ApplicationRealm">

                          <authentication>

                            <jaas name="MongoLoginRealm"/>

                          </authentication>

                        </security-realm>

                         

                        I'm not sure about this configuration, I didn't found some docs about it. MongoLoginRealm is my security-domain, is that configuration correct? Now, when I try to do the lookup I got back this exception instead:

                         

                        javax.naming.AuthenticationException: Failed to connect to any server. Servers tried: [http-remoting://localhost:8080 (Authentication failed: all available authentication mechanisms failed:)] [Root exception is javax.security.sasl.SaslException: Authentication failed: all available authentication mechanisms failed:]

                          at org.jboss.naming.remote.client.HaRemoteNamingStore.failOverSequence(HaRemoteNamingStore.java:238)

                          at org.jboss.naming.remote.client.HaRemoteNamingStore.namingStore(HaRemoteNamingStore.java:149)

                          at org.jboss.naming.remote.client.HaRemoteNamingStore.namingOperation(HaRemoteNamingStore.java:130)

                          at org.jboss.naming.remote.client.HaRemoteNamingStore.lookup(HaRemoteNamingStore.java:272)

                          at org.jboss.naming.remote.client.RemoteContext.lookupInternal(RemoteContext.java:104)

                          at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:93)

                          at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:146)

                          at javax.naming.InitialContext.lookup(InitialContext.java:411)

                          at it.bytebear.mongo.ejb.EjbClientTest.test(EjbClientTest.java:40)

                          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

                          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

                          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

                          at java.lang.reflect.Method.invoke(Method.java:606)

                          at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)

                          at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

                          at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)

                          at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

                          at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)

                          at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)

                          at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)

                          at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)

                          at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)

                          at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)

                          at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)

                          at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)

                          at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)

                          at org.junit.runners.ParentRunner.run(ParentRunner.java:363)

                          at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)

                          at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)

                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

                        Caused by: javax.security.sasl.SaslException: Authentication failed: all available authentication mechanisms failed:

                          at org.jboss.remoting3.remote.ClientConnectionOpenListener.allMechanismsFailed(ClientConnectionOpenListener.java:113)

                          at org.jboss.remoting3.remote.ClientConnectionOpenListener$Capabilities.handleEvent(ClientConnectionOpenListener.java:433)

                          at org.jboss.remoting3.remote.ClientConnectionOpenListener$Capabilities.handleEvent(ClientConnectionOpenListener.java:240)

                          at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)

                          at org.xnio.channels.TranslatingSuspendableChannel.handleReadable(TranslatingSuspendableChannel.java:196)

                          at org.xnio.channels.TranslatingSuspendableChannel$1.handleEvent(TranslatingSuspendableChannel.java:110)

                          at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)

                          at org.xnio.ChannelListeners$DelegatingChannelListener.handleEvent(ChannelListeners.java:1092)

                          at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)

                          at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)

                          at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:88)

                          at org.xnio.nio.WorkerThread.run(WorkerThread.java:539)

                          at ...asynchronous invocation...(Unknown Source)

                          at org.jboss.remoting3.EndpointImpl.doConnect(EndpointImpl.java:272)

                          at org.jboss.remoting3.EndpointImpl.doConnect(EndpointImpl.java:253)

                          at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:351)

                          at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:335)

                          at org.jboss.naming.remote.client.EndpointCache$EndpointWrapper.connect(EndpointCache.java:111)

                          at org.jboss.naming.remote.client.HaRemoteNamingStore.failOverSequence(HaRemoteNamingStore.java:197)

                          ... 32 more