How to: Create a Custom Policy Assertion that Secures SOAP Messages
Create a custom policy assertion to enforce security requirements or modify 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 secures SOAP messages. The procedure creates a custom policy assertion that secures SOAP messages that are sent to and from the Web service using X509SecurityToken security tokens. For details about creating a custom policy assertion that does not secure SOAP messages, see How to: Create a Custom Policy Assertion that does not Secure SOAP Messages.
To create a custom policy assertion that secures a SOAP message exchange
Open the project containing 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 Microsoft.VisualBasic Imports System Imports System.Collections.Generic Imports System.Text Imports System.Xml 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.Collections.Generic; using System.Text; using System.Security.Cryptography.X509Certificates; using System.Xml; using Microsoft.Web.Services3; using Microsoft.Web.Services3.Design; using Microsoft.Web.Services3.Security; using Microsoft.Web.Services3.Security.Tokens;
Create a custom input filter for the Web service.
Add a class that derives from the ReceiveSecurityFilter class.
The following code example defines a class that derives from the ReceiveSecurityFilter class.Class CustomSecurityServerInputFilter Inherits ReceiveSecurityFilter
class CustomSecurityServerInputFilter : ReceiveSecurityFilter {
Specify the security requirements for incoming SOAP messages to the Web service by overriding the ValidateMessageSecurity method.
The following code example specifies that SOAP messages that are sent to the Web service must be signed and encrypted. The security tokens that are used to sign and encrypt the SOAP message are saved in the OperationState property, which can be accessed later by a Web service's custom output filter if a SOAP response is returned to the client. The security tokens are stored in a user-defined class namedRequestState
.Public Overrides Sub ValidateMessageSecurity(ByVal envelope As SoapEnvelope, ByVal security As Security) Dim clientToken As SecurityToken = Nothing Dim serverToken As SecurityToken = Nothing ' Ensure incoming SOAP messages are signed and encrypted. Dim elem As ISecurityElement For Each elem In security.Elements If TypeOf elem Is MessageSignature Then Dim sig As MessageSignature = CType(elem, MessageSignature) clientToken = sig.SigningToken End If If TypeOf elem Is EncryptedData Then Dim enc As EncryptedData = CType(elem, EncryptedData) serverToken = enc.SecurityToken End If Next elem If clientToken Is Nothing OrElse serverToken Is Nothing Then Throw New Exception("Incoming message did not meet security requirements") End If Dim state As New RequestState(clientToken, serverToken) envelope.Context.OperationState.Set(state) End Sub 'ValidateMessageSecurity
public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security) { SecurityToken clientToken = null; SecurityToken serverToken = null; // Ensure incoming SOAP messages are signed and encrypted. foreach (ISecurityElement elem in security.Elements) { if (elem is MessageSignature) { MessageSignature sig = (MessageSignature)elem; clientToken = sig.SigningToken; } if (elem is EncryptedData) { EncryptedData enc = (EncryptedData)elem; serverToken = enc.SecurityToken; } } if (clientToken == null || serverToken == null) throw new Exception("Incoming message did not meet security requirements"); RequestState state = new RequestState(clientToken, serverToken); envelope.Context.OperationState.Set(state); }
Create a custom output filter for the Web service.
Add a class that derives from the SendSecurityFilter class.
The following example defines a class that derives from the SendSecurityFilter class.Class CustomSecurityServerOutputFilter Inherits SendSecurityFilter
class CustomSecurityServerOutputFilter : SendSecurityFilter {
Secure SOAP responses that are sent from the Web service by overriding the SecureMessage method.
The following code example signs and encrypts SOAP responses using the security tokens that encrypted and signed the SOAP request, respectively. The security tokens are retrieved from the OperationState property that was set by the Web service's custom input filter.Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, ByVal security As Security) Dim state As RequestState = envelope.Context.OperationState.Get(Of RequestState)() ' Sign the message with the Web service's security token. security.Tokens.Add(state.ServerToken) security.Elements.Add(New MessageSignature(state.ServerToken)) ' Encrypt the message with the client's security token. security.Elements.Add(New EncryptedData(state.ClientToken)) End Sub 'SecureMessage
public override void SecureMessage(SoapEnvelope envelope, Security security) { RequestState state = envelope.Context.OperationState.Get<RequestState>(); // Sign the message with the Web service's security token. security.Tokens.Add(state.ServerToken); security.Elements.Add(new MessageSignature(state.ServerToken)); // Encrypt the message with the client's security token. security.Elements.Add(new EncryptedData(state.ClientToken)); }
Create a custom output filter for the client.
Add a class that derives from the SendSecurityFilter class.
The following code example defines a class that derives from the SendSecurityFilter class.Class CustomSecurityClientOutputFilter Inherits SendSecurityFilter
class CustomSecurityClientOutputFilter : SendSecurityFilter {
Secure SOAP responses that are sent from the client by overriding the SecureMessage method.
The following code example signs and encrypts SOAP responses using the security tokens that are created in the custom filter's constructor. The security tokens that are used to sign and encrypt the SOAP message are saved in the OperationState property, which can be accessed later by a client's custom output filter to verify security requirements on SOAP responses that are returned by the Web service.Public Sub New(ByVal parentAssertion As CustomSecurityAssertion) MyBase.New(parentAssertion.ServiceActor, True) ' Get the client security token. clientToken = X509TokenProvider.CreateToken(StoreLocation.CurrentUser, StoreName.My, "CN=WSE2QuickStartClient") ' Get the server security token. serverToken = X509TokenProvider.CreateToken(StoreLocation.LocalMachine, StoreName.My, "CN=WSE2QuickStartServer") End Sub 'New ... Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, ByVal security As Security) ' Sign the SOAP message with the client's security token. security.Tokens.Add(clientToken) security.Elements.Add(New MessageSignature(clientToken)) ' Encrypt the SOAP message with the client's security token. security.Elements.Add(New EncryptedData(serverToken)) ' Encrypt the client's security token with the server's security token. security.Elements.Add(New EncryptedData(serverToken, "#" + clientToken.Id)) ' Store the client and server security tokens in the request state. Dim state As New RequestState(clientToken, serverToken) ' Store the request state in the proxy's operation state. ' This makes these tokens accessible when SOAP responses are ' verified to have sufficient security requirements. envelope.Context.OperationState.Set(state) End Sub 'SecureMessage
public CustomSecurityClientOutputFilter(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor,true ) { // Get the client security token. clientToken = X509TokenProvider.CreateToken(StoreLocation.CurrentUser, StoreName.My, "CN=WSE2QuickStartClient"); // Get the server security token. serverToken = X509TokenProvider.CreateToken(StoreLocation.LocalMachine, StoreName.My, "CN=WSE2QuickStartServer"); } ... public override void SecureMessage(SoapEnvelope envelope, Security security) { // Sign the SOAP message with the client's security token. security.Tokens.Add(clientToken); security.Elements.Add(new MessageSignature(clientToken)); // Encrypt the SOAP message with the client's security token. security.Elements.Add(new EncryptedData(serverToken)); // Encrypt the client's security token with the server's security token. security.Elements.Add(new EncryptedData(serverToken, "#" + clientToken.Id)); // Store the client and server security tokens in the request state. RequestState state = new RequestState(clientToken, serverToken); // Store the request state in the proxy's operation state. // This makes these tokens accessible when SOAP responses are // verified to have sufficient security requirements. envelope.Context.OperationState.Set(state); }
Create a custom input filter for the client.
Add a class that derives from the ReceiveSecurityFilter class.
The following code example defines a class that derives from the ReceiveSecurityFilter class.Class CustomSecurityClientInputFilter Inherits ReceiveSecurityFilter
class CustomSecurityClientInputFilter : ReceiveSecurityFilter {
Enforce the security requirements for SOAP responses from the Web service by overriding the ValidateMessageSecurity method.
The following code example ensures that SOAP responses are signed using the security token that is used to encrypt the SOAP request and that is encrypted by the security token that signed the SOAP request. The security tokens are retrieved from the OperationState property that was set by the client's custom output filter.Public Overrides Sub ValidateMessageSecurity(ByVal envelope As SoapEnvelope, ByVal security As Security) Dim state As RequestState Dim signed As Boolean = False Dim encrypted As Boolean = False ' Get the request state out of the operation state. state = envelope.Context.OperationState.Get(Of RequestState)() ' Make sure the message was signed with the server's security token. Dim elem As ISecurityElement For Each elem In security.Elements If TypeOf elem Is MessageSignature Then Dim sig As MessageSignature = CType(elem, MessageSignature) If sig.SigningToken.Equals(state.ServerToken) Then signed = True End If End If If TypeOf elem Is EncryptedData Then Dim enc As EncryptedData = CType(elem, EncryptedData) If enc.SecurityToken.Equals(state.ClientToken) Then encrypted = True End If End If Next elem If Not signed OrElse Not encrypted Then Throw New Exception("Response message does not meet security requirements") End If End Sub 'ValidateMessageSecurity
public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security) { RequestState state; bool signed = false; bool encrypted = false; // Get the request state out of the operation state. state = envelope.Context.OperationState.Get<RequestState>(); // Make sure the message was signed with the server's security token. foreach (ISecurityElement elem in security.Elements) { if (elem is MessageSignature) { MessageSignature sig = (MessageSignature)elem; if (sig.SigningToken.Equals(state.ServerToken)) signed = true; } if (elem is EncryptedData) { EncryptedData enc = (EncryptedData)elem; if (enc.SecurityToken.Equals(state.ClientToken)) encrypted = true; } } if (!signed || !encrypted) throw new Exception("Response message does not meet security requirements"); }
Create a class that represents the custom policy assertion.
Create a class that derives from the SecurityPolicyAssertion class.
The following code example defines a class that derives from the SecurityPolicyAssertion class.Class CustomSecurityAssertion Inherits SecurityPolicyAssertion
class CustomSecurityAssertion : SecurityPolicyAssertion {
Specify the Web service's custom input filter by overriding the CreateServiceInputFilter method.
When a custom policy assertion does not enforce security on SOAP requests that are sent to the Web service, set the return value of the CreateServiceInputFilter method to a null reference (Nothing in Visual Basic).
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 CustomSecurityServerInputFilter(Me) End Function 'CreateServiceInputFilter
public override SoapFilter CreateServiceInputFilter(FilterCreationContext context) { return new CustomSecurityServerInputFilter(this); }
Specify the Web service's custom output filter by overriding the CreateServiceOutputFilter method.
When a custom policy assertion does not enforce security on SOAP responses that are sent by the Web service, set the return value of the CreateServiceOutputFilter method to a null reference (Nothing in Visual Basic).
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 CustomSecurityServerOutputFilter(Me) End Function 'CreateServiceOutputFilter
public override SoapFilter CreateServiceOutputFilter(FilterCreationContext context) { return new CustomSecurityServerOutputFilter(this); }
Specify the client's custom input filter by overriding the CreateClientInputFilter method.
When a custom policy assertion does not enforce security on SOAP responses that are received by the client, set the return value of the CreateClientInputFilter method to a null reference (Nothing in Visual Basic)
The following code example adds a custom input filter for the client.Public Overrides Function CreateClientInputFilter(ByVal context As FilterCreationContext) As SoapFilter Return Nothing End Function 'CreateClientInputFilter
public override SoapFilter CreateClientInputFilter(FilterCreationContext context) { return new CustomSecurityClientInputFilter(this); }
Specify the client's custom output filter by overriding the CreateClientOutputFilter method.
When a custom policy assertion does not enforce security on SOAP requests that are sent by the client, set the return value of the CreateClientOutputFilter method to a null reference (Nothing in Visual Basic).
The following code example adds a custom output filter for the client.Public Overrides Function CreateClientOutputFilter(ByVal context As FilterCreationContext) As SoapFilter Return Nothing End Function 'CreateClientOutputFilter
public override SoapFilter CreateClientOutputFilter(FilterCreationContext context) { return new CustomSecurityClientOutputFilter(this); }
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 custom policy assertion's options 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)) If reader Is Nothing Then Throw New ArgumentNullException("reader") End If If extensions Is Nothing Then Throw New ArgumentNullException("extensions") End If Dim isEmpty As Boolean = reader.IsEmptyElement MyBase.ReadAttributes(reader) reader.ReadStartElement("CustomSecurityAssertion") If Not isEmpty Then ' Read the contents of the <clientToken> element. If reader.MoveToContent() = XmlNodeType.Element AndAlso reader.Name = "clientToken" Then reader.ReadStartElement() reader.MoveToContent() ' Get the registed security token provider for X.509 certificate security credentials. Dim type As Type = extensions(reader.Name) Dim instance As Object = Activator.CreateInstance(type) If instance Is Nothing Then Throw New InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type 0End.", type.AssemblyQualifiedName)) End If Dim clientProvider As TokenProvider(Of X509SecurityToken) = CType(instance, TokenProvider(Of X509SecurityToken)) ' Read the child elements that provide the details about the client's X.509 certificate. clientProvider.ReadXml(reader, extensions) Me.ClientX509TokenProvider = clientProvider reader.ReadEndElement() End If ' Read the contents of the <serviceToken> element. If reader.MoveToContent() = XmlNodeType.Element AndAlso reader.Name = "serviceToken" Then reader.ReadStartElement() reader.MoveToContent() ' Get the registed security token provider for X.509 certificate security credentials. Dim type As Type = extensions(reader.Name) Dim instance As Object = Activator.CreateInstance(type) If instance Is Nothing Then Throw New InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type 0End.", type.AssemblyQualifiedName)) End If Dim serviceProvider As TokenProvider(Of X509SecurityToken) = CType(instance, TokenProvider(Of X509SecurityToken)) ' Read the child elements that provide the details about the client's X.509 certificate. serviceProvider.ReadXml(reader, extensions) Me.ServiceX509TokenProvider = serviceProvider reader.ReadEndElement() End If MyBase.ReadElements(reader, extensions) reader.ReadEndElement() End If End Sub ... public override IEnumerable<KeyValuePair<string, Type>> GetExtensions() { // Add the CustomSecurityAssertion custom policy assertion to the list of registered // policy extensions. List<KeyValuePair<string, Type>> extensions = new List<KeyValuePair<string, Type>>(); extensions.Add(new KeyValuePair<string, Type>("CustomSecurityAssertion", this.GetType())); if (serviceX509TokenProviderValue != null) { // Add any policy extensions that read child elements of the <serviceToken> element // to the list of registered policy extensions. IEnumerable<KeyValuePair<string, Type>> innerExtensions = serviceX509TokenProviderValue.GetExtensions(); if (innerExtensions != null) { foreach (KeyValuePair<string, Type> extension in innerExtensions) { extensions.Add(extension); } } } if (clientX509TokenProviderValue != null) { // Add any policy extensions that read child elements of the <clientToken> element // to the list of registered policy extensions. IEnumerable<KeyValuePair<string, Type>> innerExtensions = clientX509TokenProviderValue.GetExtensions(); if (innerExtensions != null) { foreach (KeyValuePair<string, Type> extension in innerExtensions) { extensions.Add(extension); } } } return extensions; } // </snippet16 } class RequestState { SecurityToken clientToken; SecurityToken serverToken; public RequestState(SecurityToken cToken, SecurityToken sToken) { clientToken = cToken; serverToken = sToken; } public SecurityToken ClientToken { get { return clientToken; } } public SecurityToken ServerToken { get { return serverToken; } } } class CustomSecurityServerInputFilter : ReceiveSecurityFilter { public CustomSecurityServerInputFilter(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor, false) { } public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security) { SecurityToken clientToken = null; SecurityToken serverToken = null; // Ensure incoming SOAP messages are signed and encrypted. foreach (ISecurityElement elem in security.Elements) { if (elem is MessageSignature) { MessageSignature sig = (MessageSignature)elem; clientToken = sig.SigningToken; } if (elem is EncryptedData) { EncryptedData enc = (EncryptedData)elem; serverToken = enc.SecurityToken; } } if (clientToken == null || serverToken == null) throw new Exception("Incoming message did not meet security requirements"); RequestState state = new RequestState(clientToken, serverToken); envelope.Context.OperationState.Set(state); } } class CustomSecurityServerOutputFilter : SendSecurityFilter { public CustomSecurityServerOutputFilter(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor,false ) { } public override void SecureMessage(SoapEnvelope envelope, Security security) { RequestState state = envelope.Context.OperationState.Get<RequestState>(); // Sign the message with the Web service's security token. security.Tokens.Add(state.ServerToken); security.Elements.Add(new MessageSignature(state.ServerToken)); // Encrypt the message with the client's security token. security.Elements.Add(new EncryptedData(state.ClientToken)); } } class CustomSecurityClientInputFilter : ReceiveSecurityFilter { public CustomSecurityClientInputFilter(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor,true ) { } public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security) { RequestState state; bool signed = false; bool encrypted = false; // Get the request state out of the operation state. state = envelope.Context.OperationState.Get<RequestState>(); // Make sure the message was signed with the server's security token. foreach (ISecurityElement elem in security.Elements) { if (elem is MessageSignature) { MessageSignature sig = (MessageSignature)elem; if (sig.SigningToken.Equals(state.ServerToken)) signed = true; } if (elem is EncryptedData) { EncryptedData enc = (EncryptedData)elem; if (enc.SecurityToken.Equals(state.ClientToken)) encrypted = true; } } if (!signed || !encrypted) throw new Exception("Response message does not meet security requirements"); } } class CustomSecurityClientOutputFilter : SendSecurityFilter { SecurityToken clientToken; SecurityToken serverToken; public CustomSecurityClientOutputFilter(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor,true ) { // Get the client security token. clientToken = X509TokenProvider.CreateToken(StoreLocation.CurrentUser, StoreName.My, "CN=WSE2QuickStartClient"); // Get the server security token. serverToken = X509TokenProvider.CreateToken(StoreLocation.LocalMachine, StoreName.My, "CN=WSE2QuickStartServer"); } public override void SecureMessage(SoapEnvelope envelope, Security security) { // Sign the SOAP message with the client's security token. security.Tokens.Add(clientToken); security.Elements.Add(new MessageSignature(clientToken)); // Encrypt the SOAP message with the client's security token. security.Elements.Add(new EncryptedData(serverToken)); // Encrypt the client's security token with the server's security token. security.Elements.Add(new EncryptedData(serverToken, "#" + clientToken.Id)); // Store the client and server security tokens in the request state. RequestState state = new RequestState(clientToken, serverToken); // Store the request state in the proxy's operation state. // This makes these tokens accessible when SOAP responses are // verified to have sufficient security requirements. envelope.Context.OperationState.Set(state); } } } 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; } } } fxcopcmd.exe /p:"C:\Security.FxCop" /plat:"C:\WINNT\Microsoft.NET\Framework\v2.0.50215" /c /d:"C:\Program Files\Microsoft WSE\v3.0" /f:"c:\samples\wse\wseCustomPolicyAssertion\cs\bin\Debug\Client.exe" /f:"c:\samples\wse\wseCustomPolicyAssertion\cs\bin\Debug\Client.vshost.exe" /f:"c:\samples\wse\wseCustomPolicyAssertion\cs\obj\Debug\Client.exe" Microsoft FxCopCmd v1.312 Copyright (C) 1999-2004 Microsoft Corp. All rights reserved. Loading C:\Security.FxCop... Loaded SecurityRules.dll... Found project override for platform assemblies location. Using system files at: C:\WINNT\Microsoft.NET\Framework\v2.0.50215. 4 exceptions occurred while loading mscorlib. 0) Attempted to read or write protected memory. This is often an indication that other memory has been corrupted. 1) Bad serialized type name Could not resolve reference to System.Configuration. 5 exceptions occurred while loading Client. 0) Bad serialized type name 1) Assembly reference not resolved: System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a Loaded Client.exe... 1 exceptions occurred while loading vshost. 0) Bad serialized type name Loaded Client.vshost.exe... 4 exceptions occurred while loading Client. 0) Bad serialized type name Loaded Client.exe... Initializing Introspection engine... Could not resolve reference to Microsoft.VisualStudio.HostingProcess.Utilities.Sync. Could not resolve reference to Microsoft.VisualStudio.HostingProcess.Utilities.Sync. 5 exceptions occurred while loading vshost. 0) Could not resolve member reference: Microsoft.VisualStudio.HostingProcess.Synchronize::get_HostingProcessInitialized 1) Assembly reference not resolved: Microsoft.VisualStudio.HostingProcess.Utilities.Sync, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 2) Could not resolve member reference: Microsoft.VisualStudio.HostingProcess.Synchronize::get_StartRunningUsersAssembly 3) Bad serialized type name 4) Could not resolve type reference: [Microsoft.VisualStudio.HostingProcess.Utilities.Sync]Microsoft.VisualStudio.HostingProcess.Synchronize 12 exceptions occurred while loading Client. 00) Could not resolve member reference: System.Configuration.ConfigurationManager::get_AppSettings 01) Could not resolve type reference: [System.Configuration]System.Configuration.ConfigurationManager 02) Could not resolve type reference: [System]System.Security.Cryptography.X509Certificates.StoreLocation 03) Could not resolve type reference: [mscorlib]System.Collections.ObjectModel.Collection`1 04) Could not resolve member reference: System.Web.Services.Protocols.WebClientProtocol::get_UseDefaultCredentials 05) Bad serialized type name 06) Could not resolve member reference: Microsoft.Web.Services3.Design.Policy::get_Assertions 07) Could not resolve member reference: System.Web.Services.Protocols.WebClientProtocol::set_UseDefaultCredentials 08) Could not resolve member reference: System.Collections.ObjectModel.Collection`1::Add 09) Could not resolve member reference: Microsoft.Web.Services3.Design.X509TokenProvider::CreateToken 10) Could not resolve type reference: [System]System.Security.Cryptography.X509Certificates.StoreName 11) Bad type parameter in position 0 for type=Client.ClientPolicy 8 exceptions occurred while loading Client. 0) Could not resolve type reference: [System]System.Security.Cryptography.X509Certificates.StoreLocation 1) Could not resolve type reference: [mscorlib]System.Collections.ObjectModel.Collection`1 2) Bad serialized type name 3) Could not resolve member reference: Microsoft.Web.Services3.Design.Policy::get_Assertions 4) Could not resolve member reference: System.Collections.ObjectModel.Collection`1::Add 5) Could not resolve member reference: Microsoft.Web.Services3.Design.X509TokenProvider::CreateToken 6) Could not resolve type reference: [System]System.Security.Cryptography.X509Certificates.StoreName 7) Bad type parameter in position 0 for type=Client.ClientPolicy Analyzing... Analysis Complete. No messages written. Done. WARNING: the following missing references were detected. Analysis might be compromised. Use the '/directory' switch. to specify additional assembly reference search paths. * System.Configuration Version=2.0.0.0, used by:Client * Microsoft.VisualStudio.HostingProcess.Utilities.Sync Version=8.0.0.0, used by:vshost using System; using System.Collections.Generic; using System.Text; using Microsoft.Web.Services3; using Microsoft.Web.Services3.Security; using Microsoft.Web.Services3.Design; using Client.localhost; using CustomPolicyAssertions; namespace Client { class Program { static void Main(string[] args) { ServiceWse serviceProxy = new ServiceWse(); serviceProxy.SetPolicy("ClientPolicy"); Console.WriteLine("Web service returned: {0}", serviceProxy.HelloWorld()); } } class ClientPolicy : Policy { public ClientPolicy() : base() { this.Assertions.Add(new CustomSecurityAssertion()); this.Assertions.Add(new CustomTraceAssertion()); } } } <policies> <extensions> <extension name="CustomSecurityAssertion" type="CustomPolicyAssertions.CustomSecurityAssertion, Client" /> <extension name="CustomTraceAssertion" type="CustomPolicyAssertions.CustomTraceAssertion, Client" /> </extensions> <policy name="ClientPolicy"> <CustomTraceAssertion input="input-before.xml" output="output-before.xml"/> <CustomSecurityAssertion /> <CustomTraceAssertion input="input-after.xml" output="output-after.xml"/> </policy> </policies> <?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="ClientVB.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" /> </sectionGroup> <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="ClientVB.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </sectionGroup> </configSections> <microsoft.web.services3> <tokenIssuer> <statefulSecurityContextToken enabled="true" /> </tokenIssuer> <diagnostics> <trace enabled="true" input="InputTrace.webinfo" output="OutputTrace.webinfo" /> </diagnostics> <security> <x509 storeLocation="CurrentUser" allowTestRoot="true" /> </security> <policy fileName="..\..\wse3policyCache.config" /> </microsoft.web.services3> <userSettings> <ClientVB.Settings /> </userSettings> <applicationSettings> <ClientVB.Settings> <setting name="ClientVB_localhost_Service" serializeAs="String"> <value>https://localhost/CustomPolicyServiceVB/Service.asmx</value> </setting> </ClientVB.Settings> </applicationSettings> </configuration> Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ClientVB", "ClientVB.vbproj", "{02C3A5FE-44CE-4457-BCF5-D0936247EC15}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {02C3A5FE-44CE-4457-BCF5-D0936247EC15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {02C3A5FE-44CE-4457-BCF5-D0936247EC15}.Debug|Any CPU.Build.0 = Debug|Any CPU {02C3A5FE-44CE-4457-BCF5-D0936247EC15}.Release|Any CPU.ActiveCfg = Release|Any CPU {02C3A5FE-44CE-4457-BCF5-D0936247EC15}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" xmlns="https://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProductVersion>8.0.50215</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{02C3A5FE-44CE-4457-BCF5-D0936247EC15}</ProjectGuid> <OutputType>Exe</OutputType> <StartupObject>ClientVB.Program</StartupObject> <RootNamespace>ClientVB</RootNamespace> <AssemblyName>ClientVB</AssemblyName> <MyType>Console</MyType> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <DefineDebug>true</DefineDebug> <DefineTrace>true</DefineTrace> <OutputPath>bin\Debug\</OutputPath> <DocumentationFile>ClientVB.xml</DocumentationFile> <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> <DefineDebug>false</DefineDebug> <DefineTrace>true</DefineTrace> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> <DocumentationFile>ClientVB.xml</DocumentationFile> <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> </PropertyGroup> <ItemGroup> <Reference Include="Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> <Reference Include="System" /> <Reference Include="System.Configuration" /> <Reference Include="System.Data" /> <Reference Include="System.Deployment" /> <Reference Include="System.EnterpriseServices" /> <Reference Include="System.Security" /> <Reference Include="System.Web.Services" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Import Include="Microsoft.VisualBasic" /> <Import Include="System" /> <Import Include="System.Collections" /> <Import Include="System.Collections.Generic" /> <Import Include="System.Console" /> <Import Include="System.Data" /> <Import Include="System.Diagnostics" /> </ItemGroup> <ItemGroup> <Compile Include="CustomSecurityAssertion.vb" /> <Compile Include="CustomTraceAssertion.vb" /> <Compile Include="Program.vb" /> <Compile Include="My Project\AssemblyInfo.vb" /> <Compile Include="My Project\Application.Designer.vb"> <AutoGen>True</AutoGen> <DependentUpon>Application.myapp</DependentUpon> </Compile> <Compile Include="My Project\Resources.Designer.vb"> <AutoGen>True</AutoGen> <DesignTime>True</DesignTime> <DependentUpon>Resources.resx</DependentUpon> </Compile> <Compile Include="My Project\Settings.Designer.vb"> <AutoGen>True</AutoGen> <DependentUpon>Settings.settings</DependentUpon> <DesignTimeSharedInput>True</DesignTimeSharedInput> </Compile> <Compile Include="Web References\localhost\Reference.vb"> <AutoGen>True</AutoGen> <DesignTime>True</DesignTime> <DependentUpon>Reference.map</DependentUpon> </Compile> </ItemGroup> <ItemGroup> <EmbeddedResource Include="My Project\Resources.resx"> <Generator>VbMyResourcesResXFileCodeGenerator</Generator> <LastGenOutput>Resources.Designer.vb</LastGenOutput> <CustomToolNamespace>My.Resources</CustomToolNamespace> </EmbeddedResource> </ItemGroup> <ItemGroup> <None Include="app.config" /> <None Include="My Project\Application.myapp"> <Generator>MyApplicationCodeGenerator</Generator> <LastGenOutput>Application.Designer.vb</LastGenOutput> </None> <None Include="My Project\Settings.settings"> <Generator>SettingsSingleFileGenerator</Generator> <LastGenOutput>Settings.Designer.vb</LastGenOutput> </None> </ItemGroup> <ItemGroup> <WebReferences Include="Web References\" /> </ItemGroup> <ItemGroup> <WebReferenceUrl Include="https://localhost/CustomPolicyServiceVB/Service.asmx"> <UrlBehavior>Dynamic</UrlBehavior> <RelPath>Web References\localhost\</RelPath> <UpdateFromURL>https://localhost/CustomPolicyServiceVB/Service.asmx</UpdateFromURL> <ServiceLocationURL> </ServiceLocationURL> <CachedDynamicPropName> </CachedDynamicPropName> <CachedAppSettingsObjectName>Settings</CachedAppSettingsObjectName> <CachedSettingsPropName>ClientVB_localhost_Service</CachedSettingsPropName> </WebReferenceUrl> </ItemGroup> <ItemGroup> <None Include="Web References\localhost\Reference.map"> <Generator>MSDiscoCodeGenerator</Generator> <LastGenOutput>Reference.vb</LastGenOutput> </None> <None Include="Web References\localhost\Service.disco" /> <None Include="Web References\localhost\Service.wsdl" /> <None Include="wse3policyCache.config" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.VisualBasic.targets" /> </Project> <Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <LastOpenVersion>8.0.50215</LastOpenVersion> <ProjectView>ProjectFiles</ProjectView> </PropertyGroup> </Project> Imports Microsoft.VisualBasic Imports System Imports System.Collections.Generic Imports System.Text Imports System.Xml 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 CustomSecurityAssertion Inherits SecurityPolicyAssertion Dim serviceX509TokenProviderValue As TokenProvider(Of X509SecurityToken) Dim clientX509TokenProviderValue As TokenProvider(Of X509SecurityToken) Public Property ClientX509TokenProvider() As TokenProvider(Of X509SecurityToken) Get Return clientX509TokenProviderValue End Get Set(ByVal value As TokenProvider(Of X509SecurityToken)) clientX509TokenProviderValue = value End Set End Property Public Property ServiceX509TokenProvider() As TokenProvider(Of X509SecurityToken) Get Return serviceX509TokenProviderValue End Get Set(ByVal value As TokenProvider(Of X509SecurityToken)) serviceX509TokenProviderValue = value End Set End Property Public Sub New() End Sub 'New Public Overrides Function CreateClientOutputFilter(ByVal context As FilterCreationContext) As SoapFilter Return Nothing End Function 'CreateClientOutputFilter Public Overrides Function CreateClientInputFilter(ByVal context As FilterCreationContext) As SoapFilter Return Nothing End Function 'CreateClientInputFilter Public Overrides Function CreateServiceInputFilter(ByVal context As FilterCreationContext) As SoapFilter Return New CustomSecurityServerInputFilter(Me) End Function 'CreateServiceInputFilter Public Overrides Function CreateServiceOutputFilter(ByVal context As FilterCreationContext) As SoapFilter Return New CustomSecurityServerOutputFilter(Me) End Function 'CreateServiceOutputFilter Public Overrides Sub ReadXml(ByVal reader As XmlReader, ByVal extensions As IDictionary(Of String, Type)) If reader Is Nothing Then Throw New ArgumentNullException("reader") End If If extensions Is Nothing Then Throw New ArgumentNullException("extensions") End If Dim isEmpty As Boolean = reader.IsEmptyElement MyBase.ReadAttributes(reader) reader.ReadStartElement("CustomSecurityAssertion") If Not isEmpty Then ' Read the contents of the <clientToken> element. If reader.MoveToContent() = XmlNodeType.Element AndAlso reader.Name = "clientToken" Then reader.ReadStartElement() reader.MoveToContent() ' Get the registed security token provider for X.509 certificate security credentials. Dim type As Type = extensions(reader.Name) Dim instance As Object = Activator.CreateInstance(type) If instance Is Nothing Then Throw New InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type 0End.", type.AssemblyQualifiedName)) End If Dim clientProvider As TokenProvider(Of X509SecurityToken) = CType(instance, TokenProvider(Of X509SecurityToken)) ' Read the child elements that provide the details about the client's X.509 certificate. clientProvider.ReadXml(reader, extensions) Me.ClientX509TokenProvider = clientProvider reader.ReadEndElement() End If ' Read the contents of the <serviceToken> element. If reader.MoveToContent() = XmlNodeType.Element AndAlso reader.Name = "serviceToken" Then reader.ReadStartElement() reader.MoveToContent() ' Get the registed security token provider for X.509 certificate security credentials. Dim type As Type = extensions(reader.Name) Dim instance As Object = Activator.CreateInstance(type) If instance Is Nothing Then Throw New InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type 0End.", type.AssemblyQualifiedName)) End If Dim serviceProvider As TokenProvider(Of X509SecurityToken) = CType(instance, TokenProvider(Of X509SecurityToken)) ' Read the child elements that provide the details about the client's X.509 certificate. serviceProvider.ReadXml(reader, extensions) Me.ServiceX509TokenProvider = serviceProvider reader.ReadEndElement() End If MyBase.ReadElements(reader, extensions) reader.ReadEndElement() End If End Sub Public Overrides Function GetExtensions() As IEnumerable(Of KeyValuePair(Of String, Type)) Public Overrides Function GetExtensions() As IEnumerable(Of KeyValuePair(Of String, Type)) ' Add the CustomSecurityAssertion custom policy assertion to the list of registered ' Add the CustomSecurityAssertion custom policy assertion to the list of registered ' policy extensions. ' policy extensions. Dim extensions As New List(Of KeyValuePair(Of String, Type)) Dim extensions As New List(Of KeyValuePair(Of String, Type)) extensions.Add(New KeyValuePair(Of String, Type)("CustomSecurityAssertion", Me.GetType())) extensions.Add(New KeyValuePair(Of String, Type)("CustomSecurityAssertion", Me.GetType())) If (Not serviceX509TokenProviderValue Is Nothing) Then If (Not serviceX509TokenProviderValue Is Nothing) Then ' Add any policy extensions that read child elements of the <serviceToken> element ' Add any policy extensions that read child elements of the <serviceToken> element ' to the list of registered policy extensions. ' to the list of registered policy extensions. Dim innerExtensions As IEnumerable(Of KeyValuePair(Of String, Type)) = serviceX509TokenProviderValue.GetExtensions() Dim innerExtensions As IEnumerable(Of KeyValuePair(Of String, Type)) = serviceX509TokenProviderValue.GetExtensions() If (Not innerExtensions Is Nothing) Then If (Not innerExtensions Is Nothing) Then Dim extension As KeyValuePair(Of String, Type) Dim extension As KeyValuePair(Of String, Type) For Each extension In innerExtensions For Each extension In innerExtensions extensions.Add(extension) extensions.Add(extension) Next Next End If End If End If End If If (Not clientX509TokenProviderValue Is Nothing) Then If (Not clientX509TokenProviderValue Is Nothing) Then ' Add any policy extensions that read child elements of the <clientToken> element ' Add any policy extensions that read child elements of the <clientToken> element ' to the list of registered policy extensions. ' to the list of registered policy extensions. Dim innerExtensions As IEnumerable(Of KeyValuePair(Of String, Type)) = clientX509TokenProviderValue.GetExtensions() Dim innerExtensions As IEnumerable(Of KeyValuePair(Of String, Type)) = clientX509TokenProviderValue.GetExtensions() If (Not innerExtensions Is Nothing) Then If (Not innerExtensions Is Nothing) Then Dim extension As KeyValuePair(Of String, Type) Dim extension As KeyValuePair(Of String, Type) For Each extension In innerExtensions For Each extension In innerExtensions extensions.Add(extension) extensions.Add(extension) Next Next End If End If End If End If Return extensions Return extensions End Function End Function
public override void ReadXml(System.Xml.XmlReader reader, IDictionary<string, Type> extensions) { if (reader == null) throw new ArgumentNullException("reader"); if (extensions == null) throw new ArgumentNullException("extensions"); bool isEmpty = reader.IsEmptyElement; base.ReadAttributes(reader); reader.ReadStartElement("CustomSecurityAssertion"); if (!isEmpty) { if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "clientToken") { reader.ReadStartElement(); reader.MoveToContent(); // Get the registed security token provider for X.509 certificate security credentials. Type type = extensions[reader.Name]; object instance = Activator.CreateInstance(type); if (instance == null) throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type {0}.", type.AssemblyQualifiedName)); TokenProvider<X509SecurityToken> clientProvider = instance as TokenProvider<X509SecurityToken>; // Read the child elements that provide the details about the client's X.509 certificate. clientProvider.ReadXml(reader, extensions); this.ClientX509TokenProvider = clientProvider; reader.ReadEndElement(); } if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "serviceToken") { reader.ReadStartElement(); reader.MoveToContent(); // Get the registed security token provider for X.509 certificate security credentials. Type type = extensions[reader.Name]; object instance = Activator.CreateInstance(type); if (instance == null) throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type {0}.", type.AssemblyQualifiedName)); TokenProvider<X509SecurityToken> serviceProvider = instance as TokenProvider<X509SecurityToken>; // Read the child elements that provide the details about the Web service's X.509 certificate. serviceProvider.ReadXml(reader, extensions); this.ServiceX509TokenProvider = serviceProvider; reader.ReadEndElement(); } base.ReadElements(reader, extensions); reader.ReadEndElement(); } }
Example
The following code example is a custom policy assertion that signs and encrypts SOAP messages that are sent to and from the Web service using X509SecurityToken security tokens.
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Xml
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 CustomSecurityAssertion
Inherits SecurityPolicyAssertion
Dim serviceX509TokenProviderValue As TokenProvider(Of X509SecurityToken)
Dim clientX509TokenProviderValue As TokenProvider(Of X509SecurityToken)
Public Property ClientX509TokenProvider() As TokenProvider(Of X509SecurityToken)
Get
Return clientX509TokenProviderValue
End Get
Set(ByVal value As TokenProvider(Of X509SecurityToken))
clientX509TokenProviderValue = value
End Set
End Property
Public Property ServiceX509TokenProvider() As TokenProvider(Of X509SecurityToken)
Get
Return serviceX509TokenProviderValue
End Get
Set(ByVal value As TokenProvider(Of X509SecurityToken))
serviceX509TokenProviderValue = value
End Set
End Property
Public Sub New()
End Sub 'New
Public Overrides Function CreateClientOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return Nothing
End Function 'CreateClientOutputFilter
Public Overrides Function CreateClientInputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return Nothing
End Function 'CreateClientInputFilter
Public Overrides Function CreateServiceInputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return New CustomSecurityServerInputFilter(Me)
End Function 'CreateServiceInputFilter
Public Overrides Function CreateServiceOutputFilter(ByVal context As FilterCreationContext) As SoapFilter
Return New CustomSecurityServerOutputFilter(Me)
End Function 'CreateServiceOutputFilter
Public Overrides Sub ReadXml(ByVal reader As XmlReader, ByVal extensions As IDictionary(Of String, Type))
If reader Is Nothing Then
Throw New ArgumentNullException("reader")
End If
If extensions Is Nothing Then
Throw New ArgumentNullException("extensions")
End If
Dim isEmpty As Boolean = reader.IsEmptyElement
MyBase.ReadAttributes(reader)
reader.ReadStartElement("CustomSecurityAssertion")
If Not isEmpty Then
' Read the contents of the <clientToken> element.
If reader.MoveToContent() = XmlNodeType.Element AndAlso reader.Name = "clientToken" Then
reader.ReadStartElement()
reader.MoveToContent()
' Get the registed security token provider for X.509 certificate security credentials.
Dim type As Type = extensions(reader.Name)
Dim instance As Object = Activator.CreateInstance(type)
If instance Is Nothing Then
Throw New InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type 0End.", type.AssemblyQualifiedName))
End If
Dim clientProvider As TokenProvider(Of X509SecurityToken) = CType(instance, TokenProvider(Of X509SecurityToken))
' Read the child elements that provide the details about the client's X.509 certificate.
clientProvider.ReadXml(reader, extensions)
Me.ClientX509TokenProvider = clientProvider
reader.ReadEndElement()
End If
' Read the contents of the <serviceToken> element.
If reader.MoveToContent() = XmlNodeType.Element AndAlso reader.Name = "serviceToken" Then
reader.ReadStartElement()
reader.MoveToContent()
' Get the registed security token provider for X.509 certificate security credentials.
Dim type As Type = extensions(reader.Name)
Dim instance As Object = Activator.CreateInstance(type)
If instance Is Nothing Then
Throw New InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type 0End.", type.AssemblyQualifiedName))
End If
Dim serviceProvider As TokenProvider(Of X509SecurityToken) = CType(instance, TokenProvider(Of X509SecurityToken))
' Read the child elements that provide the details about the client's X.509 certificate.
serviceProvider.ReadXml(reader, extensions)
Me.ServiceX509TokenProvider = serviceProvider
reader.ReadEndElement()
End If
MyBase.ReadElements(reader, extensions)
reader.ReadEndElement()
End If
End Sub
Public Overrides Function GetExtensions() As IEnumerable(Of KeyValuePair(Of String, Type))
' Add the CustomSecurityAssertion custom policy assertion to the list of registered
' policy extensions.
Dim extensions As New List(Of KeyValuePair(Of String, Type))
extensions.Add(New KeyValuePair(Of String, Type)("CustomSecurityAssertion", Me.GetType()))
If (Not serviceX509TokenProviderValue Is Nothing) Then
' Add any policy extensions that read child elements of the <serviceToken> element
' to the list of registered policy extensions.
Dim innerExtensions As IEnumerable(Of KeyValuePair(Of String, Type)) = serviceX509TokenProviderValue.GetExtensions()
If (Not innerExtensions Is Nothing) Then
Dim extension As KeyValuePair(Of String, Type)
For Each extension In innerExtensions
extensions.Add(extension)
Next
End If
End If
If (Not clientX509TokenProviderValue Is Nothing) Then
' Add any policy extensions that read child elements of the <clientToken> element
' to the list of registered policy extensions.
Dim innerExtensions As IEnumerable(Of KeyValuePair(Of String, Type)) = clientX509TokenProviderValue.GetExtensions()
If (Not innerExtensions Is Nothing) Then
Dim extension As KeyValuePair(Of String, Type)
For Each extension In innerExtensions
extensions.Add(extension)
Next
End If
End If
Return extensions
End Function
End Class 'CustomSecurityAssertion
Class RequestState
Private clientTokenValue As SecurityToken
Private serverTokenValue As SecurityToken
Public Sub New(ByVal cToken As SecurityToken, ByVal sToken As SecurityToken)
clientTokenValue = cToken
serverTokenValue = sToken
End Sub 'New
Public ReadOnly Property ClientToken() As SecurityToken
Get
Return clientTokenValue
End Get
End Property
Public ReadOnly Property ServerToken() As SecurityToken
Get
Return serverTokenValue
End Get
End Property
End Class 'RequestState
Class CustomSecurityServerInputFilter
Inherits ReceiveSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion)
MyBase.New(parentAssertion.ServiceActor, False)
End Sub 'New
Public Overrides Sub ValidateMessageSecurity(ByVal envelope As SoapEnvelope, ByVal security As Security)
Dim clientToken As SecurityToken = Nothing
Dim serverToken As SecurityToken = Nothing
' Ensure incoming SOAP messages are signed and encrypted.
Dim elem As ISecurityElement
For Each elem In security.Elements
If TypeOf elem Is MessageSignature Then
Dim sig As MessageSignature = CType(elem, MessageSignature)
clientToken = sig.SigningToken
End If
If TypeOf elem Is EncryptedData Then
Dim enc As EncryptedData = CType(elem, EncryptedData)
serverToken = enc.SecurityToken
End If
Next elem
If clientToken Is Nothing OrElse serverToken Is Nothing Then
Throw New Exception("Incoming message did not meet security requirements")
End If
Dim state As New RequestState(clientToken, serverToken)
envelope.Context.OperationState.Set(state)
End Sub 'ValidateMessageSecurity
End Class 'CustomSecurityServerInputFilter
Class CustomSecurityServerOutputFilter
Inherits SendSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion)
MyBase.New(parentAssertion.ServiceActor, False)
End Sub 'New
Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, ByVal security As Security)
Dim state As RequestState = envelope.Context.OperationState.Get(Of RequestState)()
' Sign the message with the Web service's security token.
security.Tokens.Add(state.ServerToken)
security.Elements.Add(New MessageSignature(state.ServerToken))
' Encrypt the message with the client's security token.
security.Elements.Add(New EncryptedData(state.ClientToken))
End Sub 'SecureMessage
End Class 'CustomSecurityServerOutputFilter
Class CustomSecurityClientInputFilter
Inherits ReceiveSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion)
MyBase.New(parentAssertion.ServiceActor, True)
End Sub 'New
Public Overrides Sub ValidateMessageSecurity(ByVal envelope As SoapEnvelope, ByVal security As Security)
Dim state As RequestState
Dim signed As Boolean = False
Dim encrypted As Boolean = False
' Get the request state out of the operation state.
state = envelope.Context.OperationState.Get(Of RequestState)()
' Make sure the message was signed with the server's security token.
Dim elem As ISecurityElement
For Each elem In security.Elements
If TypeOf elem Is MessageSignature Then
Dim sig As MessageSignature = CType(elem, MessageSignature)
If sig.SigningToken.Equals(state.ServerToken) Then
signed = True
End If
End If
If TypeOf elem Is EncryptedData Then
Dim enc As EncryptedData = CType(elem, EncryptedData)
If enc.SecurityToken.Equals(state.ClientToken) Then
encrypted = True
End If
End If
Next elem
If Not signed OrElse Not encrypted Then
Throw New Exception("Response message does not meet security requirements")
End If
End Sub 'ValidateMessageSecurity
End Class 'CustomSecurityClientInputFilter
Class CustomSecurityClientOutputFilter
Inherits SendSecurityFilter
Private clientToken As SecurityToken
Private serverToken As SecurityToken
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion)
MyBase.New(parentAssertion.ServiceActor, True)
' Get the client security token.
clientToken = X509TokenProvider.CreateToken(StoreLocation.CurrentUser, StoreName.My, "CN=WSE2QuickStartClient")
' Get the server security token.
serverToken = X509TokenProvider.CreateToken(StoreLocation.LocalMachine, StoreName.My, "CN=WSE2QuickStartServer")
End Sub 'New
Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, ByVal security As Security)
' Sign the SOAP message with the client's security token.
security.Tokens.Add(clientToken)
security.Elements.Add(New MessageSignature(clientToken))
' Encrypt the SOAP message with the client's security token.
security.Elements.Add(New EncryptedData(serverToken))
' Encrypt the client's security token with the server's security token.
security.Elements.Add(New EncryptedData(serverToken, "#" + clientToken.Id))
' Store the client and server security tokens in the request state.
Dim state As New RequestState(clientToken, serverToken)
' Store the request state in the proxy's operation state.
' This makes these tokens accessible when SOAP responses are
' verified to have sufficient security requirements.
envelope.Context.OperationState.Set(state)
End Sub 'SecureMessage
End Class 'CustomSecurityClientOutputFilter
End Namespace
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Design;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;
namespace CustomPolicyAssertions
{
class CustomSecurityAssertion : SecurityPolicyAssertion
{
TokenProvider<X509SecurityToken> serviceX509TokenProviderValue;
TokenProvider<X509SecurityToken> clientX509TokenProviderValue;
public TokenProvider<X509SecurityToken> ClientX509TokenProvider
{
get
{
return clientX509TokenProviderValue;
}
set
{
clientX509TokenProviderValue = value;
}
}
public TokenProvider<X509SecurityToken> ServiceX509TokenProvider
{
get
{
return serviceX509TokenProviderValue;
}
set
{
serviceX509TokenProviderValue = value;
}
}
public CustomSecurityAssertion()
: base()
{
}
public override SoapFilter CreateClientOutputFilter(FilterCreationContext context)
{
return new CustomSecurityClientOutputFilter(this);
}
public override SoapFilter CreateClientInputFilter(FilterCreationContext context)
{
return new CustomSecurityClientInputFilter(this);
}
public override SoapFilter CreateServiceInputFilter(FilterCreationContext context)
{
return new CustomSecurityServerInputFilter(this);
}
public override SoapFilter CreateServiceOutputFilter(FilterCreationContext context)
{
return new CustomSecurityServerOutputFilter(this);
}
public override void ReadXml(System.Xml.XmlReader reader, IDictionary<string, Type> extensions)
{
if (reader == null)
throw new ArgumentNullException("reader");
if (extensions == null)
throw new ArgumentNullException("extensions");
bool isEmpty = reader.IsEmptyElement;
base.ReadAttributes(reader);
reader.ReadStartElement("CustomSecurityAssertion");
if (!isEmpty)
{
if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "clientToken")
{
reader.ReadStartElement();
reader.MoveToContent();
// Get the registed security token provider for X.509 certificate security credentials.
Type type = extensions[reader.Name];
object instance = Activator.CreateInstance(type);
if (instance == null)
throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type {0}.", type.AssemblyQualifiedName));
TokenProvider<X509SecurityToken> clientProvider = instance as TokenProvider<X509SecurityToken>;
// Read the child elements that provide the details about the client's X.509 certificate.
clientProvider.ReadXml(reader, extensions);
this.ClientX509TokenProvider = clientProvider;
reader.ReadEndElement();
}
if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "serviceToken")
{
reader.ReadStartElement();
reader.MoveToContent();
// Get the registed security token provider for X.509 certificate security credentials.
Type type = extensions[reader.Name];
object instance = Activator.CreateInstance(type);
if (instance == null)
throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Unable to instantiate policy extension of type {0}.", type.AssemblyQualifiedName));
TokenProvider<X509SecurityToken> serviceProvider = instance as TokenProvider<X509SecurityToken>;
// Read the child elements that provide the details about the Web service's X.509 certificate.
serviceProvider.ReadXml(reader, extensions);
this.ServiceX509TokenProvider = serviceProvider;
reader.ReadEndElement();
}
base.ReadElements(reader, extensions);
reader.ReadEndElement();
}
}
public override IEnumerable<KeyValuePair<string, Type>> GetExtensions()
{
// Add the CustomSecurityAssertion custom policy assertion to the list of registered
// policy extensions.
List<KeyValuePair<string, Type>> extensions = new List<KeyValuePair<string, Type>>();
extensions.Add(new KeyValuePair<string, Type>("CustomSecurityAssertion", this.GetType()));
if (serviceX509TokenProviderValue != null)
{
// Add any policy extensions that read child elements of the <serviceToken> element
// to the list of registered policy extensions.
IEnumerable<KeyValuePair<string, Type>> innerExtensions = serviceX509TokenProviderValue.GetExtensions();
if (innerExtensions != null)
{
foreach (KeyValuePair<string, Type> extension in innerExtensions)
{
extensions.Add(extension);
}
}
}
if (clientX509TokenProviderValue != null)
{
// Add any policy extensions that read child elements of the <clientToken> element
// to the list of registered policy extensions.
IEnumerable<KeyValuePair<string, Type>> innerExtensions = clientX509TokenProviderValue.GetExtensions();
if (innerExtensions != null)
{
foreach (KeyValuePair<string, Type> extension in innerExtensions)
{
extensions.Add(extension);
}
}
}
return extensions;
}
// </snippet16
}
class RequestState
{
SecurityToken clientToken;
SecurityToken serverToken;
public RequestState(SecurityToken cToken, SecurityToken sToken)
{
clientToken = cToken;
serverToken = sToken;
}
public SecurityToken ClientToken
{
get { return clientToken; }
}
public SecurityToken ServerToken
{
get { return serverToken; }
}
}
class CustomSecurityServerInputFilter : ReceiveSecurityFilter
{
public CustomSecurityServerInputFilter(CustomSecurityAssertion parentAssertion)
: base(parentAssertion.ServiceActor, false)
{
}
public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security)
{
SecurityToken clientToken = null;
SecurityToken serverToken = null;
// Ensure incoming SOAP messages are signed and encrypted.
foreach (ISecurityElement elem in security.Elements)
{
if (elem is MessageSignature)
{
MessageSignature sig = (MessageSignature)elem;
clientToken = sig.SigningToken;
}
if (elem is EncryptedData)
{
EncryptedData enc = (EncryptedData)elem;
serverToken = enc.SecurityToken;
}
}
if (clientToken == null || serverToken == null)
throw new Exception("Incoming message did not meet security requirements");
RequestState state = new RequestState(clientToken, serverToken);
envelope.Context.OperationState.Set(state);
}
}
class CustomSecurityServerOutputFilter : SendSecurityFilter
{
public CustomSecurityServerOutputFilter(CustomSecurityAssertion parentAssertion)
: base(parentAssertion.ServiceActor,false )
{
}
public override void SecureMessage(SoapEnvelope envelope, Security security)
{
RequestState state = envelope.Context.OperationState.Get<RequestState>();
// Sign the message with the Web service's security token.
security.Tokens.Add(state.ServerToken);
security.Elements.Add(new MessageSignature(state.ServerToken));
// Encrypt the message with the client's security token.
security.Elements.Add(new EncryptedData(state.ClientToken));
}
}
class CustomSecurityClientInputFilter : ReceiveSecurityFilter
{
public CustomSecurityClientInputFilter(CustomSecurityAssertion parentAssertion)
: base(parentAssertion.ServiceActor,true )
{
}
public override void ValidateMessageSecurity(SoapEnvelope envelope, Security security)
{
RequestState state;
bool signed = false;
bool encrypted = false;
// Get the request state out of the operation state.
state = envelope.Context.OperationState.Get<RequestState>();
// Make sure the message was signed with the server's security token.
foreach (ISecurityElement elem in security.Elements)
{
if (elem is MessageSignature)
{
MessageSignature sig = (MessageSignature)elem;
if (sig.SigningToken.Equals(state.ServerToken))
signed = true;
}
if (elem is EncryptedData)
{
EncryptedData enc = (EncryptedData)elem;
if (enc.SecurityToken.Equals(state.ClientToken))
encrypted = true;
}
}
if (!signed || !encrypted)
throw new Exception("Response message does not meet security requirements");
}
}
class CustomSecurityClientOutputFilter : SendSecurityFilter
{
SecurityToken clientToken;
SecurityToken serverToken;
public CustomSecurityClientOutputFilter(CustomSecurityAssertion parentAssertion)
: base(parentAssertion.ServiceActor,true )
{
// Get the client security token.
clientToken = X509TokenProvider.CreateToken(StoreLocation.CurrentUser, StoreName.My, "CN=WSE2QuickStartClient");
// Get the server security token.
serverToken = X509TokenProvider.CreateToken(StoreLocation.LocalMachine, StoreName.My, "CN=WSE2QuickStartServer");
}
public override void SecureMessage(SoapEnvelope envelope, Security security)
{
// Sign the SOAP message with the client's security token.
security.Tokens.Add(clientToken);
security.Elements.Add(new MessageSignature(clientToken));
// Encrypt the SOAP message with the client's security token.
security.Elements.Add(new EncryptedData(serverToken));
// Encrypt the client's security token with the server's security token.
security.Elements.Add(new EncryptedData(serverToken, "#" + clientToken.Id));
// Store the client and server security tokens in the request state.
RequestState state = new RequestState(clientToken, serverToken);
// Store the request state in the proxy's operation state.
// This makes these tokens accessible when SOAP responses are
// verified to have sufficient security requirements.
envelope.Context.OperationState.Set(state);
}
}
}
See Also
Tasks
How to: Create a Custom Policy Assertion that does not Secure SOAP Messages
How to: Secure an Application Using a Custom Policy Assertion
Reference
SecurityPolicyAssertion
ReceiveSecurityFilter
SendSecurityFilter
PolicyAssertion
SoapFilter