WS-Security ヘッダーの作成
Process Engine Web Service は、WS-Security を使用して認証情報を渡します。その情報を渡すときには、SOAP ヘッダーの中で平文として渡します。現在、サポートされる SOAP ヘッダーは、UsernameToken および Kerberos BinarySecurityToken です。これらのヘッダーは、すべての SOAP 要求に組み込む必要があります。さらに、WSDL からソースを生成する前に、ツールキットに対して設定することも必要です。UsernameToken のユーザー名とパスワード値は、サポートされた企業内ディレクトリー・サービスを使用して認証されます。
認証データの機密保護のために、SOAP over HTTPS (SSL) を使用します。詳細については、「Setting up Content Platform Engine and client transport SSL security」を参照してください。
Process Engine Web Service の SOAP ヘッダーは、以下のような形式になります。
<wsse:Security soap:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"
wsu:Id="SecurityToken-0c708387-2e7d-45b5-9029-b1108cf5527e">
<wsse:Username>Administrator</wsse:Username>
<wsse:Password Type="wsse:PasswordText:>secured</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
WS-Security の詳細については、「Web Services Security」を参照してください。
例
WS-Security のヘッダー情報を作成する方法は、使用する Web サービス・ツールキットによって異なります。.NET および JAX-WS クライアントの場合の例を以下に示します。
.NET
WSE3.0 の場合、WS-Security SOAP ヘッダーをクライアントの発信 SOAP メッセージに付加するカスタム・セキュリティーのポリシー・アサーションについて、Microsoft MSDN 記事の「How to: Create a Custom Policy Assertion that Secures SOAP Messages」を参照してください。以下のサンプル・コードでは、SecurityPolicyAssertion の実装について説明します。
using System;
using System.Net;
using System.Collections.Generic;
using System.Text;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Design;
using Microsoft.Web.Services3.Security.Tokens;
using Microsoft.Web.Services3.Security;
namespace PE_C_Sharp_solution
{
internal class SoapSecurityRequestFilter : SendSecurityFilter
{
private String peUsername;
private String pePassword;
private Boolean theCustomCredentialFlag;
private Boolean theKerberosFlag;
private String theSPN;
internal SoapSecurityRequestFilter(
SecurityPolicyAssertion assert)
: base(assert.ClientActor, true)
{
}
internal SoapSecurityRequestFilter(
SecurityPolicyAssertion assert,
String peUsername, String pePassword,
Boolean theCustomCredentialFlag,
Boolean theKerberosFlag, string theSPN)
: base(assert.ClientActor, true)
{
this.peUsername = peUsername;
this.pePassword = pePassword ;
this.theCustomCredentialFlag = theCustomCredentialFlag;
this.theKerberosFlag = theKerberosFlag;
this.theSPN = theSPN;
}
public override void SecureMessage(
SoapEnvelope envelope,
Security security)
{
/**
* Added to test the support for the custom authentication framework.
* This is a very simple custom authentication assuming that Content Platform Engine
* has been set up to do custom authentication given a name and password.
*
* If Kerberos testing is desired, you may want to add the option
* and instantiate a KerberosToken.
*/
SecurityToken tok = null;
if (theCustomCredentialFlag)
{
tok = new CustomBinaryToken(peUsername + "|" + pePassword);
Console.WriteLine("Using Custom Authentication .. " + peUsername);
}
else if (!theKerberosFlag && pePassword != null && pePassword.Trim().Length > 0)
{
tok = new UsernameToken(peUsername, pePassword, PasswordOption.SendPlainText);
Console.WriteLine("Using UsernameToken with " + peUsername);
}
else
Console.WriteLine("Using Kerberos : " + theSPN);
if(theKerberosFlag)
tok = new KerberosToken(theSPN);
if (tok != null)
{
security.Tokens.Add(tok);
}
else
{
throw new Exception("No credentials were set: spn=" + theSPN + ", useKerberos=" +
(theKerberosFlag ? "true" : "false"));
}
}
public override SoapFilterResult ProcessMessage(
SoapEnvelope envelope)
{
// 100-continue 動作を無効にして、不要な往復を削減します。
// また、ナグリングもオフにします。
SoapContext ctx = SoapContext.Current;
HttpWebRequest wreq = (HttpWebRequest)ctx.WebRequest;
wreq.ServicePoint.Expect100Continue = false;
wreq.ServicePoint.UseNagleAlgorithm = false;
// ベースに委任 (これにより上述の SecureMessage が呼び出されます)
return base.ProcessMessage(envelope);
}
}
/**
* Use this class to insert the WS-Security SOAP header containing
* the authentication information. UserContext は、何らかの種類のセキュリティー・トークンを
* 使用して設定する必要があります。
*/
internal class PESecurityAssertion : SecurityPolicyAssertion
{
private String peUsername;
private String pePassword;
private Boolean theCustomCredentialFlag;
private Boolean theKerberosFlag;
private String theSPN;
internal PESecurityAssertion()
: base()
{
}
internal PESecurityAssertion(String peUsername, String pePassword, Boolean theCustomCredentialFlag, Boolean theKerberosFlag, string theSPN)
: base()
{
this.peUsername = peUsername;
this.pePassword = pePassword ;
this.theCustomCredentialFlag = theCustomCredentialFlag;
this.theKerberosFlag = theKerberosFlag;
this.theSPN = theSPN;
}
public override SoapFilter CreateClientOutputFilter(
FilterCreationContext ctx)
{
// return new SoapSecurityRequestFilter(this);
return new SoapSecurityRequestFilter(this, peUsername, pePassword, theCustomCredentialFlag , theKerberosFlag, theSPN);
}
public override SoapFilter CreateClientInputFilter(
FilterCreationContext ctx)
{
return null;
}
public override SoapFilter CreateServiceInputFilter(
FilterCreationContext ctx)
{
return null;
}
public override SoapFilter CreateServiceOutputFilter(
FilterCreationContext ctx)
{
return null;
}
}
}
以下のコード・フラグメントでは、SecurityPolicyAssertion がプロキシー・オブジェクトに割り当てられる方法について説明します。
Policy pePolicy = new Policy(
new PolicyAssertion[]
{
new PEAssertion(peRouter, peLocale),
new PESecurityAssertion(peUsername,pePassword ,theCustomCredentialFlag,theKerberosFlag,theSPN)
}
);
peWSServicePort.SetPolicy(pePolicy);
JAX-WS クライアント
- javax.xml.ws.handler.soap.SOAPHandler クラスを実装します。
- 以下の例に示すように、サービス・プロキシー・オブジェクトのバインディング用にハンドラー・チェーンを設定します。
public class PEWSClientHeaderHandler implements
SOAPHandler<SOAPMessageContext> {
private static final String AUTH_NS = "http://schemas.xmlsoap.org/ws/2002/12/secext";
private static final String AUTH_PREFIX="wss";
public PEWSClientHeaderHandler() {
}
public boolean handleFault(SOAPMessageContext smc)
{
return true;
}
public void close(MessageContext mc)
{
}
public boolean handleMessage(SOAPMessageContext smc) {
boolean direction = ((Boolean) smc
.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY))
.booleanValue();
String userName = (String) smc.get(Const.REQCONTEXT_USERNAME);
String password = (String) smc.get(Const.REQCONTEXT_PASSWORD);
String connectionPoint = (String) smc.get(Const.REQCONTEXT_CONNECTIONPOINT);
String localeInfo = (String)smc.get(Const.REQCONTEXT_LOCALIZATION);
String ceuri = (String)smc.get(Const.REQCONTEXT_BOOTSTRAP_CEURI);
if (direction) {
try {
SOAPEnvelope envelope = smc.getMessage().getSOAPPart()
.getEnvelope();
SOAPFactory soapFactory = SOAPFactory.newInstance();
// WSSecurity <Security> header
SOAPElement wsSecHeaderElm = soapFactory.createElement(
"Security",
AUTH_PREFIX,
AUTH_NS);
SOAPElement userNameTokenElm = soapFactory.createElement("UsernameToken",
AUTH_PREFIX,
AUTH_NS);
SOAPElement userNameElm = soapFactory.createElement("Username",
AUTH_PREFIX,
AUTH_NS);
userNameElm.addTextNode(userName);
SOAPElement passwdElm = soapFactory.createElement("Password",
AUTH_PREFIX,
AUTH_NS);
passwdElm.addTextNode(password);
userNameTokenElm.addChildElement(userNameElm);
userNameTokenElm.addChildElement(passwdElm);
// 子エレメントをルート・エレメントに追加
wsSecHeaderElm.addChildElement(userNameTokenElm);
// SOAP エンベロープの SOAPHeader インスタンスを作成
SOAPHeader sh = envelope.addHeader();
// ヘッダーの SOAP エレメントを SOAP ヘッダー・オブジェクトに追加
sh.addChildElement(wsSecHeaderElm);
// connectionPoint header
if (connectionPoint!=null)
{
SOAPElement cpHeaderElm = soapFactory.createElement(
"Router",
"pe2004",
"http://www.filenet.com/ns/fnpe/2004/06/ws/schema");
cpHeaderElm.addTextNode(connectionPoint);
sh.addChildElement(cpHeaderElm);
}
// locale
if (localeInfo !=null)
{
SOAPElement localHeaderElm = soapFactory.createElement(
"Localization",
"pe2006",
"http://www.filenet.com/ns/fnpe/2006/07/ws/schema");
localHeaderElm.addTextNode(localeInfo);
sh.addChildElement(localHeaderElm);
}
// bootstrap CEURI header -- just added for testing purpose
if (ceuri !=null)
{
SOAPElement ceuriHeaderElm = soapFactory.createElement(
"filenet.pe.bootstrap.ceuri",
"pe2009",
"http://www.filenet.com/ns/fnpe/2009/05/ws/schema");
ceuriHeaderElm.addTextNode(ceuri);
sh.addChildElement(ceuriHeaderElm);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
return true;
}
public java.util.Set<QName> getHeaders() {
return null;
}
}
以下のコード・フラグメントは、プロキシー・オブジェクトのバインディング用に、ハンドラー・チェーン内にハンドラーを設定できる方法について説明します。
ProcessEngineServiceProxy pewsServiceProxy = new ProcessEngineServiceProxy();
pewsServiceProxy._getDescriptor().setEndpoint(url);
// install the handler chain
BindingProvider bp = (BindingProvider) pewsServiceProxy._getDescriptor().getProxy();
Binding pewsBinding = bp.getBinding();
List<Handler> handlerChain = new java.util.ArrayList<Handler>();
PEWSClientHeaderHandler wsSecurity = new PEWSClientHeaderHandler();
handlerChain.add(wsSecurity);
pewsBinding.setHandlerChain(handlerChain);