How to: Create a Custom Policy Assertion that does not Secure SOAP Messages

Create a custom policy assertion to modify or inspect SOAP messages when one of the Turnkey Security Assertions does not meet the application's needs.

There are two categories of custom policy assertions: Those that secure SOAP messages and those that do not. This topic provides the steps for creating a custom policy assertion that does not secure SOAP messages. The procedure creates a custom policy assertion that traces the SOAP messages that are exchanged between a client and a Web service. For details about creating a custom policy assertion that secures SOAP messages, see How to: Create a Custom Policy Assertion that Secures SOAP Messages.

To create a custom policy assertion that does not secure SOAP messages

  1. Open the project that contains the Web service.

  2. Add a new class to the project.

    1. In Solution Explorer, right-click the project name, and then click Add New Item….
    2. Select Class and provide a name for the class.
    3. Click Add to dismiss the dialog and add the class to the project.
  3. Add references to the Microsoft.Web.Services3, System.Web.Services, System.Security, and System.Xml assemblies.

    1. In Solution Explorer, right-click the project name, and then click Add Reference.
    2. Click the .NET tab, press and hold the CTRL key, and click Microsoft.Web.Services3.dll, System.Web.Services.dll, System.Security.dll, and System.Xml.dll.
    3. Click OK to dismiss the dialog.
  4. Add the Imports statements or using directives that are shown in the following code example to the top of the file for the new class.

    Imports System
    Imports System.IO
    Imports System.Xml
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.Security.Cryptography.X509Certificates
    
    Imports Microsoft.Web.Services3
    Imports Microsoft.Web.Services3.Design
    Imports Microsoft.Web.Services3.Security
    Imports Microsoft.Web.Services3.Security.Tokens
    
    using System;
    using System.IO;
    using System.Xml;
    using System.Collections.Generic;
    using System.Text;
    using System.Security.Cryptography.X509Certificates;
    
    using Microsoft.Web.Services3;
    using Microsoft.Web.Services3.Design;
    using Microsoft.Web.Services3.Security;
    using Microsoft.Web.Services3.Security.Tokens;
    
  5. Create custom filters for the Web service and client.

    When the custom filters are not securing SOAP messages, the filters are classes that derive from the SoapFilter class.

    The following steps detail how to implement a custom filter that derives from the SoapFilter class.

    1. Add a class that derives from the SoapFilter class.
      The following code example defines a class that derives from the SoapFilter class.

      Class CustomTraceFilter
          Inherits SoapFilter
      
      class CustomTraceFilter : SoapFilter
      
    2. Transform or view the SOAP message by overriding the ProcessMessage method.
      A SoapEnvelope that represents the SOAP message is passed to the ProcessMessage method.
      The following code example logs the SOAP message to a file.

      Public Overrides Function ProcessMessage(ByVal envelope As SoapEnvelope) As SoapFilterResult
          Dim dom As XmlDocument = Nothing
      
          Dim timeStamp As DateTime = DateTime.Now
          Dim rootNode As XmlNode = Nothing
      
          dom = New XmlDocument()
      
          If Not File.Exists(filename) Then
              Dim xmlDecl As XmlDeclaration = dom.CreateXmlDeclaration("1.0", "utf-8", Nothing)
      
              dom.InsertBefore(xmlDecl, dom.DocumentElement)
      
              rootNode = dom.CreateNode(XmlNodeType.Element, "log", String.Empty)
              dom.AppendChild(rootNode)
              dom.Save(filename)
          Else
              dom.Load(filename)
              rootNode = dom.DocumentElement
          End If
      
          Dim newNode As XmlNode = dom.ImportNode(envelope.DocumentElement, True)
          rootNode.AppendChild(newNode)
      
          dom.Save(filename)
      
          Return SoapFilterResult.Continue
      End Function 'ProcessMessage
      
      public override SoapFilterResult ProcessMessage(SoapEnvelope envelope)
      {
          XmlDocument dom = null;
          DateTime timeStamp = DateTime.Now;
          XmlNode rootNode = null;
      
          dom = new XmlDocument();
      
          if (!File.Exists(filename))
          {
              XmlDeclaration xmlDecl = dom.CreateXmlDeclaration("1.0", "utf-8", null);
      
              dom.InsertBefore(xmlDecl, dom.DocumentElement);
      
              rootNode = dom.CreateNode(XmlNodeType.Element, "log", String.Empty);
              dom.AppendChild(rootNode);
              dom.Save(filename);
          }
          else
          {
              dom.Load(filename);
              rootNode = dom.DocumentElement;
          }
      
      
          XmlNode newNode = dom.ImportNode(envelope.DocumentElement, true);
          rootNode.AppendChild(newNode);
      
          dom.Save(filename );
      
          return SoapFilterResult.Continue;
      }
      
  6. Create a class that represents the custom policy assertion.

    1. Create a class that derives from the PolicyAssertion class.
      The following code example defines a class that derives from the PolicyAssertion class.

      Class CustomTraceAssertion
          Inherits PolicyAssertion
      
      class CustomTraceAssertion : PolicyAssertion
      
    2. Specify the Web service's custom input filter by overriding the CreateServiceInputFilter method.
      The following code example adds a custom input filter for the Web service.

      Public Overrides Function CreateServiceInputFilter(ByVal context As FilterCreationContext) As SoapFilter
          Return New CustomTraceFilter("serverinput.xml")
      End Function 'CreateServiceInputFilter
      
      public override SoapFilter CreateServiceInputFilter(FilterCreationContext context)
      {
          return new CustomTraceFilter(inputfile);
      }
      
    3. Specify the Web service's custom output filter by overriding the CreateServiceOutputFilter method.
      The following code example adds a custom output filter for the Web service.

      Public Overrides Function CreateServiceOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
          Return New CustomTraceFilter("serveroutput.xml")
      End Function 'CreateServiceOutputFilter
      
      public override SoapFilter CreateServiceOutputFilter(FilterCreationContext context)
      {
          return new CustomTraceFilter(outputfile);
      }
      
    4. Specify the client's custom input filter by overriding the CreateClientInputFilter method.
      The following code example adds a custom input filter for the client.

      Public Overrides Function CreateClientInputFilter(ByVal context As FilterCreationContext) As SoapFilter
          Return New CustomTraceFilter("clientinput.xml")
      End Function 'CreateClientInputFilter
      
      public override SoapFilter CreateClientInputFilter(FilterCreationContext context)
      {
          return new CustomTraceFilter(inputfile);
      }
      
    5. Specify the client's custom output filter by overriding the CreateClientOutputFilter method.
      The following code example adds a custom output filter for the client.

      Public Overrides Function CreateClientOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
          Return New CustomTraceFilter("clientoutput.xml")
      End Function 'CreateClientOutputFilter
      
      public override SoapFilter CreateClientOutputFilter(FilterCreationContext context)
      {
          return new CustomTraceFilter(outputfile);
      }
      
    6. Add code to parse the custom XML elements and attributes that can be placed in a policy file for this custom policy assertion by overriding the ReadXml and GetExtensions methods..
      Like the turnkey security assertions, custom policy assertions can optionally provide an XML element that is used to specify the options for the custom policy assertion in a policy file. The XML element can contain child elements and attributes that specify the options for the custom policy assertion.
      A System.Xml.XmlReader is passed into the ReadXml method with the reader positioned on the XML element for the custom policy assertion. The name of the XML element is specified when the custom policy assertion is registered in the policy file using an <extension> Element. Use the System.Xml.XmlReader to retrieve the custom policy assertion's options that are set in the policy file.
      Override the GetExtensions method to associate the name of the XML element that is used to represent the policy assertion in a policy file with the type that implements the policy assertion.
      Typically, it is best to provide support for reading an XML element from a policy file for the custom policy assertion, so that policy for the application can be configured at deployment time to match the application's environment.
      The following code example verifies that the current element is named CustomSecurityAssertion and then reads it. To see an example policy file with the custom policy assertion, see How to: Secure an Application Using a Custom Policy Assertion.

          Public Overrides Sub ReadXml(ByVal reader As XmlReader, ByVal extensions As IDictionary(Of String, Type))
              Dim isEmpty As Boolean = reader.IsEmptyElement
      
              Dim input As String = reader.GetAttribute("input")
              Dim output As String = reader.GetAttribute("output")
      
              If Not (input Is Nothing) Then
                  inputfile = input
              End If
              If Not (output Is Nothing) Then
                  outputfile = output
              End If
              reader.ReadStartElement("CustomTraceAssertion")
              If Not isEmpty Then
                  reader.ReadEndElement()
              End If
          End Sub
      
      
      
      ...
      
      
              Public Overrides Function GetExtensions() As System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, System.Type))
              Dim traceExtension As New KeyValuePair(Of String, Type)("CustomTraceAssertion", Me.GetType())
              Return New KeyValuePair(Of String, Type)() {traceExtension}
          End Function
      
          public override void ReadXml(XmlReader reader, IDictionary<string, Type> extensions)
          {
              bool isEmpty = reader.IsEmptyElement;
      
              string input = reader.GetAttribute("input");
              string output = reader.GetAttribute("output");
      
              if (input != null)
                  inputfile = input;
      
              if (output != null)
                  outputfile = output;
      
              reader.ReadStartElement("CustomTraceAssertion");
              if (!isEmpty)
                  reader.ReadEndElement();
          }
      
      
      
      ...
      
      
              public override IEnumerable<KeyValuePair<string, Type>> GetExtensions()
          {
              return new KeyValuePair<string, Type>[] { new KeyValuePair<string, Type>("CustomTraceAssertion", this.GetType()) };
          }
      

Example

The following code example is a custom policy assertion that traces the SOAP messages that are exchanged between a client and a Web service.

Imports System
Imports System.IO
Imports System.Xml
Imports System.Collections.Generic
Imports System.Text
Imports System.Security.Cryptography.X509Certificates

Imports Microsoft.Web.Services3
Imports Microsoft.Web.Services3.Design
Imports Microsoft.Web.Services3.Security
Imports Microsoft.Web.Services3.Security.Tokens
Namespace CustomPolicyAssertions

    Class CustomTraceAssertion
        Inherits PolicyAssertion
        Private inputfile As String = "input.xml"
        Private outputfile As String = "output.xml"


        Public Sub New()
        End Sub 'New


        Public Overrides Function CreateClientOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
            Return New CustomTraceFilter("clientoutput.xml")
        End Function 'CreateClientOutputFilter

        Public Overrides Function CreateClientInputFilter(ByVal context As FilterCreationContext) As SoapFilter
            Return New CustomTraceFilter("clientinput.xml")
        End Function 'CreateClientInputFilter

        Public Overrides Function CreateServiceInputFilter(ByVal context As FilterCreationContext) As SoapFilter
            Return New CustomTraceFilter("serverinput.xml")
        End Function 'CreateServiceInputFilter

        Public Overrides Function CreateServiceOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
            Return New CustomTraceFilter("serveroutput.xml")
        End Function 'CreateServiceOutputFilter


        Public Overrides Sub ReadXml(ByVal reader As XmlReader, ByVal extensions As IDictionary(Of String, Type))
            Dim isEmpty As Boolean = reader.IsEmptyElement

            Dim input As String = reader.GetAttribute("input")
            Dim output As String = reader.GetAttribute("output")

            If Not (input Is Nothing) Then
                inputfile = input
            End If
            If Not (output Is Nothing) Then
                outputfile = output
            End If
            reader.ReadStartElement("CustomTraceAssertion")
            If Not isEmpty Then
                reader.ReadEndElement()
            End If
        End Sub
        Public Overrides Function GetExtensions() As System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, System.Type))
            Dim traceExtension As New KeyValuePair(Of String, Type)("CustomTraceAssertion", Me.GetType())
            Return New KeyValuePair(Of String, Type)() {traceExtension}
        End Function

        Class CustomTraceFilter
            Inherits SoapFilter
            Private filename As String = Nothing

            Public Sub New(ByVal file As String)
                filename = file
            End Sub 'New


            Public Overrides Function ProcessMessage(ByVal envelope As SoapEnvelope) As SoapFilterResult
                Dim dom As XmlDocument = Nothing

                Dim timeStamp As DateTime = DateTime.Now
                Dim rootNode As XmlNode = Nothing

                dom = New XmlDocument()

                If Not File.Exists(filename) Then
                    Dim xmlDecl As XmlDeclaration = dom.CreateXmlDeclaration("1.0", "utf-8", Nothing)

                    dom.InsertBefore(xmlDecl, dom.DocumentElement)

                    rootNode = dom.CreateNode(XmlNodeType.Element, "log", String.Empty)
                    dom.AppendChild(rootNode)
                    dom.Save(filename)
                Else
                    dom.Load(filename)
                    rootNode = dom.DocumentElement
                End If

                Dim newNode As XmlNode = dom.ImportNode(envelope.DocumentElement, True)
                rootNode.AppendChild(newNode)

                dom.Save(filename)

                Return SoapFilterResult.Continue
            End Function 'ProcessMessage
        End Class 'CustomTraceFilter
    End Class 'CustomTraceAssertion 
End Namespace
using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography.X509Certificates;

using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Design;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;

namespace CustomPolicyAssertions
{
    class CustomTraceAssertion : PolicyAssertion
    {
        string inputfile = "input.xml";
        string outputfile = "output.xml";

        public CustomTraceAssertion()
            : base()
        {
        }

        public override SoapFilter CreateClientOutputFilter(FilterCreationContext context)
        {
            return new CustomTraceFilter(outputfile);
        }

        public override SoapFilter CreateClientInputFilter(FilterCreationContext context)
        {
            return new CustomTraceFilter(inputfile);
        }

        public override SoapFilter CreateServiceInputFilter(FilterCreationContext context)
        {
            return new CustomTraceFilter(inputfile);
        }

        public override SoapFilter CreateServiceOutputFilter(FilterCreationContext context)
        {
            return new CustomTraceFilter(outputfile);
        }

        public override void ReadXml(XmlReader reader, IDictionary<string, Type> extensions)
        {
            bool isEmpty = reader.IsEmptyElement;

            string input = reader.GetAttribute("input");
            string output = reader.GetAttribute("output");

            if (input != null)
                inputfile = input;

            if (output != null)
                outputfile = output;

            reader.ReadStartElement("CustomTraceAssertion");
            if (!isEmpty)
                reader.ReadEndElement();
        }

        public override IEnumerable<KeyValuePair<string, Type>> GetExtensions()
        {
            return new KeyValuePair<string, Type>[] { new KeyValuePair<string, Type>("CustomTraceAssertion", this.GetType()) };
        }
    }

    class CustomTraceFilter : SoapFilter
    {
        string filename = null;
        public CustomTraceFilter(string file)
            : base()
        {
            filename = file;
        }

        public override SoapFilterResult ProcessMessage(SoapEnvelope envelope)
        {
            XmlDocument dom = null;
            DateTime timeStamp = DateTime.Now;
            XmlNode rootNode = null;

            dom = new XmlDocument();

            if (!File.Exists(filename))
            {
                XmlDeclaration xmlDecl = dom.CreateXmlDeclaration("1.0", "utf-8", null);

                dom.InsertBefore(xmlDecl, dom.DocumentElement);

                rootNode = dom.CreateNode(XmlNodeType.Element, "log", String.Empty);
                dom.AppendChild(rootNode);
                dom.Save(filename);
            }
            else
            {
                dom.Load(filename);
                rootNode = dom.DocumentElement;
            }


            XmlNode newNode = dom.ImportNode(envelope.DocumentElement, true);
            rootNode.AppendChild(newNode);

            dom.Save(filename );
 
            return SoapFilterResult.Continue;
        }
    }

   
}

See Also

Tasks

How to: Create a Custom Policy Assertion that Secures SOAP Messages

Reference

PolicyAssertion
SoapFilter

Concepts

Turnkey Security Assertions

Other Resources

Custom Policy Assertions