The core JAAS implementation in JBoss is actually quite general, with LoginModule implementations being responsible for deciding what defines a "credential" and how to handle it. However, I find that the implementation side loses the generality and basically uses userid/password pairs exclusively. The environment I develop for often wants to authenticate not only on what a person knows (uid/pwd) but also where the request comes from. Thus the goal I set myself was to extend the JBoss credential system to allow a LoginModule that wants IP address to work properly.
The extensions are actually not all that complex. The problem was more figuring out what to extend, rather than how to implement the extensions. I thought I should post my results, just in case anybody else cares.
The approach I ended up with involves the following extensions to JBoss core classes.
o SecurityAssociationHandler: The default callback handler doesn't know about anything except uid, pwd, and credential object, and it assumes that the proper response to a password request is a stringified version of the entire credential object. The extension has a bit more intelligence about different credential types and allows a password to be only one of the entries in a credential.
o JaasSecurityManagerService & MBean: The extension simply forces the service to use the extended association handler defined above via the setCallbackHandlerClassName() method. The replacement class gets specified in the jboss-service.xml file.
o JRMPInvoker & MBean: a remove invocation of a J2EE bean comes through this class. The extension replaces the credential passed through the invoke() method with a credential wrapper that contains the original credential and the string returned from RemoteServer.getClientHost(). The wrapper then replaces the credential in the Invocation object, which gets passed into the original invoke() method.
This is all that needs to be done for the J2EE environment. The replacement SecurityAssociationHandler knows how to extract the host-name string from the credential wrapper and returns it only if it gets an object request with a specific string in the response. Otherwise it uses the original credential from the wrapper to respond to password or other requests. This approach means that existing LoginModule implementations, such as UsersRolesLoginModule, work unchanged.
Things are only slightly more complicated for web applications. I needed to modify the catalina BasicAuthenticator class to add thread-local static variables that hold the remote host and address values for a request. The extensions to the JBoss code are the following:
o JBossSecurityMgrRealm: The authenticate() method in this class gets called from the catalina BasicAuthenticator. The extension extracts the client address from the thread-local variables in the catalina BasicAuthenticator, builds a credential wrapper, puts the password and the host into the wrapper, and calls the isValid() method in the security manager.
o EmbeddedTomcatService & MBean: The name of the security manager realm is hard-coded into this class. The extension specifies the extended security manager realm rather than the standard JBossSecurityMgrRealm. This class appears in the tomcat jboss-service.xml file.
With these tomcat-side extensions, the same stack of LoginModules can assign roles based on location or uid/pwd for both J2EE beans and web applications.