您可以使用 GenericSecurityTokenFactory SPI 来创建 X.509 令牌以供 WS-Security 运行时环境使用。这些安全性令牌可用于(但不限于)WSSAPI 和 JAAS 登录模块。
关于此任务
使用 GenericSecurityTokenFactory SPI 创建不包含 XML 的 X.509 令牌时,该令牌只能由 X.509 生成者发出且只能由 X.509 使用者使用。因此,X.509 令牌被视为简单令牌,仅供特定于其各自令牌的生成者或使用者使用。X.509 令牌不能由 GenericSecurityTokenLoginModule 发出。
GenericSecurityTokenFactory 提供若干 SPI,您可以将其用于创建 X.509 令牌,这些令牌可以由 X509GenerateLoginModule 发出或者由 X509ConsumeLoginModule 使用。使用 GenericSecurityTokenFactory SPI 创建的 X.509 令牌包含公用和/或专用密钥,其可以用于签署或加密出站消息,或者解密或验证入站消息的签名。
您可能希望使用此类型的令牌:
- 如果您需要以动态方式更改消息的签署密钥。
例如,X509GenerateCallbackHandler 要求在配置时间对签署密钥进行硬编码。如果需要覆盖此硬编码值,您可以将 JAAS 登录模块编码(该模块堆叠在 X509GenerateLoginModule 上),以便登录模块将简单 X.509 令牌置于共享状态。然后,X509GenerateLoginModule
使用简单 X.509 令牌中指定的专用密钥来覆盖回调处理程序中配置的密钥。
- 如果您需要允许多个签名验证证书不显示在 SOAP 消息中。这些消息将包括 KEYID 和 X509IssuerSerial 之类的属性引用的证书。WS-Security 引擎没有以动态方式解析未显示在 SOAP 消息中的证书。证书必须在
X509ConsumeCallbackHandler 中硬编码,并且您只能在回调处理程序中配置一个证书。如果您选择自己实施解析证书的代码,那么您可以将此代码置于堆叠在 X509ConsumeLoginModule 之上的 JAAS 登录模块中,然后将包含期望的公用证书的简单 X.509 令牌置于共享状态。然后,X509ConsumeLoginModule
使用简单 X.509 令牌中指定的公用证书来覆盖回调处理程序中配置的证书。
创建 X.509 令牌后,无法修改令牌中的公用和专用密钥。因此,您必须确定要创建的令牌类型,然后发出命令(类似以下步骤中指定的命令)来创建令牌和 JAAS 登录模块。
- 创建简单 X.509 令牌
确定要创建的简单 X.509 令牌类型,并且发出类似于以下系列命令之一的命令。
- 创建具有公用证书的简单 X.509 令牌。
import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
import com.ibm.websphere.wssecurity.wssapi.token.X509Token;
import java.security.cert.X509Certificate;
...
X509Certificate publicCert = null;
GenericSecurityTokenFactory factory = GenericSecurityTokenFactory.getInstance();
//implement code to obtain the public certificate
X509Token x509 = factory.getSimpleX509PublicToken(publicCert);
- 创建具有专用密钥和可选公用密钥的简单 X.509 令牌。
import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
import com.ibm.websphere.wssecurity.wssapi.token.X509Token;
import java.security.Key;
import java.security.cert.X509Certificate;
...
Key privateKey = null;
X509Certificate publicCert = null;
GenericSecurityTokenFactory factory = GenericSecurityTokenFactory.getInstance();
//implement code to obtain the private key
//optionally implement code to obtain the public certificate
X509Token x509 = null;
try {
x509 = factory.getSimpleX509PrivateToken(publicCert , privateKey);
} catch (WSSException ex) {
//throws an exception if privateKey is null
}
- 创建 JAAS 登录模块,该模块可以堆叠在
X509GenerateLoginModule 或 X509ConsumeLoginModule 之上。
package test.tokens;
import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import com.ibm.websphere.wssecurity.wssapi.token.X509Token;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
public class MyX509LoginModule implements LoginModule {
//For the sake of readability, this login module does not
//protect against all NPE's
private Map _sharedState;
private Map _options;
private CallbackHandler _handler;
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this._handler = callbackHandler;
this._sharedState = sharedState;
this._options = options;
}
public boolean login() throws LoginException {
GenericSecurityTokenFactory factory = null;
WSSUtilFactory utilFactory = null;
try {
factory = GenericSecurityTokenFactory.getInstance();
utilFactory = WSSUtilFactory.getInstance();
} catch (Exception e) {
throw new LoginException(e.toString());
}
X509Token x509 = null;
try {
x509 = getX509Token(factory, utilFactory);
} catch (Exception e) {
throw new LoginException("Exception: "+e.toString());
}
//if generating (signing/encrypting):
factory.putGeneratorTokenToSharedState(this._sharedState, x509);
//if consuming (decrypting/signature verification):
factory.putConsumerTokenToSharedState(this._sharedState, x509);
return true;
}
public X509Token getX509Token (GenericSecurityTokenFactory factory,
WSSUtilFactory utilFactory) throws Exception{
//This sample uses a sample keystore
final String KEYSTORE = "c:/WebSphere/AppServer/profiles/AppSrv01/etc/ws-security/samples/dsig-sender.ks";
final String KEYSTORE_PASS = "client";
final String ALIAS = "soaprequester";
final String ALIAS_PASS = "client";
final String KEYSTORE_TYPE = "jks";
X509Certificate publicKey = null;
java.security.Key privateKey = null;
java.security.cert.Certificate cert = null;
X509Token x509 = null;
//if you need to get the inbound token so that you can do some processing
//to determine which certificate to obtain, get then OMElement for the inbound token
Map wssContext = utilFactory.GetWSSContext(this._handler);
org.apache.axiom.om.OMElement element = utilFactory.getProcessingElement(wssContext);
//Open the keystore
java.security.KeyStore keystore = utilFactory.getKeyStore(KEYSTORE_TYPE, KEYSTORE, KEYSTORE_PASS.toCharArray());
//Get the entry from the keystore
KeyStore.PasswordProtection pwdProtection = null;
if (ALIAS_PASS != null) {
pwdProtection = new KeyStore.PasswordProtection(ALIAS_PASS.toCharArray());
}
KeyStore.Entry entry = keystore.getEntry(ALIAS, pwdProtection);
//Get the public and/or private key from the entry
if (entry instanceof KeyStore.PrivateKeyEntry) {
//entry is a private key
KeyStore.PrivateKeyEntry pkentry = (KeyStore.PrivateKeyEntry)entry;
cert = pkentry.getCertificate();
privateKey = pkentry.getPrivateKey();
} else if (entry instanceof KeyStore.TrustedCertificateEntry) {
//entry is a public key
KeyStore.TrustedCertificateEntry tcentry = (KeyStore.TrustedCertificateEntry)entry;
cert = tcentry.getTrustedCertificate();
}
if ((cert != null) && (cert instanceof X509Certificate)) {
publicKey = (X509Certificate)cert;
} else {
throw new LoginException("Certificate is not X509Certificate");
}
x509 = factory.getSimpleX509Token(publicKey, privateKey);
if (x509 == null) {
throw new LoginException("X509Token is null");
}
return x509;
}
}
- 创建 JAAS 登录配置。
注: 此步骤假定您要堆叠在 X509GenerateLoginModule 上生成令牌。如果要堆叠在 X509ConsumeLoginModule
上使用令牌,那么必须调整步骤以适应此变化。
- 在管理控制台中,转至。
- 在“认证”下,转至 。
- 单击新建,然后在“别名”下输入 test.generate.x509。
- 在“JAAS 登录模块”下,单击新建,然后在“模块类名”下输入 test.tokens.MyX509LoginModule。选择使用登录模块代理,然后单击确定。
- 单击新建,在“模块类名”下输入 com.ibm.ws.wssecurity.wssapi.token.impl.X509GenerateLoginModule。单击确定。
- 在面包屑中,单击 JAAS - 系统登录以返回至 JAAS 系统登录页面。
- 配置 X.509 令牌生成者以使用新的 JAAS 配置。
注: 此步骤假定您要堆叠在 X509GenerateLoginModule 上生成令牌。如果要堆叠在 X509ConsumeLoginModule
上使用令牌,那么必须调整步骤以适应此变化。
- 在管理控制台中,打开要更改的绑定配置。
- 选择 。
- 在“认证令牌”下,选择要更改的出站 X.509 令牌。
- 在“JAAS 登录”下,选择 test.generate.x509。
- 单击确定,然后单击保存。
- 重新启动应用程序服务器以应用 JAAS 配置更改。
- 测试服务。