This document describes how to use the FileNet® P8 Content Engine Web Service Extensible Authentication Framework (WS-EAF). The information in this document is intended for developers who want to extend the functionality of WS-EAF by developing custom login modules that will handle binary security tokens as defined in WS-Security standards. To derive full benefit from the information in this document, we assume the reader is familiar with the WS-Security standard as well as the Java™ Authentication and Authorization Service (JAAS) standard. Sections provided in this document include:
The Content Engine server accepts incoming requests over two transport protocols: an Enterprise Java Bean (EJB) transport and a web service transport. Authentication over the EJB transport is extensible through use of the JAAS standard. The Java 2 Enterprise Edition (J2EE) application server authenticates callers before they can access the EJB. Extensible authentication over the EJB transport is not discussed further in this document because it is defined by the JAAS industry standard.
WS-EAF provides a pluggable authentication mechanism for the web service transport. The authentication mechanism in WS-EAF is based on the Web Service Security (WS-Security) OASIS standard and implemented with the JAAS standard.
The WS-Security standard defines how security credentials are formatted and inserted in a web service request. When a web service request arrives in the Content Engine server, the Content Engine web service listener extracts the WS-Security header and performs a JAAS login based on its contents. If this JAAS login is successful, then the web service listener passes the request to the Content Engine EJB layer within the EJB container.
The Content Engine web service provides out-of-the-box-support for the WS-Security Username Token profile, as well as the Kerberos profile. Support for other WS-Security compliant approaches can be added through the WS-EAF. (See Resources for links to information about the WS-Security standard and JAAS).
In general, to extend Content Engine web services authentication, you must write a custom LoginModule and plug it into WS-EAF. Depending on the targeted application server and actual authentication mechanism, the process could be very complex and requires a thorough understanding of the authentication framework of different application servers.
WS-EAF supports both Java and .NET web service clients when using the web service transport in the Content Engine server. Java clients include standalone Java applications, servlets, and Java™Server Pages (JSP). There are many tools available to aid in writing Java-based web service applications. You can program a Java web service client using Java™ API for XML-based RPC (JAX-RPC), Java™ API for XML Messaging (JAXM), or Apache's WSS4J.
In the .NET environment, Microsoft Web Services Enhancements (WSE) 3.0 is the recommended API for developing web service-based clients. See Resources for links to information sources for web service client development. To take advantage of WS-EAF, users of the Content Engine.NET API can also easily send requests to the Content Engine server using the custom token types.
This topic briefly introduces JAAS and gives an overview of WS-EAF.
WS-EAF makes heavy use of the JAAS programming model. JAAS is a standard Java framework to manage authentication and authorization tasks. JAAS is composed of an application programming interface (API) and a service programming interface (SPI). The figure below depicts a high-level representation of the JAAS authentication model:
Authentication occurs in the JAAS LoginModules. In addition to supporting the pluggable authentication model (PAM), LoginModules are also stackable. Stacking LoginModules allows for defining scenarios in which more than one step is required to complete successfully for authentication to succeed. For example, a configuration may require a username/password authentication, as well as a separate biometric authentication.
For more information on JAAS, see Resources.
By leveraging the JAAS authentication model, WS-EAF automatically supports a pluggable and stackable authentication mechanism. WS-EAF is a very generic authentication framework and doesn't expose any FileNet-specific SPI for use in extending its functionality. Instead, you typically use the standard JAAS API and an application server-specific SPI available from your application server vendor.
WS-EAF consists of a set of conventions for writing a JAAS LoginModule that is able to interact with the Content Engine web service listener to obtain the credentials that are present in the WS-Security header of an incoming request packet. The diagram below illustrates how this interaction occurs for the very first login process (descriptions of the numbered steps follow the diagram):
CallbackHandler
(CBH) is created by WS-EAF and seeded with the contents of the WS-Security
header. CallbackHandler
created in the previous step.
Note The "FileNetP8Engine" stanza is the default JAAS configuration entry to WS-EAF. Because this is just another of the available JAAS key-value pairs of configuration parameters, you can define an alternative login stanza via the administration console using the JAASConfigurationName key. For the purposes of illustration, this document uses the default name when referencing the stanza in text and examples.
CallbackHandler
as a parameter. handle()
method of the CallbackHandler.
For each callback that the client has requested,
the web service CallbackHandler
supplies the callback with requested
XML fragments from the incoming WS-Security header, such that they can be retrieved by the custom
WS-EAF JAAS LoginModule.Subject
is populated and returned.Subject
, and can call the Content Engine service to
handle the request, via the Content Engine EJB.To improve performance, WS-EAF caches the authenticated Subject
upon a successful
JAAS login. The cache key is an encoded form of a username/password combination
or a binary security token. The cache is configurable through the FileNet
Enterprise Manager administration tool. If another SOAP request is sent to
the web service listener with the same credentials, the WS-EAF retrieves
the Subject
directly from local cache without performing another JAAS login,
provided that the cache entry is still valid (that is, not timed-out or purged).
Extending WS-EAF involves the following tasks:
javax.security.auth.spi.LoginModule
interface.Inside a custom LoginModule, the following standard JAAS callbacks are supported:
javax.security.auth.callback.NameCallback;
javax.security.auth.callback.PasswordCallback;
javax.security.auth.callback.TextInputCallback;
NameCallback
and PasswordCallback
are used for Username/Password token authentication
mechanisms. Since the Content Engine server supports username/password authentication
out-of-the-box, developers creating custom solutions should use the TextInputCallback
for handling custom
binary security. You can instantiate one or more TextInputCallback
(s),
passing in different string prompts for each. Depending on the prompt passed
in, WS-EAF sets appropriate values to the instance of TextInputCallback
and
corresponding credential information can be retrieved using TextInputCallback.getText()
inside a custom
LoginModule. The supported prompts and the values returned by the getText()
method are listed below:
valueType
or null
.If you are using WS-EAF and want to retrieve the WS-Security header XML string from within your custom login module, you must specify the following JVM argument for the Content Engine Server: -Dcom.filenet.authentication.wsi.needsWSIHeader
. (Note that you can also add it as an entry to the FileNet.properties file.) This property controls whether the WS-Security header XML string is generated for each WSI request, which has a performance cost. So for customers who do not use WS-EAF, there is no need to specify this JVM property. This property is also not needed if you use WS-EAF but do not wish to retrieve the WS-Security header XML string from within your custom login module.
The example below illustrates usage of TextInputCallback
and the
prompt parameter. Suppose the user designed a custom binary security token
for use with the Content Engine 4.0 web service transport. When the Content
Engine web service listener receives the SOAP call, the WS-Security header
might look like this:
<wsse:Security soap:mustUnderstand="1">
<wsse:BinarySecurityToken ValueType="binary"
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="SecurityToken-f6da72f4-df43-4765-adb7-86eb583e7419">
RGFwaG5lVGVzdHxmaWxlbmV0MTIz
</wsse:BinarySecurityToken>
</wsse:Security>
Notice the BinarySecurityToken
block, which represents the
custom binary security token. After WS-EAF initiates the JAAS authentication
process, the
custom authentication credential can be retrieved by a custom LoginModule with the following code snippet:
javax.security.auth.callback.Callback[] callbacks = new Callback[2];
callbacks[0] = new TextInputCallback("BINARYTOKEN");
callbacks[1] = new TextInputCallback("BINARYTOKEN_VALUETYPE");
callbackhandler.handle(callbacks);
//retrieve the binary security token
String binaryToken = ((TextInputCallback)callback[0]).getText();
//retrieve the binary security token value type
String valueType = ((TextInputCallback)callback[1]).getText();
Had the TextInputCallback
been constructed with the "WSIHEADER" prompt,
the getText()
method would return the entire WS-Security header as an XML
String. The custom LoginModule can parse this XML String to locate the credential.
By using TextInputCallback
, WS-EAF provides sufficient knowledge for
a custom LoginModule to authenticate the SOAP request.
Developing custom LoginModules for different application servers can become complicated. Using WS-EAF describes some of the issues related to using WS-EAF in different J2EE application server environments supported by the Content Engine.
Each J2EE application server has integrated JAAS into their security framework, but since the J2EE standard says little about exactly how to do this, each J2EE vendor has its own integration approach. This means that each J2EE application server has a special, unique way of doing a "valid" login, which is defined here as a JAAS login that will be recognized by the rest of the vendor's J2EE framework. Not performing a JAAS login the "valid" way for that application server will not work correctly in one way or another and, will not propagate the security identity to the FileNet P8 EJB layer.
As an example, in BEA WebLogic®, the JAAS Subject
has special "validated" principals
that, by default, are digitally signed only by a WebLogic Authentication
Provider, whereas IBM® WebSphere® has taken the approach of adding special WSPrincipals
and
WSCredentials
objects that can only be generated by special WebSphere
LoginModules.
JBoss does not use special, valid Subjects
, but employs the strategy of using "hidden" thread
local storage to store and pass around security data. This "thread
identity" should be setup only by a JBoss login module.
The following subtopics provide more information that is specific to supported application servers.
WebLogic has a security framework that uses Security Providers. There are a variety of these providers for special jobs, such as Role Mapping Providers or Authorization Providers, but for WS-EAF, we are only interested in Authentication Providers.
An Authentication Provider is a Java™ Management Extensions (JMX) managed
bean (Mbean) that has a UI page or two in the WebLogic administration
console for setting various login options. Each Authentication Provider has
a flag—OPTIONAL, REQUIRED, REQUISITE, or SUFFICIENT
—just as does
a JAAS LoginModule. They can even be "stacked" in WebLogic security
realms in much the same way that LoginModules can be stacked in a JAAS configuration
stanza.
An Authentication Provider has an associated JAAS LoginModule, which performs the JAAS login. The rest of the Authentication Provider provides a framework that automatically digitally signs Principals created by its LoginModule and also has methods that validate such Principals later and that perform such tasks as identity assertion.
The WebLogic security framework can be divided into a WebLogic client side API and server side SPI. The client side API provides interfaces for applications to perform programmatic authentication or implement custom JAAS LoginModules. On the server side WebLogic provides a Security Service Programming Interface (SSPI), which can be used to implement custom security providers. Viewed from the WebLogic application standpoint, WS-EAF is considered an in-container application client.
WebLogic application server supplies a default UsernamePasswordLoginModule for general client authentication with username/password credentials. For other authentication mechanisms, you will typically need to implement your own client LoginModule. The WebLogic API provides three important methods that are useful in developing a custom LoginModule for WS-EAF:
weblogic.security.auth.Authenticate.authenticate(Environment env,
Subject subject)
weblogic.security.services.Authentication.login(CallbackHandler
handler)
weblogic.security.services.Authentication.login(String realmName,
CallbackHandler handler)
Either a thick client or an in-container client such as a servlet can invoke
a LoginModule implemented with Authenticate.authenticate
method. The method
takes an Environment
argument. This Environment
map must contain a username
and a credential string. The authenticate method calls into the WebLogic
server side security runtime, where the work is done by WebLogic security
providers. The WebLogic security providers perform the actual authentication
and return a signed valid Subject
to the client application.
From the above description of the Authenticate.authenticate()
method, you
can see that for a typical extensible authentication implementation using
WS-EAF, it may be of little use, as it depends on an underlying username/password
authentication mechanism. However, if the custom binary security token can
be decomposed into a username/password pair, and the decomposed username/password
information is intended to be used in the authentication process, then a
LoginModule implemented with Authenticate.authenticate
will be the simplest
way to achieve the goal.
In most other use cases, you should use one of the above Authentication.login
methods to implement your custom LoginModule (referred to as an "application
LoginModule").
The following pseudo-code shows what a typical custom application LoginModule
needs to do in the initialize()
, login()
and commit()
methods:
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
{
this.callbackHandler = callbackHandler;
this.subjectBeforeCommit = null;
this.subject = subject;
}
public boolean login()
{
subjectBeforeCommit = Authentication.login(callbackHandler);
}
public boolean commit()
{
subject.getPrincipals().addAll(subjectBeforeCommit.getPrincipals());
subject.getPublicCredentials().addAll(
subjectBeforeCommit.getPublicCredentials());
subject.getPrivateCredentials().addAll(
subjectBeforeCommit.getPrivateCredentials());
}
The callbackHandler
in the above example is the one WS-EAF creates when
it initiates a standard JAAS authentication process. Notice how Authentication.login
is called and the
returned Subject
is saved in the login()
method. Inside
the commit()
method, the Principals/credentials are transferred to the current
authenticating Subject
.
The Authentication.login()
method calls into the WebLogic security framework
and eventually invokes the custom Authentication Provider's LoginModule
implementation.
A WebLogic Authentication Provider is a JMX MBean that can be deployed from the WebLogic administration console. The WebLogic security framework also uses JAAS internally so implementing a custom Authentication Provider involves a JAAS LoginModule implementation (referred to as the Security Provider LoginModule), as well as implementing some additional SPI interfaces that allow the custom Authentication Provider to interact with the application server. The LoginModule is the central place in which authentication occurs. So here the focus is on the LoginModule component implementation. (See Resources for links to information about the actual steps in the implementation and deployment of the custom Authentication Provider.)
The pseudo-code below shows what needs to be done inside the key methods for the Authentication Provider LoginModule:
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
{
//This callbackHandler is the one passed by authentication.login() method
this.callbackHandler = callbackHandler;
this.subject = subject;
this. principalsForSubject = new Vector();
}
public boolean login()
{
Callback[] callbacks = null;
callbacks = new Callback[1];
callbacks[0] = new TextInputCallback("WSIHEADER");
callbackHandler.handle(callbacks);
String wsiHeader = ((TextInputCallback)callbacks[0]).getText();
Parse wsiHeader and retrieve the BinarySecurityToken, ValueType.
Custom authentication using the BinarySecurityToken
Retrieve the user and group information after authentication
principalsForSubject.add(new WLSUserImpl(username));
principalsForSubject.add(new WLSGroupImpl(groupName));
}
public boolean commit()
{
subject.getPrincipals().addAll(principalsForSubject);
}
Notice inside the login()
method, the callbackHandler
is the one passed
by Authentication.login()
method, and this example uses the "WSIHEADER" prompt
to retrieve the whole WS-Security header. After the Authentication Provider
finishes authentication, the Subject
is passed to the WebLogic Principal
Validator to sign, thereby making it valid.
Additional Notes:
Principals
created by the LoginModule must be derived
from WLSPrincipal
or must use the supplied WLSUserImpl
or WLSGroupImpl
classes so that the
default PrincipalValidatorImpl
works with them. You can avoid this, but
at the price of implementing your own PrincipalValidator
class.runAs
command. IdentityAssertion
,
which must be handled by any custom LoginModule. When true
, the module
should ask for a NameCallback
only (no PasswordCallback
) and should only be validating
that the name is a valid Principal
at the moment.The WebSphere application server security framework heavily uses JAAS. It provides two custom extension points: application login configurations and system login configurations.
One application login configuration consists of a series of JAAS LoginModules
and is intended for application programmatic authentication using JAAS. In
WebSphere, some default application login configurations are predefined,
such as WSLogin, ClientContainer, etc. The actual workhorse of these predefined
application logins is WSLoginModuleImpl
. This LoginModule supports both username/password
and credential token authentication mechanisms. (Note that for the credential
token authentication mechanism, the token has to be one recognized by WebSphere,
such as an LTPA token.) A standalone Java client, client container applications,
servlets, JSP files, and EJBs can use this LoginModule to perform a programmatic
login.
WebSphere system login configurations are primarily used by the WebSphere
Security Runtime. WebSphere also provides several predefined system login
configurations such as RMI_INBOUND, RMI_OUTBOUND, WEB_INBOUND etc. The LoginModules
within these login configurations are dynamically invoked by Security Runtime.
For example, when an HTTP request comes in, the LTPALoginModule
and WsMapDefaultInboundLoginModule
that
are in WEB_INBOUND system login configuration are called to fulfill the authentication
request, if configured to do so. Stacking one or more custom LoginModules into predefined system login configurations
can extend system logins.
WS-EAF falls into the category of application logins. A new application
login configuration is created called "FileNetP8Engine". By default,
it uses WSLoginModuleImpl
to handle username/password authentication mechanism.
To use WS-EAF for supporting custom binary security token, you must implement
a new LoginModule and add it into the "FileNetP8Engine" application
login configuration. Furthermore, since in the WebSphere environment, a custom
LoginModule can't instantiate a WSCredential
, which is stored inside
a valid JAAS Subject after successful authentication, another WebSphere provided
LoginModule has to be stacked to handle creation of WSCredentials
.
In the next few paragraphs, we use the "Identity Assertion with Trust
Validation" approach to develop a custom LoginModule and stack it with
com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule
in
a WebSphere 6 application server environment. (For more information, see
Resources for the "WebSphere Identity Assertion with Trust Validation" link).
The overall authentication consists of two steps:
com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule.state
com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule.trusted
com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule.principal
java.security.Principal
IdentityAssertionLoginModule
, it retrieves
the trusted map from the shared state map and builds WSCredential and WSSubject.First let's show what the application login configuration looks like
after stacking the custom LoginModule and IdentityAssertionLoginModule
. The
following is the "FileNetP8Engine" application login configuration
entry excerpted from the WebSphere security.xml file:
<entries xmi:id="JAASConfigurationEntry_FileNetP8Engine" alias="FileNetP8Engine">
<loginModules xmi:id="JAASLoginModule_1"
moduleClassName="com.ibm.ws.security.common.auth.module.proxy.WSLoginModuleProxy" authenticationStrategy="SUFFICIENT">
<options xmi:id="Property_2" name="delegate" value="com.ibm.ws.security.common.auth.module.WSLoginModuleImpl"/>
<options xmi:id="Property_3" name="use_realm_callback" value="false"/>
<options xmi:id="Property_4" name="use_appcontext_callback" value="false"/>
</loginModules>
<loginModules xmi:id="JAASLoginModule_2" moduleClassName="com.filenet.authentication.MySampleLoginModule"
authenticationStrategy="OPTIONAL">
<options xmi:id="Property_11" name="debug" value="true" required="false"/>
</loginModules>
<loginModules xmi:id="JAASLoginModule_3"
moduleClassName="com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule"
authenticationStrategy="REQUIRED">
<options xmi:id="Property_21" name="debug" value="true" required="false"/>
</loginModules>
</entries>
You can modify this configuration entry from the WebSphere administration
console. The order is important: the custom LoginModule MySampleLoginModule
has to be in front of IdentityAssertionLoginModule
. Also note in the above
stanza, WSLoginModuleImpl
is configured and has the "Sufficient
" flag
to provide the default username/password authentication mechanism.
Below is pseudo-code for the MySampleLoginModule
example's initialize()
and login()
methods:
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
{
//This callbackHandler is the one passed by WS-EAF when authentication //process begins
this.callbackHandler = callbackHandler;
this.subject = subject;
this. sharedState = sharedState;
}
public boolean login()
{
Callback[] callbacks = null;
callbacks = new Callback[1];
callbacks[0] = new TextInputCallback("WSIHEADER");
callbackHandler.handle(callbacks);
String wsiHeader = ((TextInputCallback)callbacks[0]).getText();
Parse wsiHeader and retrieve the BinarySecurityToken, ValueType.
Custom authentication using the BinarySecurityToken
final String username = Retrieve the username information
//prepare the trust map
Map trustMap = new HashMap();
trustMap.put("com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule.trusted",
new Boolean(isValidUser));
//create custom principal
Principal prin = new Principal(){
public String getName(){
Return username;
}
};
trustMap.put("com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule.principal", prin);
//now put the trustMap into shared state
sharedState.put("com.ibm.wsspi.security.common.auth.module.IdentityAssertionLoginModule.state", trustMap);
}
The callback handler used in the login method is the one passed in from
WS-EAF, and we are using "WSIHEADER" prompt to retrieve the whole
WS-Security header. Note how the trusted map is constructed after authentication/validation.
An anonymous java.security.Principal
implementation is used for the custom
Principal
. The IdentityAssertionLoginModule
retrieves the trusted map from
the loginContext
shared state after custom login()
completes.
The JBoss application server allows applications to be secured by declaring a security domain inside their deployment descriptor (jboss.xml or jboss-web.xml). The JBoss security component framework (JBossSX) is automatically invoked to perform security checks by intercepting EJB calls. JBossSX leverages the JAAS framework in its default implementation.
Whereas WebLogic and WebSphere return a valid JAAS Subject after a successful JAAS login, JBoss takes a different approach. Using JBoss terminology, a "client login" is a login from either a standalone Java client or an in-container servlet. In JBoss, upon a successful programmatic application JAAS client login, the returned Subject is not a "valid" one and cannot be reused by a different thread. In the JBoss model, client logins just capture the caller's credentials and associate them with the current thread. The actual authentication is deferred until an attempt is made to access a server resource (for example, an EJB). When a server resource is accessed, the credentials that were associated with the thread by the client LoginModule are used by the server LoginModule to perform the real authentication.
To associate the caller's credentials with the current calling thread,
JBoss uses two built-in LoginModules: ClientLoginModule
and AltClientLoginModule
.
When these two LoginModules are used standalone, they retrieve the username
and credentials from the JAAS NameCallback
and PasswordCallback
, respectively.
By setting the module option "password-stacking" to true
, they
instead retrieve the username and password credential from the JAAS shared
state map, which can be set by other stacked LoginModules. The major difference
between ClientLoginModule
and AltClientLoginModule
is that the latter delays
the association of caller identity to the current thread until the JAAS commit
phase.
The Content Engine EJBs are secured under a security domain named "FileNet", while application logins are configured using the "FileNetP8Engine" JAAS stanza in the JBoss login-config.xml file.
The following example JAAS stanzas illustrate typical setups for supporting custom binary security tokens:
FileNetP8Engine {
com.foo.UserNamePasswordLoginModule optional;
com.foo.ClienSecurityTokenLoginModule optional;
org.jboss.security.ClientLoginModule required
multi-threaded=true password-stacking=useFirstPass
}
FileNet{
org.jboss.security.auth.spi.LdapLoginModule sufficient;
com.foo.ServerSecurityTokenLoginModule sufficient;
}
Note that in the above JAAS configuration stanza, we simultaneously support two authentication mechanisms: username/password-based authentication, and custom security token authentication. From the above configurations, you can see that you must implement two LoginModules to support custom binary security tokens:
ClientSecurityTokenLoginModule
- used by application JAAS loginServerSecurityTokenLoginModule
- used by JBossSX during the authentication check when invoking EJB calls.The following paragraphs describe the WS-EAF implementation of these two LoginModules.
The purpose of ClientSecurityTokenLoginModule
is not to
perform an actual authentication, but to set up the credential information
for the stacked org.jboss.security.ClientLoginModule
to pick up. ClientLoginModule
,
when configured with the "password-stacking=useFirstPass
" option,
retrieves authentication credential values from the JAAS shared state map
by looking up two predefined keys and then associating this credential information
with the current calling thread as discussed earlier. The two keys are:
javax.security.auth.login.name
- the value can be retrieved later using
NameCallback
.javax.security.auth.login.password
- the value can be retrieved
later using PasswordCallback
.The following pseudo-code highlights what the login()
method should do in
ClientSecurityTokenLoginModule
to set up these two keys:
public boolean login() throws LoginException
{
Callback callbacks[] = new Callback[1];
//callback used to retrieve wsi security header.
callbacks[0] = new TextInputCallback("WSIHEADER");
String wsiHeader = ((TextInputCallback)callbacks[0]).getText();
// set up the shared state
sharedState.put("javax.security.auth.login.name","anything");
//the stacked ClientLoginModule will retrieve this as credential
sharedState.put("javax.security.auth.login.password", wsiHeader);
return true;
}
Since we are passing the whole WS-Security header to JBossSX, we only use
the password
key and just put arbitrary data as the value of the name
key.
It is also safe to not set anything into the name
in this case. You
can also set the name
key to a username and the password
key to a password
in cases where your binary security token can be decomposed to retrieve username
and password values.
The JBossSX SPI provides some
abstract LoginModules to facilitate the development of a custom LoginModule.
Since this minimizes the development effort and
enforces correct implementation of the JBoss Subject
usage
patterns (see JBoss reference information), it is recommended that a custom
LoginModule extend org.jboss.security.auth.spi.AbstractServerLoginModule
for WS-EAF development.
The following pseudo-code shows the key details of this approach:
public class FnDemoServerBinaryTokenLoginModule extends
AbstractServerLoginModule {
private Principal identity;
public boolean login() throws LoginException {
super.loginOk = false;
Callback callbacks[] = new Callback[1];
//callback used to retrieve wsi security header.
callbacks[0] = new PasswordCallback("pass", false);
super.callbackHandler.handle(callbacks);
String wsiHeader =
new String(((PasswordCallback)callbacks[0]).getPassword());
Parse the wsi security header and extract credentials.
Do actual authentication here and find out the username
//authentication passed. set up JBoss identity.
if (identity == null) {
identity = super.createIdentity(username);
}
super.loginOk = true;
return super.loginOk;
}
protected Principal getIdentity() {
return identity;
}
protected Group[] getRoleSets() throws LoginException {
//set up the caller principal as current user.
Group[] groups = {new SimpleGroup("CallerPrincipal")};
groups[0].addMember(identity);
return groups;
}
Inside the login()
method, the WS-Security header is retrieved using PasswordCallback
.
The getIdentity()
and getRolesSets()
methods are template methods of AbstractServerLoginModule
.
They should be implemented to provide the caller's primary identity
and group information. Since the Content Engine doesn't use role-based
J2EE security, here we just set up the "CallerPrincipal" group,
which provides the application identity rather than the security domain identity.
For more information on the JBoss security framework and the JBossSX SPI, see Resources.
Code samples are available for download on the IBM support page. (http://www.ibm.com/software/data/support).
Samples are available for WebLogic, WebSphere, and JBoss application server environments. A "readme" document included with the code samples explains how to use them.