I would like to describe a JAAS login configuration for a rich client. In this case, I am using the JBoss6 and the MySQL database to store user, password and role information. Firstly, I specified my own security domain on the server for my application.  I added my security domain using name “my-domain” into login-config.xml. You can find this file with a default profile in a directory:

<jboss_home_dir>/server/default/conf/login-config.xml

My security domain:

<application-policy name="my-domain">
	<authentication>
		<login-module code="org.jboss.security.ClientLoginModule" flag="required">
			<module-option name="restore-login-identity">true</module-option>
		</login-module>
		<login-module code = "org.jboss.security.auth.spi.DatabaseServerLoginModule" flag = "required">
			<module-option name = "password-stacking">useFirstPass</module-option>
			<module-option name = "dsJndiName">java:/AuthDS</module-option>
			<module-option name = "principalsQuery">SELECT password FROM COM_USER WHERE login=?</module-option>
			<module-option name = "rolesQuery">SELECT role.id, 'Roles' FROM COM_ROLE role, COM_USER_ROLE map,COM_USER principal WHERE role.GUID = map.ROLE_ID AND map.USER_ID = principal.GUID AND principal.login=?</module-option>
			<module-option name="hashAlgorithm">MD5</module-option>
			<module-option name="hashEncoding">Base64</module-option>
			<module-option name="hashCharset">UTF-8</module-option>
			<module-option name ="unauthenticatedIdentity">guest</module-option>
		</login-module>
	</authentication>
</application-policy>

This domain has two login modules. The first one is for a client login module (call-back method).  The second one, database login module, is responsible for the user, password and roles. For database module, I need a data source (AuthDS), which need to be deployed on the server. For the password field in the user table, I am using the MD5 hash algorithm, Base64 hash encoding and UTF-8 hash charset. I need to hash the password before I save it in the database. To do this, I am using the method:

import org.jboss.crypto.CryptoUtil;

public String hashPassword(String user, String password) {
    return  CryptoUtil.createPasswordHash("MD5", "Base64", "UTF-8", user, password);
}

For LDAP authentication, you need to change the database login module to the LDAP login module.  In my EAR component, I also need to specify the security domain. This can be done directly in the maven configuration:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-ear-plugin</artifactId>
	<version>2.5</version>
	<configuration>
		<jboss>
			<version>5</version>
			<security-domain>my-domain</security-domain>
		</jboss>
		<version>6</version>
		<defaultLibBundleDir>lib</defaultLibBundleDir>
		<unpackTypes>war,ejb</unpackTypes>
	</configuration>
</plugin>

Or you can create jboss-app.xml manually and put this file in the EAR package in META-INF directory.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-app PUBLIC
	"-//JBoss//DTD Java EE Application 5.0//EN"
	"http://www.jboss.org/j2ee/dtd/jboss-app_5_0.dtd">
<jboss-app>
  <security-domain>my-domain</security-domain>
</jboss-app>

You can also specify the security domain on the EJB service with the annotation.

import org.jboss.annotation.security.SecurityDomain;

@Stateless(name="MyService")
@Remote(MyServiceBI.class)
@SecurityDomain("my-domain")
public class MyServiceBean implements ServiceBI {
	....
}

Here is an useful comment from Octavio:
The annotation org.jboss.annotation.security.SecurityDomain that you mention worked fine in JBoss 4. In JBoss 6 the annotation was moved to a different package: org.jboss.security.annotation. However, JBoss 6.0 and 6.1 ignore this annotation completely, so the EJB gets deployed without a security domain. This is probably why I was not getting any security events in my log. The application needs to be secured with a jboss-app.xml.

Now you can create a simple client application with dependencies to the ejb-client of my EJB project and JBoss client libraries. I created the method for login like this:

import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginException;
import org.jboss.security.auth.callback.AppCallbackHandler;
import org.jboss.security.client.SecurityClient;
import org.jboss.security.client.SecurityClientFactory;

public void login(String user, String password) {
	try {
		// Callback hnadler
		AppCallbackHandler apch = new AppCallbackHandler(user, password.toCharArray());

		// Setup the login configuration
		Configuration.setConfiguration(new LoginAuthConfiguration());

		// Create security client and login to the server
		SecurityClient ssclient = SecurityClientFactory.getSecurityClient();
		ssclient.setJAAS("client-module", apch);
		ssclient.setVmwideAssociation(true);

		ssclient.login();

	} catch (LoginException ex) {
		LOGGER.error("Error login: " + ex.getMessage(), ex);
	} catch (Exception e) {
		LOGGER.error("Error creating the secyrity client.", e);
	}
}

I am using my own implementation of the login configuration LoginAuthConfiguration. This configuration always returns the same client login module with flag REQUIRED.  The client is using the org.jboss.security.ClientLoginModule. You can specify more configurations depended on the name.

import java.util.HashMap;

import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;

/**
 * The login client configuration.
 * @author Andrej Petras <andrej@ajka-andrej.com>
 */
public class LoginAuthConfiguration extends Configuration {

    /** The jBoss client login module. */
    private static final String JBOSS_CLIENT_MODULE = "org.jboss.security.ClientLoginModule";

    /**
     * {@inheritDoc}
     */
    @Override
    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
        AppConfigurationEntry conf = new AppConfigurationEntry(JBOSS_CLIENT_MODULE, REQUIRED, new HashMap<String, Object>());
        return new AppConfigurationEntry[]{conf};
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void refresh() {
    }
}

To create the initial context I am using a no clustering JNDI configuration:

java.naming.provider.url.port=8443
java.naming.provider.url.protocol=https
java.naming.provider.url=jnp://localhost:1099
j2ee.clientName=my-client
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming.client

Now you can call EJB methods. Firstly, you need to call the method “login”, which provides the login mechanisms to the server. After successful executing of the login method you can call your services. In the jboss-logging.xml file I enabled the log configuration of login modules.

   <logger category="org.jboss.security.ClientLoginModule">
      <level name="TRACE"/>
   </logger>

   <logger category="org.jboss.security.auth.spi.DatabaseServerLoginModule">
      <level name="TRACE"/>
   </logger>

  <logger category="org.jboss.security">
      <level name="TRACE"/>
   </logger>

Finally, you can see logs in the server log file  when you log in with the client.

TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.my-domain] Begin isValid, principal:user, cache info: null
TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.my-domain] defaultLogin, principal=user
TRACE [org.jboss.security.auth.login.XMLLoginConfigImpl] Begin getAppConfigurationEntry(my-domain), size=12
TRACE [org.jboss.security.auth.login.XMLLoginConfigImpl] End getAppConfigurationEntry(my-domain), authInfo=AppConfigurationEntry[]:
[0]
LoginModule Class: org.jboss.security.ClientLoginModule
ControlFlag: LoginModuleControlFlag: required
Options:
name=restore-login-identity, value=true
[1]
LoginModule Class: org.jboss.security.auth.spi.DatabaseServerLoginModule
ControlFlag: LoginModuleControlFlag: required
Options:
name=hashCharset, value=UTF-8
name=hashAlgorithm, value=MD5
name=principalsQuery, value=SELECT password FROM COM_USER WHERE login=?
name=unauthenticatedIdentity, value=guest
name=hashEncoding, value=Base64
name=dsJndiName, value=java:/AuthDS
name=rolesQuery, value=SELECT role.id, 'Roles' FROM COM_ROLE role,COM_USER_ROLE map,COM_USER principal WHERE role.GUID = map.ROLE_ID AND map.USER_ID = principal.GUID AND principal.login=?
name=password-stacking, value=useFirstPass

TRACE [org.jboss.security.ClientLoginModule] Security domain: tc-system
TRACE [org.jboss.security.ClientLoginModule] Enabling restore-login-identity mode
TRACE [org.jboss.security.ClientLoginModule] Begin login
TRACE [org.jboss.security.ClientLoginModule] Obtained login: user, credential.class: [C
TRACE [org.jboss.security.ClientLoginModule] End login
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] initialize
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Security domain: my-domain
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Saw unauthenticatedIdentity=guest
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Password hashing activated: algorithm = MD5, encoding = Base64, charset = UTF-8, callback = null, storeCallback = null
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] DatabaseServerLoginModule, dsJndiName=java:/AuthDS
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] principalsQuery=SELECT password FROM COM_USER WHERE login=?
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] rolesQuery=SELECT role.id, 'Roles' FROM COM_ROLE role,COM_USER_ROLE map,COM_USER principal WHERE role.GUID = map.ROLE_ID AND map.USER_ID = principal.GUID AND principal.login=?
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] suspendResume=true
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] login
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] suspendAnyTransaction
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Excuting query: SELECT password FROM COM_USER WHERE login=?, with username: user
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Obtained user password
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] resumeAnyTransaction
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] User 'user' authenticated, loginOk=true
TRACE [org.jboss.security.ClientLoginModule] commit, subject=Subject:
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] commit, loginOk=true
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] getRoleSets using rolesQuery: SELECT role.id, 'Roles' FROM COM_ROLE role,COM_USER_ROLE map,COM_USER principal WHERE role.GUID = map.ROLE_ID AND map.USER_ID = principal.GUID AND principal.login=?, username: user
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] suspendAnyTransaction
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Excuting query: SELECT role.id, 'Roles' FROM COM_ROLE role,COM_USER_ROLE map,COM_USER principal WHERE role.GUID = map.ROLE_ID AND map.USER_ID = principal.GUID AND principal.login=?, with username: user
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Assign user to role Authenticated
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] Assign user to role u-tc-admin
TRACE [org.jboss.security.auth.spi.DatabaseServerLoginModule] resumeAnyTransaction
TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.my-domain] defaultLogin, lc=javax.security.auth.login.LoginContext@2b8515bf, subject=Subject(450299456).principals=org.jboss.security.SimplePrincipal@1216919532(user)org.jboss.security.SimpleGroup@450584964(Roles(members:Authenticated,u-tc-admin))
TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.my-domain] updateCache, inputSubject=Subject(450299456).principals=org.jboss.security.SimplePrincipal@1216919532(user)org.jboss.security.SimpleGroup@450584964(Roles(members:Authenticated,u-tc-admin)), cacheSubject=Subject(954150626).principals=org.jboss.security.SimplePrincipal@1216919532(user)org.jboss.security.SimpleGroup@450584964(Roles(members:Authenticated,u-tc-admin))
TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.my-domain] Inserted cache info: org.jboss.security.plugins.auth.JaasSecurityManagerBase$DomainInfo@447f1499[Subject(954150626).principals=org.jboss.security.SimplePrincipal@1216919532(user)org.jboss.security.SimpleGroup@450584964(Roles(members:Authenticated,u-tc-admin)),credential.class=[C@1907659718,expirationTime=1306062790734]
TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.my-domain] End isValid, true

Useful links:

JAAS & JBoss: Client Authentication

JndiLoginInitialContextFactory

DatabaseServerLoginModule