Wildfly setup using remote access ejb and the custom connection module / applicationrealm is also called

advertisements

When activating a custom login module for EJB remote authentification, the applicationrealm is additionally called for authentication. Unfortunately, I do not know why.

With the current implementation the user is logged in the customlogin module and logged in the ejb. This is only successful as long as a user with same username and same password is registered in the application-users.properties. Change the user so the login does not work anymore. I am at this point not clear whether the authentication is running exclusively through application-users.properties (ApplicationRealm) or combined via application-users.properties and via custom login module. and why does it authenticate with application-users.properties.

The goal is to authenticate EJB remote access completely by custom login module.

Following the setup:

EJB remote client properties:

props.put("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
props.put(java.naming.factory.url.pkgs, "org.jboss.ejb.client.naming");
props.put("jboss.naming.client.ejb.context", false);
props.put("org.jboss.ejb.client.scoped.context", true);
props.put("endpoint.name", "client-endpoint");
props.put("remote.connections", "default");
props.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", false);
props.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", false);
props.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");  

props.put("java.naming.provider.url", "http-remoting://127.0.0.1:8080");
props.put("remote.connection.default.host", "127.0.0.1");
props.put("remote.connection.default.port", "8080");
props.put("remote.connection.default.username", "username");
props.put("remote.connection.default.password", "password");

ejb url:

ejb:/my-app/MyServiceImpl!com.some.MyServiceInterface

standalone.xml configuration based on normal standalone.xml (not full):

security-realm

<security-realm name="MyRealm">
        <authentication>
                    <jaas name="com.some.MyCustomLoginModule"/>
     </authentication>
</security-realm>

security-domain

<security-domain name="MySecurityDomain" cache-type="default">
        <authentication>
                <login-module code="com.some.MyCustomLoginModule" flag="required" module="login.my">
                            <module-option name="usersProperties" value="user.properties"/>
                            <module-option name="rolesProperties" value="roles.properties"/>
             </login-module>
     </authentication>
</security-domain>

remoting subsystem

<subsystem xmlns="urn:jboss:domain:remoting:3.0">
            <endpoint/>
            <http-connector name="http-remoting-connector" connector-ref="default" security-realm="MyRealm"/>
</subsystem>

Implementation:

service impl

@Stateless
@SecurityDomain("MySecurityDomain")
@DeclareRoles("user")
public class MyServiceImpl implements MyService {  

     private static final Logger logger = Logger.getLogger(MyServiceImpl .class);  

     @Resource
     private EJBContext ejbContext;  

     @PermitAll
     public String getPrincipalName() {
          logger.info("Principal: " + ejbContext.getCallerPrincipal().getName());
          return ejbContext.getCallerPrincipal().getName();
     }
}

service interface

@Remote
public interface MyService {
     public String getPrincipalName();
}

custom login module

import java.security.Principal;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import org.jboss.logging.Logger;
import org.jboss.security.auth.spi.UsersRolesLoginModule;  

public class CustomLoginModule extends UsersRolesLoginModule {
    private CustomPrincipal principal;  

     private static final Logger logger = Logger.getLogger(CustomLoginModule.class);  

     @Override
     public void initialize(Subject arg0, CallbackHandler arg1, Map<String, ?> arg2, Map<String, ?> arg3) {
          logger.info("init module from main class");
          super.initialize(arg0, arg1, arg2, arg3);
     }  

     public boolean login() throws LoginException {
          logger.info("Calling login()");
          logger.info("User before: " + getUsername());  

          boolean login = super.login();  

          logger.info("User: " + getUsername());
          logger.info("Password: " + getUsersPassword());  

          if (login) {
               principal = new CustomPrincipal(getUsername(), "An user description!");
          }
          return login;
     }  

     protected Principal getIdentity() {
          return principal != null ? principal : super.getIdentity();
     }
}


The server-client product I work on also handles the login process completely by the back end through EJB and where the username and passwords are verified. Wildfly is only serving our server and we don't use the Wildfly's Management console so we don't use Wildfly's application-users.

We simply setup the ApplicationRealm like this:

<security-realm name="MyRealm">
    <authentication>
        <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
    </authentication>
</security-realm>

jboss-ejb.client.properties :

remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false

and the login process is handled only through our EJBs.

NOTE: This might not be the solution for everyone with a similar setup. The nature of our product allows us to do this and we have a certificate in place and this all runs only internally behind our customer's networks and firewalls.