将 Kerberos 客户机主体名称映射至 SPNEGO TAI 的 WebSphere 用户注册表标识(不推荐)。
以使用系统编程接口,通过实现从 Microsoft Active Directory 检索到的最终用户标识至 WebSphere® Application Server 安全注册表中使用的标识的任意映射,来定制“简单且受保护的 GSS-API 协商机制” (SPNEGO) 信任关联拦截器 (TAI) 的行为。
开始之前

在 WebSphere Application Server V6.1 中引入了一个信任关联拦截器 (TAI),TAI 使用“简单且受保护的 GSS-API 协商机制” (SPNEGO) 来对安全资源的 HTTP 请求进行安全地协商和认证。现在,WebSphere Application Server 7.0 中已不推荐使用此功能。SPNEGO Web 认证已取代该 TAI,以提供动态重新装入 SPNEGO 过滤器的功能以及对应用程序登录方法启用回退。
depfeat注: 确保已成功执行下列任务:
- 将 Web 浏览器配置为使用 SPNEGO。请参阅将客户端浏览器配置为使用 SPNEGO TAI(不推荐)
- 配置 Java™ 虚拟机 (JVM) 属性、定制 SPNEGO TAI 属性以及启用 SPNEGO TAI。请参阅在 WebSphere Application Server 中配置 JVM 定制属性、过滤 HTTP 请求和启用 SPNEGO TAI(不推荐)
关于此任务
您不需要使用 SPNEGO TAI 的这个简单部署。WebSphere Application Server 可以使用不同的注册表(如本地操作系统、LDAP 或定制注册表)来代替 Microsoft Active Directory。如果 WebSphere Application Server 使用除 Microsoft Active Directory 之外的注册表,那么需要执行从 Microsoft Windows 用户标识到 WebSphere Application Server 用户标识的映射。
过程
使用 JAAS 定制登录模块执行客户机 Kerberos 主体名称从 Microsoft Active Directory 到 WebSphere 用户注册表标识的任何定制映射。JAAS 定制登录模块是为认证 WebSphere Application Server 中的入局和出局请求而定义的插件机制,插在 ltpaLoginModule 之前。 JAAS 定制登录模块使用 subject.getPrincipals(KerberosPrincipal.class) 方法检索 javax.security.auth.Subject 中的客户机 Kerberos 主体名称,将客户机 Kerberos 主体名称映射至 WebSphere 用户注册表标识,然后将映射标识插入散列表属性 com.ibm.wsspi.security.cred.userId 中。然后 ltpaLoginModule 使用映射的标识来创建 WSCredential。
注: 定制登录模块还可以在 com.ibm.wsspi.security.tai.TAIResult 的 javax.security.auth.Subject 中提供全套的安全性属性以完整地声明映射的标识。完整声明了标识后,wsMapDefaultInboundLoginModule 将这些安全性属性映射至 WSCredential。
定制登录模块的样本如下所示:
package com.ibm.ws.security.server.lm;
import java.util.Map;
import java.lang.reflect.Array;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.security.auth.kerberos.*;
import com.ibm.websphere.security.auth.WSLoginFailedException;
import com.ibm.wsspi.security.token.AttributeNameConstants;
/**
*
* @author IBM Corporation
* @version 1.0
* @since 1.0
*
*/
public class sampleSpnegoMappingLoginModule implements LoginModule {
/*
*
* Constant that represents the name of this mapping module. Whenever this sample
* code is used to create a class with a different name, this value should be changed.
*
*/
private final static String MAPPING_MODULE_NAME = "com.ibm.websphere.security.sampleSpnegoMappingLoginModule";
private String mapUid = null;
/**
* Construct an uninitialized WSLoginModuleImpl object.
*/
public sampleSpnegoMappingLoginModule() {
debugOut("sampleSpnegoMappingLoginModule() entry");
debugOut("sampleSpnegoMappingLoginModule() exit");
}
/**
* Initialize this login module.
*
*
* This is called by the LoginContext after this login module is
* instantiated. The relevant information is passed from the LoginContext
* to this login module. If the login module does not understands any of the data
* stored in the sharedState and options parameters,
* they can be ignored.
*
*
* @param subject The subject to be authenticated.
* @param callbackHandler
* A CallbackHandler for communicating with the end user to gather
login information (e.g., username and password).
* @param sharedState
* The state shared with other configured login modules.
* @param options The options specified in the login configuration for this particular login module.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
debugOut("initialize(subject = \"" + subject.toString() +
"\", callbackHandler = \"" + callbackHandler.toString() +
"\", sharedState = \"" + sharedState.toString() +
"\", options = \"" + options.toString() + "\")");
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
debug = "true".equalsIgnoreCase((String)this.options.get("debug"));
debugOut("initialize() exit");
}
/**
*
* Method to authenticate a Subject (phase 1).
*
*
*
* This method authenticates a Subject. It uses CallbackHandler to gather
* the Subject information, like username and password for example, and verify these
* information. The result of the authentication is saved in the private state within
* this login module.
*
*
* @return true if the authentication succeeded, or false
* if this login module should be ignored.
* @exception LoginException
* If the authentication fails.
*/
public boolean login() throws LoginException
{
debugOut("sampleSpnegoMappingLoginModule.login() entry");
boolean succeeded = false;
java.util.Set krb5Principals= subject.getPrincipals(KerberosPrincipal.class);
java.util.Iterator krb5PrincIter = krb5Principals.iterator();
while (krb5PrincIter.hasNext()) {
Object princObj = krb5PrincIter.next();
debugOut("Kerberos principal name: "+ princObj.toString());
if (princObj != null && princObj.toString().equals("utle@WSSEC.AUSTIN.IBM.COM")){
mapUid = "user1";
debugOut("mapUid: "+mapUid);
java.util.Hashtable customProperties = (java.util.Hashtable)
sharedState.get(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY);
if (customProperties == null) {
customProperties = new java.util.Hashtable();
}
succeeded = true;
customProperties.put(AttributeNameConstants.WSCREDENTIAL_USERID, mapUid);
Map<String,java.util.Hashtable)>
mySharedState=(Map<String,java.util.Hashtable>)sharedState;
mySharedState.put((AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY.customProperties);
debugOut("Add a mapping user ID to Hashtable, mapping ID = "+mapUid);
}
debugOut("login() custom properties = " + customProperties);
}
}
succeeded = true;
debugOut("sampleSpnegoMappingLoginModule.login() exit");
return succeeded;
}
/**
*
* Method to commit the authentication result (phase 2).
*
*
*
* This method is called if the LoginContext's overall authentication
* succeeded (the revelant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL login module
* succeeded).
*
*
* @return true if the commit succeeded, or false
* if this login module should be ignored.
* @exception LoginException
* If the commit fails.
*/
public boolean commit() throws LoginException
{
debugOut("commit()");
debugOut("commit()");
return true;
}
/**
* Method to abort the authentication process (phase 2).
*
*
* This method is called if the LoginContext's overall authentication
* failed (the revelant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL login module
* did not succeed).
*
*
*
* If this login module's authentication attempt succeeded, then this method cleans
* up the previous state saved in phase 1.
*
*
* @return true if the abort succeeded, or false
* if this login module should be ignored.
* @exception LoginException
* If the abort fails.
*/
public boolean abort() throws LoginException {
debugOut("abort() entry");
debugOut("abort() exit");
return true;
}
/**
* Method which logs out a Subject.
*
* @return true if the logout succeeded, or false
* if this login module should be ignored.
* @exception LoginException
* If the logout fails.
*/
public boolean logout() throws LoginException
{
debugOut("logout() entry");
debugOut("logout() exit");
return true;
}
private void cleanup()
{
debugOut("cleanup() entry");
debugOut("cleanup() exit");
}
/*
*
* Private method to print trace information. This implementation uses System.out
* to print trace information to standard output, but a custom tracing system can
* be implemented here as well.
*
*/
private void debugOut(Object o)
{
System.out.println("Debug: " + MAPPING_MODULE_NAME);
if (o != null) {
if (o.getClass().isArray()) {
int length = Array.getLength(o);
for (int i = 0; i < length; i++) {
System.out.println("\t" + Array.get(o, i));
}
} else {
System.out.println("\t" + o);
}
}
}
private Subject subject;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;
protected boolean debug = false;
}