You can use the GenericSecurityTokenFactory APIs to pass a SAML token that you have
created to the SAMLGenerateLoginModule or GenericIssuedTokenGenerateLoginModule modules. You can
also use these APIs to obtain SAML tokens that are consumed by SAMLConsumeLoginModule or
GenericIssuedTokenConsumeLoginModule modules.
Before you begin
You must have a functioning set of JAX-WS service client and provider applications to which you
can add new JAAS login module classes.
About this task
This task generates a SAML 1.1 bearer token, but it can easily be modified to use sender-vouches
and any SAML version supported by the runtime environment.
Although you can stack a login module under SAMLGenerateLoginModule to inspect a SAML token that
has been created by that class, you cannot modify the SAML token that is obtained in this way unless
the token does not contain a digital signature. If you modify a SAML token that contains a digital
signature, the XML for the SAML token will be adjusted for your updates; but, because the token was
signed before you updated it, the signature validation will fail on the receiver.
This task generates a SAML 1.1 bearer token, but you can use any SAML version and type that is
supported by the runtime environment. For more information about creating and modifying SAML tokens
with the GenericSecurityTokenFactory APIs, see Developing SAML applications. For more
information about how to place the token on the client's request context instead of using a JAAS
login module, see the com.ibm.wsspi.wssecurity.token.tokenHolder and
com.ibm.wsspi.wssecurity.token.enableCaptureTokenContext constants in
com.ibm.wsspi.wssecurity.core.Constants.
Since the generator example cannot be easily modified to use holder-of-key, an example of the
createSamlToken() method that is specific for SAML holder-of-key is supplied at the end of this
task.
Procedure
- Create the following generator JAAS login module and make it available to your
application code.
package test.tokens;
import java.util.ArrayList;
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.GenericSecurityTokenFactory;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactory;
import com.ibm.wsspi.wssecurity.saml.config.CredentialConfig;
import com.ibm.wsspi.wssecurity.saml.config.ProviderConfig;
import com.ibm.wsspi.wssecurity.saml.config.RequesterConfig;
import com.ibm.wsspi.wssecurity.saml.data.SAMLAttribute;
import com.ibm.wsspi.wssecurity.core.config.KeyInformationConfig;
import com.ibm.wsspi.wssecurity.core.config.KeyStoreConfig;
import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory;
public class MySamlGenerator implements LoginModule {
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;
try {
factory = GenericSecurityTokenFactory.getInstance();
} catch (Exception e) {
throw new LoginException(e.toString());
}
if (factory == null) {
throw new LoginException("GenericSecurityTokenFactory.getInstance() returned null");
}
SAMLToken myToken = null;
try {
myToken = createSamlToken();
} catch (Exception e) {
throw new LoginException(e.toString());
}
if (myToken == null) {
throw new LoginException("myToken is null");
}
//Put the token in a list on the shared state where it will be available to be used by
//stacked login modules
factory.putGeneratorTokenToSharedState(_sharedState, myToken);
return true;
}
private SAMLToken createSamlToken() throws Exception {
//SAML Bearer example
SAMLTokenFactory samlFactory = SAMLTokenFactory.getInstance(SAMLTokenFactory.WssSamlV11Token11);
RequesterConfig reqData = samlFactory.newBearerTokenGenerateConfig();
reqData.setAuthenticationMethod("Password"); //Authentication method for Assertion
ProviderConfig samlIssuerCfg = samlFactory.newDefaultProviderConfig("self-issue");
CredentialConfig cred = samlFactory.newCredentialConfig ();
cred.setRequesterNameID("Alice"); // SAML NameIdentifier
//Add some SAML attributes:
SAMLAttribute attribute = new SAMLAttribute
("email", new String[] {"joe@websphere"},null, "WebSphere", "email", "joe");
ArrayList<SAMLAttribute> al = new ArrayList<SAMLAttribute>();
al.add(attribute);
attribute = new SAMLAttribute("Membership",
new String[] {"Super users", "My team"}, null, null, null, null );
al.add(attribute);
cred.setSAMLAttributes(al);
SAMLToken samlToken = samlFactory.newSAMLToken(cred, reqData, samlIssuerCfg);
return samlToken;
}
public boolean logout() throws LoginException {
return false;
}
public boolean abort() throws LoginException {
return false;
}
public boolean commit() throws LoginException {
return true;
}
}
- Create the following consumer JAAS login module and make it available to your application
code.
package test.tokens;
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 javax.xml.namespace.QName;
import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactory;
import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
public class MySamlConsumer implements LoginModule {
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;
try {
factory = GenericSecurityTokenFactory.getInstance();
} catch (Exception e) {
throw new LoginException(e.toString());
}
if (factory == null) {
throw new LoginException("GenericSecurityTokenFactory.getInstance() returned null");
}
//Get the token that was consumed by the GenericIssuedConsumeLoginModule
SecurityToken myToken = factory.getConsumerTokenFromSharedState(_sharedState, new QName(SAMLTokenFactory.WssSamlV11Token11));
if (myToken == null) {
throw new LoginException("myToken is null");
}
if (myToken instanceof SAMLToken) {
//Examine the SAML token with SAML APIs
SAMLToken samlToken = (SAMLToken)myToken;
String id = samlToken.getSamlID();
String subjectDns = samlToken.getSubjectDNS();
//...
} else {
throw new LoginException("Did not receive a SAML token");
}
return true;
}
public boolean logout() throws LoginException {
return false;
}
public boolean abort() throws LoginException {
return false;
}
public boolean commit() throws LoginException {
return true;
}
}
- Create a JAAS login configuration.
- In the administrative console, go to .
- Under Authentication, go to .
- Create the SAML token generator.
- Click New, and under Alias, enter
test.generate.saml.
- Under JAAS login modules, click New, and under Module class name, enter
test.tokens.MySamlGenerator. Select Use login module
proxy, and click OK.
- Click New, and under Module class name, enter
com.ibm.ws.wssecurity.wssapi.token.impl.SAMLGenerateLoginModule. Click
OK.
- Create the SAML token consumer.
- Click JAAS - System logins in the breadcrumbs to return to the JAAS
system logins page.
- Click New, and under Alias, enter
test.consume.saml.
- Under JAAS login modules, click New, and under Module class name, enter
com.ibm.ws.wssecurity.wssapi.token.impl.SAMLConsumeLoginModule. Select
Use login module proxy, and click OK.
- Click Save.
- Configure the SAML token generator to use the new JAAS login configuration.
- In the administrative console, open the bindings configuration that you want to
change.
- Select .
- Under Authentication tokens, select the SAML outbound token that you want to
change.
- Under JAAS login, select test.generate.saml.
- Configure the SAML token consumer to use the new JAAS configuration.
- In the administrative console, open the bindings configuration that you want to
change.
- Select .
- Under Authentication tokens, select the SAML inbound token that you want to
change.
- Under JAAS login, select test.consume.saml.
- Click Save.
- Restart the application server to apply the JAAS configuration changes.
- Test the service.
Example
The following example illustrates the createSamlToken() method for creating an asymetric
SAML 2.0 holder-of-key
token.private SAMLToken createSamlToken() throws Exception {
SAMLTokenFactory samlFactory = SAMLTokenFactory.getInstance(SAMLTokenFactory.WssSamlV20Token11);
RequesterConfig reqData = samlFactory.newAsymmetricHolderOfKeyTokenGenerateConfig();
reqData.setAuthenticationMethod("Password"); //Authentication method for Assertion
ProviderConfig samlIssuerCfg = samlFactory.newDefaultProviderConfig("self-issue");
CredentialConfig cred = samlFactory.newCredentialConfig ();
cred.setRequesterNameID("Alice"); // SAML NameIdentifier
// (Optional) If you want to use keystore and key properties other than what
// is set in the SAMLIssuerConfig.properties file, reset the keystore,
// trust store and alias information in the ProviderConfig object.
KeyInformationConfig kic = samlFactory.newKeyInformationConfig("private_key","keypass","CN=Private");
KeyStoreConfig ksc = samlFactory.newKeyStoreConfig("jks","/keystores/myKeystore.ks","storepass");
samlIssuerCfg.setKeyStoreConfig(ksc); //keystore that holds the private key
samlIssuerCfg.setTrustStoreConfig(ksc); //keystore that holds the public key
// Set the alias for the public certificate that must exist in the trust store.
// This alias must not require a password.
reqData.setKeyAliasForRequester("public_cert");
SecurityToken samlToken = samlFactory.newSAMLToken(cred, reqData, samlIssuerCfg);
// Get the private key from the key store
WSSUtilFactory wssufactory = WSSUtilFactory.getInstance();
java.security.KeyStore ks = wssufactory.getKeyStore("jks","/keystores/myKeystore.ks",
"storepass".toCharArray());
java.security.Key privateKey = ks.getKey("private_key", "keypass".toCharArray());
// Add the private key to the token so that the token can be used to sign
// elements in a SOAP message. ((com.ibm.ws.wssecurity.wssapi.token.impl.SecurityTokenImpl)samlToken).
setKey(SecurityToken.SIGNING_KEY, privateKey); ((com.ibm.ws.wssecurity.wssapi.token.impl.SecurityTokenImpl)samlToken).
setKey(SecurityToken.DECRYPTING_KEY, privateKey);
return samlToken;
}