8 Replies Latest reply on Mar 22, 2012 6:03 AM by danjee

    Remote client access with database login module: user name and password are UUIDs

    f.ulbricht

      Hello there,

       

      I have a simple application with a secured session bean. I want to invoke this bean from a remote client.

       

      This is my configuration:

       

      standalone.xml:

       

      ...

                  <security-realm name="TutorialRealm">

                      <authentication>

                          <jaas name="tutorial"/>

                      </authentication>

                  </security-realm>

      ...

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

                  <connector name="remoting-connector" socket-binding="remoting" security-realm="TutorialRealm"/>

              </subsystem>

      ...

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

                          <authentication>

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

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

                              </login-module>

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

                                  <module-option name="dsJndiName" value="java:/TutorialDS"/>

                                  <module-option name="principalsQuery" value="SELECT PASSWORD FROM SYSTEM_USER WHERE USER_NAME = ?"/>

                                  <module-option name="rolesQuery" value="SELECT USER_ROLE, 'Roles' FROM SYSTEM_USER_ROLE WHERE USER_NAME = ?"/>

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

                              </login-module>

                          </authentication>

                      </security-domain>

      ...

       

      My bean looks like this (it just returns the current user, but this method was never called):

       

      @Stateless(name = "Secured")
      @Remote(SecuredRemote.class)
      @SecurityDomain("tutorial")
      public class SecuredBean implements SecuredRemote {

       

      @Resource
      private SessionContext sessionContext;

       

      @Override
      @RolesAllowed("role1")
      public String getCurrentUserName() {
        Principal principal = this.sessionContext.getCallerPrincipal();

        return principal.getName();
      }
      }

       

      In my ear I have a jboss-app.xml like this:

       

      <jboss-app xmlns="http://www.jboss.com/xml/ns/javaee"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="7.0">

      <security-domain>tutorial</security-domain>

      </jboss-app>

       

      My client code is this:

       

      @SuppressWarnings("nls")
      public class Client {

      private static String applicationName = "test.ear";
      private static String remoteModuleName = "remote.jar";

      private static String userName = "admin";
      private static String password = "test";

       

      public static void main(final String[] args) {

        final Client client = new Client();
        try {
         client.run();
        } catch (final Exception ex) {
         ex.printStackTrace();
        }
      }

       

      public Client() {
        // create client configuration
        final EJBClientConfiguration clientConfiguration = new PropertiesBasedEJBClientConfiguration(
          createClientConfigurationProperties());

        // create a context selector
        final ContextSelector<EJBClientContext> contextSelector = new ConfigBasedEJBClientContextSelector(
          clientConfiguration);

        // set the selector for use
        EJBClientContext.setSelector(contextSelector);
      }

       

      public void run() throws Exception { 

        // lookup and use secured bean
        final SecuredRemote secured = lookupBean("Secured", SecuredRemote.class, false);
        System.out.println(secured.getCurrentUserName());
      }

       

      private static <T> T lookupBean(final String beanName, final Class<T> viewClass, final boolean stateful)
         throws NamingException {
        final String lookupName = String.format("ejb:%1$s/%2$s/%3$s!%4$s?%5$s", applicationName, remoteModuleName,
          beanName, viewClass.getName(), stateful ? "stateful" : "stateless");

        return (T) getInitialContext().lookup(lookupName);
      }

       

      private static Context context;

      private static Context getInitialContext() throws NamingException {
        if (context == null) {
         final Hashtable<Object, Object> contextProperties = new Hashtable<>();
         contextProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
         contextProperties.put(Context.SECURITY_PRINCIPAL, userName);
         contextProperties.put(Context.SECURITY_CREDENTIALS, password);

         contextProperties.put("jboss.naming.client.ejb.context", true);
         contextProperties.put(Context.PROVIDER_URL, "remote://localhost:4447");

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

         context = new InitialContext(contextProperties);
        }
        return context;
      }

       

      private static Properties createClientConfigurationProperties() {
        final Properties properties = new Properties();
        properties.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
        properties.put("remote.connections", "default");

        properties.put("remote.connection.default.host", "localhost");
        properties.put("remote.connection.default.port", "4447");

        properties.put("remote.connection.default.username", userName);
        properties.put("remote.connection.default.password", password);

        properties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "true");
        // properties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS","JBOSS-LOCAL-USER");
        properties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");

        return properties;
      }
      }

       

      The database query from the login module is executed but using the "jdbc.spy" is see the user name is a random UUID. So I never see the entered user name on the server side. In the end there is of course this exception on server side:

      JBAS014134: EJB Invocation failed on component Secured for method public abstract java.lang.String com.qualitype.tutorial.remote.SecuredRemote.getCurrentUserName(): javax.ejb.EJBAccessException: JBAS013323: Invalid User

       

      If I enable the "SASL_DISALLOWED_MECHANISMS" property the  is: java.lang.IllegalStateException: No EJB receiver available for handling [...] combination

      If I enable the "INITIAL_CONTEXT_FACTORY" property the exception is: javax.security.sasl.SaslException: Authentication failed: all available authentication mechanisms failed

       

      As you can see, I use a lot of different properties. This is a collection copied from various samples from the forum. I think I tested nearly all combination of them but it always leads me to one of the exceptions above.

       

      In my opinion the configuration on server side should be alright. But I have a lot of doubts concerning the client configuration...

        • 1. Re: Remote client access with database login module: user name and password are UUIDs
          f.ulbricht

          After checking the logfile again, it shows the user name is now "$local" for the sample above.

           

           

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) initialize

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) Security domain: tutorial

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) DatabaseServerLoginModule, dsJndiName=java:/TutorialDS

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) principalsQuery=SELECT ENCODED_PASSWORD FROM SYSTEM_USER WHERE USER_NAME = ?

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) rolesQuery=SELECT ROLE_NAME, 'Roles' FROM SYSTEM_USER_ROLE WHERE USER_NAME = ?

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) suspendResume=true

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) login

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) commit, loginOk=true

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) getRoleSets using rolesQuery: SELECT ROLE_NAME, 'Roles' FROM SYSTEM_USER_ROLE WHERE USER_NAME = ?, username: $local

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) suspendAnyTransaction

          15:09:38,292 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) Excuting query: SELECT ROLE_NAME, 'Roles' FROM SYSTEM_USER_ROLE WHERE USER_NAME = ?, with username: $local

          15:09:38,307 DEBUG [jboss.jdbc.spy] (EJB default - 2) java:/TutorialDS [Connection] prepareStatement(SELECT ROLE_NAME, 'Roles' FROM SYSTEM_USER_ROLE WHERE USER_NAME = ?)

          15:09:38,307 DEBUG [jboss.jdbc.spy] (EJB default - 2) java:/TutorialDS [PreparedStatement] setString(1, $local)

          15:09:38,307 DEBUG [jboss.jdbc.spy] (EJB default - 2) java:/TutorialDS [PreparedStatement] executeQuery()

          15:09:38,307 DEBUG [jboss.jdbc.spy] (EJB default - 2) java:/TutorialDS [ResultSet] next()

          15:09:38,307 TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] (EJB default - 2) No roles found

          15:09:38,307 DEBUG [jboss.jdbc.spy] (EJB default - 2) java:/TutorialDS [ResultSet] close()

          15:09:38,307 DEBUG [jboss.jdbc.spy] (EJB default - 2) java:/TutorialDS [Statement] close()

          15:09:38,307 DEBUG [jboss.jdbc.spy] (EJB default - 2) java:/TutorialDS [Connection] close()

          • 2. Re: Remote client access with database login module: user name and password are UUIDs
            dlofthouse

            If you are seeing the user as $local you need to disable the JBOSS-LOCAL-USER SASL mechanisms on the client side.

             

            The XNIO option for this is : -

             

            org.xnio.Options.SASL_DISALLOWED_MECHANISMS JBOSS-LOCAL-USER

             

            You will need to disable this both for the JNDI connection and for the EJB connection, there are example of this on the other posts discussing the same issue.

            • 3. Re: Remote client access with database login module: user name and password are UUIDs
              f.ulbricht

              That's it - it works!

               

              Here my final (minimized) configuration:

               

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

              remote.connection.default.host=localhost
              remote.connection.default.port=4447

              remote.connection.default.username=userName

              remote.connection.default.password=password

              remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER
              remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false

               

              And for JNDI:

               

              Context.URL_PKG_PREFIXES=org.jboss.ejb.client.naming

               

              This seems to be all that is required to have it work.

               

              Thank you very much!

              • 4. Re: Remote client access with database login module: user name and password are UUIDs
                sebbay

                Hello,

                I'm facing the same problem. In the client I use a LoginContext to pass the username/password to the context:

                 

                final Properties jndiProperties = new Properties();

                 

                jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

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

                jndiProperties.put(Context.PROVIDER_URL, "remote://localhost:4447");

                 

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

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

                 

                InitialContext context = null;

                 

                try

                {

                          Configuration.setConfiguration ( new LoginConfiguration ());

                          Class<?> cb = Class.forName ( "org.jboss.security.auth.callback.UsernamePasswordHandler" );

                          Constructor<?> c = cb.getConstructor ( new Class[] { String.class, char[].class });

                          LoginContext lc = new LoginContext ( "other", ( CallbackHandler ) c.newInstance ( new Object[] { "fapiuser", "guest".toCharArray() }));

                          lc.login();

                 

                          context = new InitialContext(jndiProperties);

                 

                          EJBObject ejbObject = (EJBObject) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);

                          System.out.println("remote: " + ejbObject);

                 

                          ...

                 

                On server-side I use a custom login module:

                 

                public class CustomLoginModule extends UsernamePasswordLoginModule {

                 

                  protected String getUsersPassword() throws LoginException

                  {

                    final String username = super.getUsername();

                    log.info( ">>> username: '" + username + "'" );

                                    ...

                  }

                }

                 

                In JBoss logfile I also see the user name as a random UUID. Can somebody help me to solve this problem?

                 

                 

                Regards,

                Sebastian

                • 5. Re: Remote client access with database login module: user name and password are UUIDs
                  apovodyrev

                  Seems like all remote calls have to be authenticated by remoting-connector.

                  This is the key  <connector name="remoting-connector" socket-binding="remoting" security-realm="TutorialRealm"/> where whole jboss ejb remote access is tied to a single app realm. Seems like a mess. If you have multiple apps on the same server with own security, maintaining acces to them with remote client is going to be nightmare.


                  Application login module must have <module-option name="password-stacking" value="useFirstPass"/> to piggy back on cached Principal/Credentials

                   

                  If security realm (ApplicationRealm by default) is removed from remoting-connector, there is no way to authenticate ejb remote call.

                   

                  Tried multiple approaches

                  1)

                  jndiProperties.put(InitialContext.SECURITY_PRINCIPAL, "user");

                  jndiProperties.put(InitialContext.SECURITY_CREDENTIALS, "pass");

                  2)

                  org.jboss.security.client.SecurityClient

                  3)

                  org.jboss.security.auth.callback.AppCallbackHandler

                   

                  User credential set by above means do not get to java ee security context and random UUID values are used on server, or $local if 

                  setting  SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER  not used

                   

                  A frequently refernced link from jboss7 docs  https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI is not sufficient to make your remote clients work because it leaves the server configuration part out of discussion.

                   

                  Frustrated after fighting this for the thrid day in the row.

                  • 6. Re: Remote client access with database login module: user name and password are UUIDs
                    danjee
                    Seems like all remote calls have to be authenticated by remoting-connector.
                    This is the key  <connector name="remoting-connector" socket-binding="remoting" security-realm="TutorialRealm"/> where whole jboss ejb remote access is tied to a single app realm. Seems like a mess. If you have multiple apps on the same server with own security, maintaining acces to them with remote client is going to be nightmare.
                    
                    

                     

                    My workaround for this was to put a jar file with a dummy login module that just let authentication requests pass, considering that other security-domains are enabled in EJBs.

                     

                     

                     

                    Application login module must have <module-option name="password-stacking" value="useFirstPass"/> to piggy back on cached Principal/Credentials
                    

                     

                    That didn't work for me in JBoss 7.1.1. Do I miss other configurations for making cache to work ?

                    • 7. Re: Remote client access with database login module: user name and password are UUIDs
                      apovodyrev

                      Daniel,

                      I use Jboss 7.1.0. password-stacking will work if you have more than one LoginModule. Say, you leave security realm for remoting unchanged (ApplicationRealm configured by application-users.properties),  Then org.jboss.as.security.remoting.RemotingLoginModule will place principal in the sharedState map maintained by javax.security.auth.login.LoginContext. Then your DatabseServerLoginModule gets its turn it will pick the pricipal cached by RemotingLoginModule. If <module-option name="password-stacking" value="useFirstPass"/> is enabled.

                       

                      Your suggestion for dummy LoginModule is good. There you can place principal/credential supplied by remote client(remote.connection.default.username/password) into sharedState which in turn will be picked up by any other LoginModule in the array of applications deployed on this jboss instance.

                       

                      I see configuration could be like this

                                  <security-realm name="ApplicationRealm">
                                      <authentication>
                                          <jaas name="my-dummy-domain"/>
                                      </authentication>
                                  </security-realm>

                       

                                  <security-domain name="my-dummy-domain" cache-type="default">
                                      <authentication>
                                          <login-module code="MyDummyLoginModule" flag="required">
                                              <module-option name="password-stacking" value="useFirstPass"/>
                                          </login-module>
                                      </authentication>
                                  </security-domain>

                       

                                  <security-domain name="myRealDomain" cache-type="default">
                                      <login-module code="Database" flag="required">
                                          <module-option name="password-stacking" value="useFirstPass"/>
                                          <module-option name="dsJndiName" value=""/>
                                          <module-option name="principalsQuery" value="select password ..?"/>
                                          <module-option name="rolesQuery" value="select ur.role, 'Roles' from ..."/>
                                      </login-module>
                                  </security-domain>

                       

                      Pls, let me know if you use your dummy loginmodule in a similar way

                      Andrei

                      • 8. Re: Remote client access with database login module: user name and password are UUIDs
                        danjee

                        Hello Andrei,

                         

                        I didn't had the time to handle this upgrade to JBoss 7 this last few days. Indeed I use my dummy login module in this way, without this option:

                         

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

                             

                        for it.

                         

                        But this option is enabled in my real login module and the multiple call to EJB problem persists even when calling methods remotely or locally from a war.

                        The problem with multiple calls to the EJB as I understood it will be solved in 7.1.2 version.