The case need to create .net framework 3 web site client to refer the Axis2 web services with WSS4J Security (WS-Security specification 1.0). Need to custom SOAP Header and signature.
As all knows, visual studio 2008 doesn't integrated with WSE 3.0, also since the current VS project is web site instead of web application, the proxy file of web service is dynamic with DLL file which means you are not able to change it. Here find a new way to tackle with it.
Here's the main steps and code reference.
- Setup WSE 3.0 (Download from Microsoft web site and install)
- Convert the JKS to PFX keystore file. ( Mentioned at last blog post)
- Create a new Class Library project into the solution.
- Add web reference and designate the WSDL (Provided from Axis2 web service) file. ( You will find the proxy file named reference.vb in the same folder with wsdl file at this Class Library project.
- Click to open WSE 3.0 configuration tool and click menu open the file app.config which in Class Library project folder.
- Click on "Enable this project for Web Services Enhancements" under General panel, and Enable Policy and Add a new Policy with a new name under Policy panel. If you want to get debugging soap packet, Enable Message Trace and designate Input and Output File under Diagnostics panel and then click menu File and Save it.
- Update part of the app.config as follows snapshot:
- Find the file named wse3policyCache.config and update it as snapshot:
- Create a new class file as bottom coding:
- Build the Class Library project and debugging.
- From main web site, add reference for this new project and there should be a new dll happens in Bin folder.
- Refer to the DLL project namespace with web service name to access.
- Rebuild main web site and test them out.
File: CustomSecurityAssertion.vb
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 GiftRegistryProxy
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 New CustomSecurityClientOutputFilter(Me)
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 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 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 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 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
Protected keystore As String = System.Configuration.ConfigurationManager.AppSettings("keystore")
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=Customretailergrworksservice, OU=Custom, O=MarCoole, L=Walnut Creek, S=California, C=US")
'####################### Start update for key handler
Dim cert As X509Certificate2 = New X509Certificate2(keystore, "CustomGRWorksServiceRetailer")
clientToken = New X509SecurityToken(cert)
'####################### End update for key handler
' Get the server security token.
serverToken = X509TokenProvider.CreateToken(StoreLocation.LocalMachine, StoreName.My, "CN=Customretailergrworksservice, OU=Custom, O=MarCoole, L=Walnut Creek, S=California, C=US")
End Sub 'New
Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, ByVal security As Security)
'Dim token As X509SecurityToken = GetSecurityToken("CN=Customretailergrworksservice, OU=Custom, O=MarCoole, L=Walnut Creek, S=California, C=US")
'####################### Start update for key handler
Dim cert As X509Certificate2 = New X509Certificate2(keystore, "CustomGRWorksServiceRetailer")
Dim token = New X509SecurityToken(cert)
'####################### End update for key handler
If token Is Nothing Then
Throw New SecurityFault("Message Requirements could not be satisfied.")
End If
' Add the security token to the WS-Security SOAP header.
security.Tokens.Add(token)
' Specify the security token to sign the message with.
Dim sig As New MessageSignature(token)
security.Elements.Add(sig)
'######################################### Start xml header definition
security.EncodedMustUnderstand = "0"
'creating the custom element in the outgoing message
Dim securityNode As XmlNode = envelope.CreateNode(XmlNodeType.Element, "wsse:Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")
'creating the element
Dim binarySecurityTokenNode As XmlNode = envelope.CreateNode(XmlNodeType.Element, "wsse:BinarySecurityToken", "")
Dim binaryElement As XmlElement = binarySecurityTokenNode
binaryElement.SetAttribute("xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")
binaryElement.SetAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3")
binaryElement.SetAttribute("wsu:Id", "CertId-3221922")
binaryElement.SetAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary")
binarySecurityTokenNode.InnerText = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
securityNode.AppendChild(binarySecurityTokenNode)
envelope.ImportNode(securityNode, True)
Dim node As XmlNode = envelope.Header
node.AppendChild(securityNode)
'######################################### End xml header definition
End Sub 'SecureMessage
End Class 'CustomSecurityClientOutputFilter
End Namespace
No comments:
Post a Comment