GenericSecurityTokenFactory API を使用して、作成した SAML トークンを SAMLGenerateLoginModule または GenericIssuedTokenGenerateLoginModule モジュールに渡すことができます。この API を使用して、SAMLConsumeLoginModule または GenericIssuedTokenConsumeLoginModule モジュールで消費された SAML トークンを取得することもできます。
始める前に
新規 JAAS ログイン・モジュール・クラスを追加できる JAX-WS サービス・クライアントとプロバイダー・アプリケーションの機能セットが必要です。
このタスクについて
このタスクでは、SAML 1.1 bearer トークンを生成しますが、sender-vouches およびランタイム環境でサポートされる任意の SAML バージョンを使用するように簡単に変更できます。
SAMLGenerateLoginModule の下にログイン・モジュールをスタックして、当該クラスで作成された SAML トークンを検査できますが、トークンにデジタル署名が含まれていない場合を除いて、このようにして取得した SAML トークンを変更することはできません。デジタル署名が含まれている SAML トークンを変更した場合、その更新に合わせて SAML トークンの XML が調整されます。ただし、トークンは更新前に署名されているため、受信側で署名の検証は失敗します。
このタスクでは、SAML 1.1 bearer トークンを生成しますが、ランタイム環境でサポートされる任意の SAML バージョンおよびタイプを使用できます。GenericSecurityTokenFactory API を使用した SAML トークンの作成および変更について詳しくは、『SAML アプリケーションの開発』を参照してください。JAAS ログイン・モジュールを使用してトークンを作成するのではなく、クライアントの要求コンテキストにトークンを配置する方法について詳しくは、com.ibm.wsspi.wssecurity.core.Constants の com.ibm.wsspi.wssecurity.token.tokenHolder および com.ibm.wsspi.wssecurity.token.enableCaptureTokenContext 定数を参照してください。
holder-of-key を使用するように生成プログラムの例を簡単に変更できないため、SAML holder-of-key に固有の createSamlToken() メソッドの例を、このタスクの末尾に示します。
手順
- 以下の生成プログラム JAAS ログイン・モジュールを作成し、
アプリケーション・コードで使用できるようにします。
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;
}
}
- 以下のコンシューマー JAAS ログイン・モジュールを作成し、
アプリケーション・コードで使用できるようにします。
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;
}
}
- JAAS ログイン構成を作成します。
- 管理コンソールで、に移動します。
- 「認証」で、に移動します。
- SAML トークン生成プログラムを作成します。
- 「新規」をクリックし、「別名」で test.generate.saml と入力します。
- 「JAAS ログイン・モジュール」で「新規」をクリックし、「モジュール・クラス名」で test.tokens.MySamlGenerator と入力します。
「ログイン・モジュール・プロキシーを使用」を選択し、「OK」をクリックします。
- 「新規」をクリックし、「モジュール・クラス名」で com.ibm.ws.wssecurity.wssapi.token.impl.SAMLGenerateLoginModule と入力します。
「OK」をクリックします。
- SAML トークン・コンシューマーを作成します。
- パンくずリストで「JAAS - システム・ログイン」をクリックして、JAAS システム・ログイン・ページに戻ります。
- 「新規」をクリックし、「別名」で test.consume.saml と入力します。
- 「JAAS ログイン・モジュール」で「新規」をクリックし、「モジュール・クラス名」で com.ibm.ws.wssecurity.wssapi.token.impl.SAMLConsumeLoginModule と入力します。
「ログイン・モジュール・プロキシーを使用」を選択し、「OK」をクリックします。
- 「保存」をクリックします。
- 新しい JAAS ログイン構成を使用するように SAML トークン生成プログラムを構成します。
- 管理コンソールで、変更するバインディング構成を開きます。
- を選択します。
- 認証トークンの下で、変更する SAML アウトバウンド・トークンを選択します。
- 「JAAS ログイン」で test.generate.saml を選択します。
- 新しい JAAS 構成を使用するように SAML トークン・コンシューマーを構成します。
- 管理コンソールで、変更するバインディング構成を開きます。
- を選択します。
- 認証トークンの下で、変更する SAML インバウンド・トークンを選択します。
- 「JAAS ログイン」で test.consume.saml を選択します。
- 「保存」をクリックします。
- アプリケーション・サーバーを再始動して JAAS 構成の変更を適用します。
- サービスをテストします。
例
以下の例では、非対称 SAML 2.0 holder-of-key トークンを作成するための createSamlToken() メソッドを示します。
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;
}