You can develop a custom Java Authentication SPI for Containers (JASPI) authentication provider by creating classes that implement the required interfaces noted in the JSR 196: Java Authentication Service Provider Interface for Containers specification.
Review the specific interface implementation requirements for JASPI authentication providers and modules in the JSR 196: Java Authentication Service Provider Interface for Containers specification.
WebSphere® Application Server supports the use of third-party authentication providers that are compliant with the servlet container profile specified in Java Authentication SPI for Containers (JASPI) Version 1.0.
The servlet container profile defines interfaces that are used by the security runtime environment in collaboration with the web container in WebSphere Application Server to invoke authentication modules before and after a web request is processed by an application. Authentication using JASPI modules is performed only when JASPI has been enabled in the security configuration and when a configured JASPI provider has been associated with the web module that processes the received web request.
To develop a custom authentication provider, create classes that implement the required interfaces noted in the JSR 196: Java Authentication Service Provider Interface for Containers specification. A provider can use one or more authentication modules for authentication. Modules can use callbacks to perform authentication, or they can manually add the necessary user identity information to the client subject. Depending on the scope of the provider, the implementation classes can be stored in various locations on the application server.
import java.util.Map;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.config.AuthConfigFactory;
import javax.security.auth.message.config.AuthConfigProvider;
import javax.security.auth.message.config.ServerAuthConfig;
public class SampleAuthConfigProvider implements AuthConfigProvider {
public SampleAuthConfigProvider(Map<String, String> properties, AuthConfigFactory factory) {
...
}
public ServerAuthConfig getServerAuthConfig(String layer, String appContext, CallbackHandler handler)
throws AuthException {
...
}
}
An instance of the AuthConfigProvider implementation class is used by WebSphere Application Server when a request arrives to be processed by the web module of the application. The getServerAuthConfig method is used to obtain a ServerAuthConfig instance. The CallbackHandler argument in the method call is used by the authentication module(s).
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.config.ServerAuthConfig;
import javax.security.auth.message.config.ServerAuthContext;
public class SampleServerAuthConfig implements ServerAuthConfig {
public String getAuthContextID(MessageInfo messageInfo) throws IllegalArgumentException {
...
}
public ServerAuthContext getAuthContext(String authContextID, Subject serviceSubject, Map properties)
throws AuthException {
...
}
}
The getAuthContextID and getAuthContext methods in the ServerAuthConfig implementation class are used to obtain a ServerAuthContext instance.
import javax.security.auth.Subject;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.config.ServerAuthContext;
public class SampleServerAuthContext implements ServerAuthContext {
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
throws AuthException {
...
}
public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject)
throws AuthException {
...
}
}
The validateRequest method in the ServerAuthContext implementation class is used to invoke the module that authenticates the received web request message. If the authentication result is successful, the web container dispatches the received web request message that the target web module processes in the application. If the authentication result is not successful, the request is rejected with the appropriate response status.
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.MessagePolicy;
import javax.security.auth.message.module.ServerAuthModule;
public class SampleAuthModule implements ServerAuthModule {
public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options)
throws AuthException {
...
}
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
throws AuthException {
...
}
public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject)
throws AuthException {
...
}
}
The initialize method in the ServerAuthModule implementation class is called by the ServerAuthContext implementation class to initialize the authentication module and to associate it with the ServerAuthContext instance.
WebSphere Application Server expects the name values obtained with PasswordValidationCallback.getUsername() and CallerPrincipalCallback.getName() to be identical. If they are not, unpredictable results occur. The CallbackHandler's handle() method processes each callback given in the argument array of the method sequentially. Therefore, the name value set in the private credentials of the client subject is the one obtained from the last callback processed.
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.callback.PasswordValidationCallback;
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
throws AuthException {
...
PasswordValidationCallback pvcb = new PasswordValidationCallback(clientSubject, username, password);
handler.handle(new Callback[] {pvcb});
...
}
bpracimport java.util.Hashtable;
import java.util.String;
import javax.security.auth.Subject;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import com.ibm.wsspi.security.registry.RegistryHelper;
import com.ibm.wsspi.security.token.AttributeNameConstants.AttributeNameConstants;
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
throws AuthException {
...
UserRegistry reg = RegistryHelper.getUserRegistry(null);
String uniqueid = reg.getUniqueUserID(username);
Hashtable hashtable = new Hashtable();
hashtable.put(AttributeNameConstants.WSCREDENTIAL_UNIQUEID, uniqueid);
hashtable.put(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME, username);
hashtable.put(AttributeNameConstants.WSCREDENTIAL_PASSWORD, password);
hashtable.put(AttributeNameConstants.WSCREDENTIAL_GROUPS, groupList); //optional
clientSubject.getPrivateCredentials().add(hashtable);
...
}
For more information about the Hashtable requirements and custom login, read about Developing custom login modules for a system login configuration for JAAS.
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.servlet.http.HttpServletRequest;
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
throws AuthException {
...
Map msgMap = messageInfo.getMap();
if ("login".equalsIgnoreCase(msgMap.get("com.ibm.websphere.jaspi.request"))) {
// This request is for the login method
String username = msgMap.get("com.ibm.websphere.jaspi.user");
String password = msgMap.get("com.ibm.websphere.jaspi.password");
// Authenticate using the user name and password set above.
}
else if ("authenticate".equalsIgnoreCase(msgMap.get("com.ibm.websphere.jaspi.request"))) {
// this request is for the authenticate method
String authHeader
= ((HttpServletRequest) messageInfo.getRequestMessage()).getHeader("Authorization");
if (authHeader == null) {
// The user has not provided a username and password yet, return
// AuthStatus.SEND_CONTINUE to challenge
}
else {
// Authenticate using the user name and password in the authentication header.
}
}
else {
// This is not a Servlet 3.0 login or authenticate request; handle as usual.
}
...
}
This location is always on the classpath for the WebSphere Application Server classloader. Using this location, the provider can be registered for a set of web modules or applications as the cell or domain default provider for all web modules and applications, and it can be registered manually as a persistent provider.
Place the provider JAR file anywhere on the WebSphere Application Server system. Configure a shared library that points to the JAR, and add that shared library to the application or server classpath. In a shared library, the provider can be registered for a set of web modules or applications, but the provider cannot be used as the cell or domain default provider. It also cannot be registered as a persistent provider because the shared library is not in the classpath for provider registration during server startup. For more information about configuring a shared library, read about Creating shared libraries.
Include the provider JAR file in the application's EAR file as a utility JAR, or embed the compiled class files in the web module WAR. The embedded provider can be registered for the web modules in the application as long as the classes are included in the classpath for the web module. This provider cannot be used as a cell or domain default provider, nor can it be registered as a persistent provider. The classes in the application are not available for provider registration during server startup.
Read about Configuring a new JASPI authentication provider using the administrative console or JaspiManagement command group for the AdminTask object for more information.