外部セキュリティー・トークン・サービス (STS) から、bearer サブジェクト確認方式を使用して SAML トークンを要求することができます。SAML bearer トークンの取得後に、Java™ API for XML-Based Web Services (JAX-WS) プログラミング・モデルおよび Web Services Security API (WSS API) を使用して、Web サービス要求メッセージでそのトークンを送信できます。
始める前に
この作業では、JAX-WS プログラミング・モデル、WSS API インターフェース、SAML の概念、および Web サービスの設定を構成および管理するためのポリシー・セットの使用について、ユーザーが十分な知識を持っていることが前提になります。
このタスクについて
bearer サブジェクト確認方式を使用して SAML トークンを外部 STS に要求し、その SAML トークンを Web サービス要求メッセージに入れ、Web サービス・クライアントから WSS API を使用して 送信することができます。
このタスクで使用される Web サービス・アプリケーション・クライアントは、ダウンロードで入手可能な JaxWSServicesSamples サンプル・アプリケーションに含まれているクライアント・コードに変更を加えたバージョンです。手順のセクションではサンプルから抜粋したコード・スニペットについて説明していますが、
すぐに使用できる完全な Web サービス・クライアントのサンプルがサンプルのセクションに記載されています。
手順
- Web サービス・プロバイダーを呼び出すために使用する Web サービス・クライアントを特定し、取得します。
このクライアントを使用して、
プログラムで WSS API を使用することによって SAML トークンを SOAP 要求メッセージに
挿入します。
この手順で使用される Web サービス・クライアントは、JaxWSServicesSamples Web サービス・サンプル・アプリケーションに含まれるクライアント・コードの変更版です。
サンプル Web サービス・クライアントを取得し、変更することによって、プログラムで WSS API を使用して SOAP 要求メッセージで SAML トークンを渡すための Web Services Security API を追加するには、以下のステップを実行します。
- JaxWSServicesSamples サンプル・アプリケーションをダウンロードします。 JaxWSServicesSamples サンプルは、デフォルトではインストールされません。
- JaxWSServicesSamples クライアント・コードを取得します。
例を示すため、この手順では、JaxWSServicesSamples サンプルに含まれている Echo シン・クライアント・サンプル
の変更版を使用します。
Web サービス Echo シン・クライアント・サンプル・ファイル SampleClient.java は、src¥SampleClientSei¥src¥com¥ibm¥was¥wssample¥sei¥cli ディレクトリーにあります。
サンプル・クラス・ファイルは、WSSampleClientSei.jar ファイルに含まれています。
JaxWSServicesSamples.ear エンタープライズ・アプリケーションおよびそれをサポートする Java アーカイブ (JAR) ファイルは、JaxWSServicesSamples サンプル・アプリケーション内の installableApps ディレクトリーにあります。
- アプリケーション・サーバーに JaxWSServicesSamples.ear ファイルをデプロイします。 JaxWSServicesSamples.ear ファイルをデプロイしたら、サンプル Web サービス・クライアント・コードを、サンプル・アプリケーションに対してテストする準備ができたことになります。
Web サービス・クライアント・サンプルを使用する代わりに、
ご使用の Web サービス・クライアント・アプリケーションの WSS API を使用して、プログラムで SOAP 要求メッセージの SAML トークンを渡すためにコード・スニペットを追加することもできます。この手順中の例では JAX-WS Web サービス・シン・クライアントが使用されていますが、管理対象クライアントを使用することもできます。
- SAML20 Bearer WSHTTPS default ポリシー・セットを Web サービス・プロバイダーに関連付けます。 このポリシー・セットは、
HTTPS トランスポートを使用してメッセージを保護するために使用されます。SAML20 Bearer WSHTTPS default ポリシー・セットを Web サービス・プロバイダーに関連付ける方法について詳しくは、『SAML bearer トークン用のクライアントおよびプロバイダーのバインディングの構成』を参照してください。
- SAML Bearer Provider sample default 汎用バインディングをサンプル Web サービス・プロバイダーに割り当てます。 SAML Bearer Provider sample default 汎用バインディングを Web サービス・アプリケーションに割り当てる方法について詳しくは、『SAML bearer トークン用のクライアントおよびプロバイダーのバインディングの構成』を参照してください。
- trustStoreType、trustStorePassword、trustStorePath の各カスタム・プロパティーが、
STS 署名者証明書が含まれるトラストストアに対応していることを確認します。 管理コンソールを使用して、以下のステップを実行します。
- とクリックします。
- 認証トークンの表で「gen_saml11token」をクリックします。
- 「コールバック・ハンドラー」をクリックします。
- 「カスタム・プロパティー」セクションで、trustStoreType、trustStorePassword、trustStorePath の各カスタム・プロパティーが、STS 署名者証明書が含まれるトラストストアに対応していることを確認します。
- 外部 STS から SAML トークンを要求します。 以下のコード・スニペットは、SAML トークンを要求する方法を示しています。
この例では、外部 STS が、UsernameToken を受け取って検証した後で SAML 2.0 トークンを発行するように構成されていることを前提としています。
//Request the SAML Token from external STS
WSSFactory factory = WSSFactory.getInstance();
String STS_URI = "https://externalstsserverurl:port/TrustServerWST13/services/RequestSecurityToken";
String ENDPOINT_URL = "http://localhost:9080/WSSampleSei/EchoService";
WSSGenerationContext gencont1 = factory.newWSSGenerationContext();
WSSConsumingContext concont1 = factory.newWSSConsumingContext();
HashMap<Object, Object> cbackMap1 = new HashMap<Object, Object>();
cbackMap1.put(SamlConstants.STS_ADDRESS, STS_URI);
cbackMap1.put(SamlConstants.SAML_APPLIES_TO, ENDPOINT_URL);
cbackMap1.put(SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE, "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
cbackMap1.put(SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST, "false");
cbackMap1.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
cbackMap1.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
SAMLGenerateCallbackHandler cbHandler1 = new SAMLGenerateCallbackHandler(cbackMap1);
// Add UNT to trust request
UNTGenerateCallbackHandler utCallbackHandler = new UNTGenerateCallbackHandler("testuser", "testuserpwd");
SecurityToken ut = factory.newSecurityToken(UsernameToken.class, utCallbackHandler);
gencont1.add(ut);
cbHandler1.setWSSConsumingContextForTrustClient(concont1);
cbHandler1.setWSSGenerationContextForTrustClient(gencont1);
SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, cbHandler1, "system.wss.generate.saml");
System.out.println("SAMLToken id = " + samlToken.getId());
- Thin Client for JAX-WS JAR ファイルをクラスパスに追加します。 app_server_root/runtimes/com.ibm.jaxws.thinclient_8.5.0.jar ファイルをクラスパスに追加します。この JAR ファイルのクラスパスへの追加について詳しくは、『Web サービス対応クライアントのテスト』を参照してください。
- WSSFactory newSecurityToken メソッドを使用して、
外部 STS から SAML トークンを要求します。
SAML トークンを要求するため、以下のメソッドを指定してください。
WSSFactory newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml")
SAML トークンの要求には、Java セキュリティー
権限 wssapi.SAMLTokenFactory.newSAMLToken が必要です。ポリシー・ツールを
使用して、以下のポリシー・ステートメントを Java セキュリティー・ポリシー・ファイルまたは
アプリケーション・クライアント was.policy ファイルに追加してください。
permission java.security.SecurityPermission "wssapi.SAMLTokenFactory.newSAMLToken"
SAMLToken.class パラメーター
は、作成するセキュリティー・トークンのタイプを指定します。
callbackHandler オブジェクトには、要求する SAML トークンの特性を定義するパラメーターと、
STS に到達し SAML トークンを取得するために必要なその他のパラメーターが含まれます。SAMLGenerateCallbackHandler オブジェクトは、次の表に示す構成パラメーターを指定します。
表 1. SAMLGenerateCallbackHandler プロパティー. この表は、
bearer サブジェクト確認方式を使用する SAMLGenerateCallbackHandler オブジェクトの
構成パラメーターを示します。プロパティー |
説明 |
必須 |
SamlConstants.CONFIRMATION_METHOD |
Bearer 確認方式の使用を指定します。 |
はい |
SamlConstants.TOKEN_TYPE |
トークン・タイプを指定します。
Web サービス・クライアントにポリシー・セットが関連付けられている場合、Web Services Security ランタイム環境はこのプロパティーを使用しません。
tokenGenerator バインディング構成の valueType 属性を使用して、
トークン・タイプの値を指定します。
この手順中の例では SAML 2.0 トークン
が使用されていますが、WSSConstants.SAML.SAML11_VALUE_TYPE 値を使用することもできます。
|
はい |
SamlConstants.STS_ADDRESS |
セキュリティー・トークン・サービスのアドレスを指定します。
このタスク・トピックで使用されている例では、
このプロパティーの値は https に設定されており、
SSL を使用して SAML トークン要求を保護することを指定しています。
STS による SAML トークン要求
を SSL を使用して保護できるようにするためには、-Dcom.ibm.SSL.ConfigURL プロパティーを設定する必要があります。
|
はい |
SamlConstants.SAML_APPLIES_TO |
SAML トークンを使用するためのターゲット STS アドレスを指定します。 |
いいえ |
SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST |
STS から要求するトークンが、
RequestSecurityToken (RST) エレメントに含まれる単一のトークンであるか、
または単一の RequestSecurityTokenCollection (RSTC) エレメントに含まれる RST エレメントの
コレクション内の複数のトークンであるかを指定します。 デフォルトの動作では、
RequestSecurityToken (RST) エレメントに含まれる単一のトークンを STS から要求します。
このプロパティーに値 true を指定すると、
単一の RequestSecurityTokenCollection (RSTC) エレメントに含まれる RST エレメントの
コレクション内の複数のトークンを STS から要求することを示します。
|
いいえ |
SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE |
WS-Trust 要求に組み込まれる WS-Trust 名前空間を指定します。 |
いいえ |
WSSGenerationContext インスタンスおよび WSSConsumingContext インスタンス
も SAMLGenerateCallbackHandler オブジェクトに設定されています。WSSGenerationContext インスタンスには、STS に送信したい UsernameToken を作成するための情報が指定された UNTGenerateCallbackHandler オブジェクトが含まれている必要があります。
system.wss.generate.saml パラメーターは、SAML トークンの作成に使用される Java Authentication
and Authorization Service (JAAS) ログイン・モジュールを指定します。次の例のように、必要な JAAS ログイン構成を含んでいる JAAS 構成ファイルを定義するため、JVM プロパティー
を指定する必要があります。
-Djava.security.auth.login.config=profile_root/properties/wsjaas_client.conf
あるいは、サンプル・クライアント・コードに Java システム・プロパティーを設定することによって JAAS ログイン構成ファイルを指定することもできます。例えば、以下のようになります。
System.setProperty("java.security.auth.login.config", "profile_root/properties/wsjaas_client.conf");
- 作成された SAML トークンのトークン ID を取得します。
以下のステートメントを、作成した SAML トークンの簡単なテストとして使用できます。
System.out.println("SAMLToken id = " + samlToken.getId())
- SAML トークンを、Web サービス要求メッセージの SOAP セキュリティー・ヘッダーに追加します。
- Web サービス・クライアントを初期化し、SOAPAction プロパティーを構成します。 以下のコード・スニペットは、これらのアクションを示しています。
// Initialize web services client
EchoService12PortProxy echo = new EchoService12PortProxy();
echo._getDescriptor().setEndpoint(endpointURL);
// Configure SOAPAction properties
BindingProvider bp = (BindingProvider) (echo._getDescriptor().getProxy());
Map<String, Object> requestContext = bp.getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "echoOperation");
- WSSGenerationContext を初期化します。 以下のコードは、WSSGenerationContext インターフェースを使用して、生成コンテキストを初期化し、SAMLToken を Web サービス要求メッセージに挿入できるようにする方法を示します。
// Initialize WSSGenerationContext
WSSGenerationContext gencont = factory.newWSSGenerationContext();
gencont.add(samlToken);
具体的には、
gencont.add(samlToken) メソッド呼び出し
が、SAML トークンを要求メッセージに入れることを指定しています。ポリシー・ツールを
使用して、以下のポリシー・ステートメントを Java セキュリティー・ポリシー・ファイルまたは
アプリケーション・クライアント was.policy ファイルに追加してください。
permission javax.security.auth.AuthPermission "modifyPrivateCredentials"
- SOAP メッセージ・セキュリティー・ヘッダーにタイム・スタンプ・エレメントを
追加します。 SAML20 Bearer WSHTTPS default ポリシー・セットは、Web サービス要求メッセージおよび応答メッセージが SOAP メッセージのセキュリティー・ヘッダー内にタイム・スタンプ・エレメントを含んでいることを必要とします。以下のコード・スニペットでは、factory.newWSSTimestamp() メソッド呼び出し
がタイム・スタンプを生成し、gencont.add(timestamp) メソッド呼び出し
がタイム・スタンプを要求メッセージに入れることを指定しています。
// Add a timestamp to the request message.
WSSTimestamp timestamp = factory.newWSSTimestamp();
gencont.add(timestamp);
gencont.process(requestContext);
- WSSGenerationContext オブジェクトを Web サービス RequestContext オブジェクトに関連付けます。 これで、WSSGenerationContext オブジェクト
は、要求メッセージをフォーマットするのに必要なすべてのセキュリティー情報
を含んでいる状態になります。次の例のように、gencont.process(requestContext) メソッド呼び出しは WSSGenerationContext オブジェクトを Web サービス RequestContext オブジェクトに関連付けて、必要な SOAP セキュリティー・ヘッダーを Web Services Security ランタイム環境がフォーマットできるようにします。
// Attaches WSSGenerationContext object to the Web services RequestContext object.
gencont.process(requestContext);
- JVM プロパティーを使用して SSL トランスポート・レベル・メッセージ保護を指定します。
SAML20 Bearer WSHTTPS default ポリシー・セットは、SSL を使用するトランスポート・レベル・メッセージ保護を必要とします。また、この同じプロパティーを使用して、STS に対する SAML トークン要求の SSL による保護を
有効にすることができます。次の JVM プロパティーを使用して SSL トランスポート・レベル・メッセージ保護を指定してください。
-Dcom.ibm.SSL.ConfigURL=file:profile_root\properties\ssl.client.props
あるいは、サンプル・クライアント・コードに Java システム・プロパティーを使用して、SSL 構成ファイルを定義することもできます。例えば、以下のようになります。
System.setProperty("com.ibm.SSL.ConfigURL", "file:profile_root/properties/ssl.client.props");
タスクの結果
外部 STS から、 SAML トークンを、トランスポート・レベルで保護し、bearer サブジェクト確認方式を使用して要求しました。トークンの取得後に、JAX-WS プログラミング・モデルおよび WSS API を使用して、Web サービス要求メッセージでトークンを送信しました。
メッセージ・レベルで保護された bearer サブジェクト確認方式の SAML トークンを外部 STS に要求する場合は、WSS API およびメッセージ・レベル保護を使用した、外部 STS に対する SAML sender-vouches トークンの要求に関する資料を参照してください。bearer サブジェクト確認方式の SAML トークンにメッセージ・レベル保護を使用する場合は、
外部 STS から SAML トークンを要求するステップで、確認方式として
sender-vouches ではなく、
Bearer を指定してください。例えば、以下のようにします。
//Request the SAML Token from external STS
WSSFactory factory = WSSFactory.getInstance();
String STS_URI = "https://externalstsserverurl:port/TrustServerWST13/services/RequestSecurityToken";
String ENDPOINT_URL = "http://localhost:9080/WSSampleSei/EchoService";
WSSGenerationContext gencont1 = factory.newWSSGenerationContext();
WSSConsumingContext concont1 = factory.newWSSConsumingContext();
HashMap<Object, Object> cbackMap1 = new HashMap<Object, Object>();
cbackMap1.put(SamlConstants.STS_ADDRESS, STS_URI);
cbackMap1.put(SamlConstants.SAML_APPLIES_TO, ENDPOINT_URL);
cbackMap1.put(SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE, "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
cbackMap1.put(SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST, "false");
cbackMap1.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML11_VALUE_TYPE);
cbackMap1.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
SAMLGenerateCallbackHandler cbHandler1 = new SAMLGenerateCallbackHandler(cbackMap1);
// Add UNT to trust request
UNTGenerateCallbackHandler utCallbackHandler = new UNTGenerateCallbackHandler("testuser", "testuserpwd");
SecurityToken ut = factory.newSecurityToken(UsernameToken.class, utCallbackHandler);
gencont1.add(ut);
cbHandler1.setWSSConsumingContextForTrustClient(concont1);
cbHandler1.setWSSGenerationContextForTrustClient(gencont1);
SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, cbHandler1, "system.wss.generate.saml");
System.out.println("SAMLToken id = " + samlToken.getId());
また、応答メッセージ内のデジタル署名の検査を構成するステップは、
bearer トークンの場合はオプションです。
例
以下のコード例は、外部 STS に SAML トークンを要求し、
その SAML トークンを Web サービス要求メッセージで送信する方法を示す Web サービス・クライアント・アプリケーションの例です。SAML トークンは必要だが、アプリケーションが Web サービス・メッセージを使用して SAML トークンを渡す必要はないという使用シナリオの場合は、以下のサンプル・コードの前半部分のみ (// Initialize Web services client セクションまで) を使用すればすみます。
/**
* The following source code is sample code created by IBM Corporation.
* This sample code is provided to you solely for the purpose of assisting you in the
* use of the technology. The code is provided 'AS IS', without warranty or condition of
* any kind. IBM shall not be liable for any damages arising out of your use of the
* sample code, even if IBM has been advised of the possibility of such damages.
*/
package com.ibm.was.wssample.sei.cli;
import com.ibm.was.wssample.sei.echo.EchoService12PortProxy;
import com.ibm.was.wssample.sei.echo.EchoStringInput;
import com.ibm.websphere.wssecurity.wssapi.WSSFactory;
import com.ibm.websphere.wssecurity.wssapi.WSSGenerationContext;
import com.ibm.websphere.wssecurity.wssapi.WSSConsumingContext;
import com.ibm.websphere.wssecurity.wssapi.WSSTimestamp;
import com.ibm.websphere.wssecurity.callbackhandler.SAMLGenerateCallbackHandler;
import com.ibm.websphere.wssecurity.callbackhandler.UNTGenerateCallbackHandler;
import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
import com.ibm.wsspi.wssecurity.core.token.config.WSSConstants;
import com.ibm.wsspi.wssecurity.saml.config.SamlConstants;
import java.util.Map;
import java.util.HashMap;
import javax.xml.ws.BindingProvider;
/**
* SampleClient
* main entry point for thin client JAR sample
* and worker class to communicate with the services
*/
public class SampleClient {
private String urlHost = "localhost";
private String urlPort = "9443";
private static final String CONTEXT_BASE = "/WSSampleSei/";
private static final String ECHO_CONTEXT12 = CONTEXT_BASE+"EchoService12";
private String message = "HELLO";
private String uriString = "https://" + urlHost + ":" + urlPort;
private String endpointURL = uriString + ECHO_CONTEXT12;
private String input = message;
/**
* main()
*
* see printusage() for command-line arguments
*
* @param args
*/
public static void main(String[] args) {
SampleClient sample = new SampleClient();
sample.CallService();
}
/**
* CallService Parms were already read. Now call the service proxy classes
*
*/
void CallService() {
String response = "ERROR!:";
try {
System.setProperty("java.security.auth.login.config", "profile_root/properties/wsjaas_client.conf ");
System.setProperty("com.ibm.SSL.ConfigURL", "file:profile_root/properties/ssl.client.props");
//Request the SAML Token from external STS
WSSFactory factory = WSSFactory.getInstance();
String STS_URI = "https://externalstsserverurl:port/TrustServerWST13/services/RequestSecurityToken";
String ENDPOINT_URL = "http://localhost:9080/WSSampleSei/EchoService";
WSSGenerationContext gencont1 = factory.newWSSGenerationContext();
WSSConsumingContext concont1 = factory.newWSSConsumingContext();
HashMap<Object, Object> cbackMap1 = new HashMap<Object, Object>();
cbackMap1.put(SamlConstants.STS_ADDRESS, STS_URI);
cbackMap1.put(SamlConstants.SAML_APPLIES_TO, ENDPOINT_URL);
cbackMap1.put(SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE, "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
cbackMap1.put(SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST, "false");
cbackMap1.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
cbackMap1.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
SAMLGenerateCallbackHandler cbHandler1 = new SAMLGenerateCallbackHandler(cbackMap1);
// Add UNT to trust request
UNTGenerateCallbackHandler utCallbackHandler = new UNTGenerateCallbackHandler("testuser", "testuserpwd");
SecurityToken ut = factory.newSecurityToken(UsernameToken.class, utCallbackHandler);
gencont1.add(ut);
cbHandler1.setWSSConsumingContextForTrustClient(concont1);
cbHandler1.setWSSGenerationContextForTrustClient(gencont1);
SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, cbHandler1, "system.wss.generate.saml");
System.out.println("SAMLToken id = " + samlToken.getId());
// Initialize web services client
EchoService12PortProxy echo = new EchoService12PortProxy();
echo._getDescriptor().setEndpoint(endpointURL);
// Configure SOAPAction properties
BindingProvider bp = (BindingProvider) (echo._getDescriptor().getProxy());
Map<String, Object> requestContext = bp.getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "echoOperation");
// Initialize WSSGenerationContext
WSSGenerationContext gencont = factory.newWSSGenerationContext();
gencont.add(samlToken);
// Add timestamp
WSSTimestamp timestamp = factory.newWSSTimestamp();
gencont.add(timestamp);
gencont.process(requestContext);
// Build the input object
EchoStringInput echoParm =
new com.ibm.was.wssample.sei.echo.ObjectFactory().createEchoStringInput();
echoParm.setEchoInput(input);
System.out.println(">> CLIENT: SEI Echo to " + endpointURL);
// Prepare to consume timestamp in response message.
WSSConsumingContext concont = factory.newWSSConsumingContext();
concont.add(WSSConsumingContext.TIMESTAMP);
concont.process(requestContext);
// Call the service
response = echo.echoOperation(echoParm).getEchoResponse();
System.out.println(">> CLIENT: SEI Echo invocation complete.");
System.out.println(">> CLIENT: SEI Echo response is: " + response);
} catch (Exception e) {
System.out.println(">> CLIENT: ERROR: SEI Echo EXCEPTION.");
e.printStackTrace();
}
}
}
この Web サービス・クライアント・アプリケーション・サンプルが正しく実行された場合、次のようなメッセージを受け取ります。
SAMLToken id = _191EBC44865015D9AB1270745072344
Retrieving document at 'file:profile_root/.../wsdl/'.
>> CLIENT: SEI Echo to https://localhost:9443/WSSampleSei/EchoService12
>> CLIENT: SEI Echo invocation complete.
>> CLIENT: SEI Echo response is: SOAP12==>>HELLO