How to: Specify the Parts of a SOAP Message That Are Signed or Encrypted

WSE allows a developer to control which portions of the SOAP message are signed or encrypted. When you don't specify the portions of the SOAP message to encrypt, WSE encrypts the entire contents of the <Body> element and none of the SOAP headers. For digital signing, WSE signs the entire contents of the <Body> element, the <Timestamp> element of the Security header, and all addressing headers.

These defaults work for the majority of the cases; however, you might add a SOAP header to the SOAP message that contains values that must be secured. For example, a SOAP header containing a business transaction ID that impacts processing by the message recipient might require that its value be signed; so if it is changed, the recipient knows. Besides adding additional elements to be signed, WSE allows you to override the defaults using the SignatureOptions property of the MessageSignature class.

WSE also allows a SOAP message recipient to programmatically determine the portions of the SOAP message that were signed or encrypted. For details, see How to: Determine Which Parts of a SOAP Message Were Signed or Encrypted.

The following procedure contains a sample of adding an Id attribute to a SOAP header.

To add an Id attribute to an XML element

  • Apply a System.Xml.Serialization.XmlAttributeAttribute to the property, field, parameter, or return value representing the XML element being signed or encrypted.

    Set the AttributeName property to "Id" and the Namespace property to "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd". The value of the property, field, parameter, or return value must be a unique identifier within the SOAP message that follows the rules for the xsd:Id type defined at http://www.w3.org/2001/XMLSchema. If the rules are not followed for the xsd:Id type, WSE throws an exception with a message text of "Malformed reference".

    The following code example specifies that when the OrderTimeHeader SOAP header is serialized into XML, the value of the Id field is serialized as an XML attribute for the OrderTimeHeader XML element.

    Note

    Add a using or Imports directive to the System.Xml.Serialization namespace prior to applying an XmlAttribute to the property, field, parameter, or return value.

    Public Class OrderTimeHeader
        Inherits SoapHeader
        ' The following Id field is how you specify a reference.
        <XmlAttribute("Id", [Namespace] := _
          "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")>  _
        Public Id As [String]
    
        Public Created As DateTime
        Public Expires As DateTime
        Public Received As DateTime
    End Class 
    
    public class OrderTimeHeader : SoapHeader
    {
        // The following Id field is how you specify a reference.
        [XmlAttribute("Id",       Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]    public String Id;
    
        public DateTime Created;
        public DateTime Expires;
        public DateTime Received;
    
}

To digitally sign additional XML elements of a SOAP message

  1. Add a security token to the WS-Security SOAP header.

    The following code example is from a Web service client, where an instance of the proxy class has been assigned to a variable named proxy. A security token has been retrieved and assigned to a variable named token. That security token is added to the WS-Security SOAP header.

    proxy.RequestSoapContext.Security.Tokens.Add(token)
    
    proxy.RequestSoapContext.Security.Tokens.Add(token);
    
  2. Create a new instance of the MessageSignature class, passing in the security token.

    Dim sig As New MessageSignature(token)
    
    MessageSignature sig = new MessageSignature(token);
    
  3. Create a new instance, and populate the contents of the SOAP header you want to digitally sign.

    The following code example creates a new instance of and populates an OrderTimeHeader SOAP header.

    Dim header as New OrderTimeHeader()
    header.Created = DateTime.Now
    header.Expires = header.Created.AddMinutes(5)
    
    OrderTimeHeader header = new OrderTimeHeader();
    header.Created = DateTime.Now;
    header.Expires = header.Created.AddMinutes(5);
    
  4. Specify the unique identifier for the SOAP header.

    The following code example populates the Id field of the SOAP header, which is serialized into the Id attribute of the XML element for the SOAP header.

    header.Id = "Id:05d2518d-d6db-481f-846d-2e8872b6e56d"
    
    header.Id = "Id:05d2518d-d6db-481f-846d-2e8872b6e56d";
    
  5. Assign the SOAP header to the member variable of the proxy class representing the SOAP header.

    proxy.OrderTimeHeaderValue = header
    
    proxy.OrderTimeHeaderValue = header;
    
  6. Create a new instance of the SignatureReference class, passing in the value of the Id field with a # symbol prefix.

    Dim soapRef As New SignatureReference( _
      "#Id:05d2518d-d6db-481f-846d-2e8872b6e56d") 
    soapRef.AddTransform( New Microsoft.Web.Services2.Security.Xml.XmlDsigExcC14NTransform() )
    
    SignatureReference soapRef = new SignatureReference("#Id:05d2518d-d6db-481f-846d-2e8872b6e56d");
    soapRef.AddTransform( new Microsoft.Web.Services2.Security.Xml.XmlDsigExcC14NTransform() );
    
  7. Add the instance of the SignatureReference class to the MessageSignature, using the AddReference method.

    sig.AddReference(soapRef)
    
    sig.AddReference(soapRef);
    
  8. Add the MessageSignature to the WS-Security SOAP header to the SOAP message.

    proxy.RequestSoapContext.Security.Elements.Add(sig)
    
    proxy.RequestSoapContext.Security.Elements.Add(sig);
    
  9. Send the SOAP message.

    The following code example communicates with the Web service using the proxy class.

    Return.Text = proxy.EchoString(Send.Text)
    
    Return.Text = proxy.EchoString(Send.Text);
    

To encrypt additional XML elements of a SOAP message

  1. Create a new instance, and populate the contents of the SOAP header you want to encrypt.

    When you are encrypting a SOAP response from a Web service, add a member variable to the class implementing the Web service of the SOAP header type containing the Id field. Next apply a SoapHeaderAttribute attribute to the Web service method, specifying the member variable and setting the Direction property. Set the Direction property to SoapHeaderDirection.InOut if the SOAP header is sent to both the Web service and the client, or SoapHeaderDirection.Out if the client is the only recipient.

    The following code example adds a member variable named referencedSOAPheader representing the SOAP header and then applies an SoapHeaderAttribute to the Web service method, specifying that the contents of the SOAP header is stored in the referencedSOAPheader member variable.

    Public Class Service1
      Inherits System.Web.Services.WebService
        Public referencedSOAPheader As OrderTimeHeader
    
        <WebMethod(), SoapHeader("referencedSOAPheader", _
          Direction := SoapHeaderDirection.InOut)>  _
        Public Function EchoString(str As [String]) As String
    
    public class Service1 : System.Web.Services.WebService
    {
       public OrderTimeHeader referencedSOAPheader;
       [WebMethod]
       [SoapHeader("referencedSOAPheader",
         Direction=SoapHeaderDirection.InOut)]
       public string EchoString( String str )
    
  2. Create or get an instance of a security token.

    The following code example assumes that a Web service has digitally signed the SOAP message using an X.509 certificate when it called the Web service. Because the SOAP message was digitally signed, the public key for the X.509 certificate was passed in the SOAP message and is available. That public key can be used to encrypt the SOAP response, as we know the client has the private key to decrypt the SOAP message.

    Dim token As X509SecurityToken
    For Each token In  context.Security.Tokens
       If Not (token Is Nothing) Then
          tok = token
       End If
    Next token
    
    foreach( X509SecurityToken token in context.Security.Tokens)
    {
       if( token != null )
       {
          tok = token;
       }
    }
    
  3. Specify the unique identifier for the SOAP header.

    The following code example sets the Id field of the referencedSOAPheader member variable representing the SOAP header.

    referencedSOAPheader.Id = "Id:05d2518d-d6db-481f-846d-2e8872b6e56d"
    
    referencedSOAPheader.Id = "Id:05d2518d-d6db-481f-846d-2e8872b6e56d";
    
  4. Create a new instance of the EncryptedData class, passing in the security token and the unique identifier with a # sign prefix.

    Dim enc As New EncryptedData(tok, _
      "#Id:05d2518d-d6db-481f-846d-2e8872b6e56d")
    
    EncryptedData enc = new EncryptedData(tok, 
      "#Id:05d2518d-d6db-481f-846d-2e8872b6e56d" );
    
  5. Add the instance of EncryptedData to the SOAP response.

    The following code example gets the SoapContext for the SOAP response, using the static Current method of RequestSoapContext and adds the EncryptedData to it.

    RequestSoapContext.Current.Security.Elements.Add(enc)
    
    RequestSoapContext.Current.Security.Elements.Add(enc);
    

See Also

Tasks

How to: Digitally Sign a SOAP Message
How to: Encrypt a SOAP Message
How to: Determine Which Parts of a SOAP Message Were Signed or Encrypted