You can use the GenericSecurityTokenFactory SPIs to create
X.509 tokens for use by the WS-Security runtime environment. These
security tokens can be used for, but are not limited to, WSSAPIs and
JAAS login modules.
About this task
When a GenericSecurityTokenFactory SPI is
used to create an X.509 token that does not contain XML, the token
can only be emitted by the X.509 generator and consumed by the X.509
consumer. Therefore, an X.509 token is considered a simple token,
which is only intended for use by its respective token-specific generator
or consumer. An X.509 token cannot be emitted by the GenericSecurityTokenLoginModule.
The
GenericSecurityTokenFactory provides several SPIs that you can use
to create X.509 tokens that can be emitted with the X509GenerateLoginModule
or consumed by the X509ConsumeLoginModule. X.509 tokens that are
created using a GenericSecurityTokenFactory SPI contain public and/or
private keys that can be used to sign or encrypt an outbound message
or decrypt or verify the signature of an inbound message.
You
might want to use this type of token:
- If you need to dynamically change the signing key for a message.
For example, the X509GenerateCallbackHandler requires that the signing
key be hardcoded at configuration time. If you need to override this
hardcoded value, you can code a JAAS login module that is stacked
over X509GenerateLoginModule such that the login module puts a simple
X.509 token in the shared state. The X509GenerateLoginModule then
uses the private key that is specified in the simple X.509 token to
override the one configured in the callback handler.
- If you need to allow multiple signature verifying certificates
that do not appear in the SOAP message. These messages would include
certificates that are referenced by attributes such as KEYID and X509IssuerSerial.
The WS-Security engine does not dynamically resolve certificates
that do not appear in the SOAP message. The certificate must be hardcoded
in the X509ConsumeCallbackHandler, and you can only configure one
certificate in the callback handler. If you choose to implement code
that resolves the certificate yourself, you can put this code in a
JAAS login module that is stacked over X509ConsumeLoginModule, and
then put a simple X.509 token in the shared state that contains the
desired public certificate. The X509ConsumeLoginModule then uses
the public certificate that is specified in the simple X.509 token
to override the one configured in the callback handler.
After an X.509 token is created, the public and private
key in the token cannot be modified. Therefore, you must determine
the type of token you want to create, and then issue commands similar
to the ones specified in the following steps to create your token
and JAAS login module.
- Create a simple X.509 token
Decide the type
of simple X.509 token you want to create, and issue commands similar
to one of the following series of commands.
- Create a simple X.509 token with a public certificate.
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);
- Create a simple X.509 token with a private and optional
public key.
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
}
- Create a JAAS login module that can be stacked on top of
X509GenerateLoginModule or 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;
}
}
- Create a JAAS login configuration.
Note: This step assumes that you are stacking on X509GenerateLoginModule
to generate a token. If you want to stack on X509ConsumeLoginModule
to consume a token, you must adjust the steps to accommodate this
variation.
- In the administrative console, go to .
- Under Authentication, go to .
- Click New, and under Alias, enter test.generate.x509.
- Under JAAS login modules, click New,
and under Module class name, enter test.tokens.MyX509LoginModule.
Select Use login module proxy, and click OK.
- Click New, and under Module class
name, enter com.ibm.ws.wssecurity.wssapi.token.impl.X509GenerateLoginModule.
Click OK.
- Click JAAS - System logins in
the breadcrumbs to return to the JAAS system logins page.
- Configure your X.509 token generator to use the new JAAS
configuration.
Note: This step assumes that you are stacking on X509GenerateLoginModule
to generate a token. If you want to stack on X509ConsumeLoginModule
to consume a token, you must adjust the steps to accommodate this
variation.
- In the administrative console, open the bindings configuration
that you want to change.
- Select .
- Under Authentication tokens, select the outbound X.509
token that you want to change.
- Under JAAS login, select test.generate.x509.
- Click OK, then Save.
- Restart the application server to apply the JAAS configuration
changes.
- Test the service.