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
Open the project that contains the Web service.
Add a new class to the project.
- In Solution Explorer, right-click the project name, and then click Add New Item….
- Select Class and provide a name for the class.
- Click Add to dismiss the dialog and add the class to the project.
Add references to the Microsoft.Web.Services3, System.Web.Services, System.Security, and System.Xml assemblies.
- In Solution Explorer, right-click the project name, and then click Add Reference.
- 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.
- Click OK to dismiss the dialog.
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;
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.
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
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; }
Create a class that represents the custom policy assertion.
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
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); }
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); }
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); }
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); }
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 namedCustomSecurityAssertion
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