Process Engine Web Service uses WS-Security to pass authentication information, carried as plaintext in a SOAP header. Currently, the supported SOAP headers are the UsernameToken and the Kerberos BinarySecurityToken. These headers need to be present in every SOAP request, and need to be set for your toolkit before you generate source from the WSDL. The Username and Password values from the UsernameToken are authenticated by using the (supported) enterprise directory service.
Use SOAP over HTTPS (SSL) to secure the authentication data. Refer to Setting up Content Platform Engine and client transport SSL security for instructions.
The Process Engine Web Service SOAP header uses the following format:
<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>
For more information about WS-Security, see Web Services Security.
The WS-Security header information is created differently depending on the web services toolkit that you are using. The following examples are for .NET and JAX-WS clients.
.NET
For WSE3.0, for the custom security policy assertion to attach a WS-Security SOAP header to the client's outgoing SOAP message, see the following Microsoft MSDN article: How to: Create a Custom Policy Assertion that Secures SOAP Messages. The following sample code illustrates the implementation of 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)
{
// Disable 100-continue behaviour, to save on the unnecessary
// round trip. Also turn off nagling.
SoapContext ctx = SoapContext.Current;
HttpWebRequest wreq = (HttpWebRequest)ctx.WebRequest;
wreq.ServicePoint.Expect100Continue = false;
wreq.ServicePoint.UseNagleAlgorithm = false;
// Delegate to base (this will call SecureMessage above)
return base.ProcessMessage(envelope);
}
}
/**
* Use this class to insert the WS-Security SOAP header containing
* the authentication information. UserContext should be set with
* some kind of security token.
*/
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;
}
}
}
The following code fragment illustrates how the SecurityPolicyAssertion is assigned to the proxy object:
Policy pePolicy = new Policy(
new PolicyAssertion[]
{
new PEAssertion(peRouter, peLocale),
new PESecurityAssertion(peUsername,pePassword ,theCustomCredentialFlag,theKerberosFlag,theSPN)
}
);
peWSServicePort.SetPolicy(pePolicy);
JAX-WS clients
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);
// add child elements to the root element
wsSecHeaderElm.addChildElement(userNameTokenElm);
// create SOAPHeader instance for SOAP envelope
SOAPHeader sh = envelope.addHeader();
// add SOAP element for header to SOAP header object
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;
}
}
The following code fragment illustrates how the handler can be set in the handler chain for the binding of the proxy object:
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);