Requiring Multiple Signatures
I've shown you how to use a private key to sign messages to prove that the source of the message is a valid trading partner. In addition, you looked at providing username tokens to identify the application user. But, how do you do both? Using the pre-release WSE 2.0 policy configuration tool, this is not possible. So I took a crack at modifying the policy file by hand, to provide multiple policies for the same endpoint, or to provide multiple token signatures. My attempt failed the XML schema validation for the policy file, which means I also had no luck getting the run time to respect it.
Although in theory this effort should be possible according to the WS-Policy specification, there are still some growing pains you'll experience when you try to add complexity to the way you apply these standards through early adoption tools like WSE 2.0. Because I was unable to use policy to generate the correct XML directly from the client side, I removed the policy from the client altogether and moved to a hand-built implementation that passed a username token and digital signature along with full body encryption.
On the client side, the WSE Web service proxy provides a RequestSoapContext
that make it possible to set and retrieve values applicable to each. To send a message that includes a UsernameToken
without supplying a policy after creating the token object, it is added to the RequestSoapContext.Security.Tokens
collection. In addition, because WSE automatically includes this token in the <wsee:Security>
element, it is required that you indicate the intention to sign the message with the token by creating a Signature object from the message and adding it to the RequestSoapContext.Security.Elements
UsernameToken userToken = new UsernameToken(
new Signature( userToken) );
The WSE run time takes information supplied to the proxy at run time, and serializes it according to the appropriate XML specification. By default, signatures are applied to the following WS-Addressing headers: wsa:Action
, and soap:Body
. In fact, although policy configuration automates many things, by default only the SOAP body is signed unless you edit the policy file manually.
The following code specifies the digital signature token to be applied as a signature as well:
X509SecurityToken sigToken =
new Signature(sigToken) );
And finally, to supply encryption to outgoing messages:
X509SecurityToken encToken =
EncryptedData encData = new
Note that security tokens are added to the security tokens collection for the request context prior to using the token for encryption or message signing as discussed earlier. For encryption, an EncryptedData
element is added to the RequestSoapContext.Security.Elements
To enforce policy on the Web services side, for all three security elements, the best I could do with the WSE 2.0 tool is supply a policy for X.509 signatures and encryption, manually edit the policy file to specify body and header parts to sign, and supply a username token from the calling client without the use of policy enforcement. Because the UsernameTokenManager
is invoked even if the service policy does not require it, I can rely on the username token being validated regardless. Unfortunately, since the policy file does not verify the presence of the username token in this scenario, I must write code to verify whether a security principal has been set before any of my Web service methods execute. You'll see this in the sample code for this article.
Preventing Message Replay: Has This Message Been Sent Before?
After ensuring that the caller is trusted, authenticating the invoking user, and signing and encrypting sensitive parts of a message exchange, there is still the issue of message replay. You can prevent this problem through several approaches. Servers can check for a repeating nonce (sent with symmetric authentication) in relation to the WS-Timestamp value, to see if the message has been replayed. To ensure no tampering with the applicable message parts, a signature is applied to the WS-Timestamp header and applicable tokens.
In a very large-scale solution, sophisticated XML firewalls manage the inspection of messages to detect replay; IP-level Denial of Service (DoS) checking is also performed at the network perimeter, using WSE 2.0 extensibility features that you can provide to custom policy assertions and build your own replay cache. Such an example is provided with the WSE 2.0 pre-release samples, so I integrated this code with my final solution to supply you with a complete scenario that also addresses this final layer of security.
The WSE 2.0 release takes a great crack at demystifying the emerging WS* standards, and provides extensibility for developers to create their own solutions, if necessary, to remain interoperable and keep up with rapid change. In this article, I explored how to leverage WSE 2.0 support for WS-Policy to implement various layers of OASIS WS-Security features, how to manipulate policy files to add support not provided through the WSE tool interface, and how to overcome some of the limitations that exist with the tool today.