Como acessar um serviço WSE 3.0 com um cliente do WCF
Os clientes do Windows Communication Foundation (WCF) são compatíveis com o nível de conexão com Aprimoramentos de Serviços Web (WSE) 3.0 para serviços do Microsoft .NET quando os clientes do WCF são configurados para usar a versão de agosto de 2004 da especificação WS-Addressing. No entanto, os serviços WSE 3.0 não suportam o protocolo de troca de metadados (MEX), portanto, quando você usa a Ferramenta de utilitário de metadados ServiceModel (Svcutil.exe) para criar uma classe de cliente WCF, as configurações de segurança não são aplicadas a o cliente WCF gerado. Portanto, você deve especificar as configurações de segurança que o serviço WSE 3.0 exige após a geração do cliente WCF.
Você pode aplicar essas configurações de segurança usando uma associação personalizada para levar em conta os requisitos do serviço WSE 3.0 e os requisitos interoperáveis entre um serviço WSE 3.0 e um cliente WCF. Esses requisitos de interoperabilidade incluem o uso acima mencionado da especificação WS-Addressing de agosto de 2004 e a proteção de mensagem padrão WSE 3.0 de SignBeforeEncrypt. A proteção de mensagem padrão para WCF é SignBeforeEncryptAndEncryptSignature. Este tópico detalha como criar uma associação WCF que interopera com um serviço WSE 3.0. O WCF também fornece um exemplo que incorpora essa associação. Para obter mais informações sobre este exemplo, consulte Interoperando com ASMX Web Services.
Para acessar um serviço da Web WSE 3.0 com um cliente WCF
Execute a Ferramenta de utilitário de metadados ServiceModel (Svcutil.exe) para criar um cliente WCF para o serviço Web WSE 3.0.
Para um serviço Web WSE 3.0, um cliente WCF é criado. Como o WSE 3.0 não oferece suporte ao protocolo MEX, você não pode usar a ferramenta para recuperar os requisitos de segurança do serviço Web. O desenvolvedor do aplicativo deve adicionar as configurações de segurança para o cliente.
Para obter mais informações sobre como criar um cliente WCF, consulte Como: criar um cliente.
Crie uma classe que represente uma associação que possa se comunicar com os serviços da Web WSE 3.0.
A classe a seguir faz parte do exemplo interoperação com o WSE:
Crie uma classe que derive da classe Binding.
O exemplo de código a seguir cria uma classe chamada
WseHttpBinding
que deriva da classe Binding.public class WseHttpBinding : Binding {
Public Class WseHttpBinding Inherits Binding
Adicione propriedades à classe que especificam a declaração pronta para uso do WSE usada pelo serviço WSE, se as chaves derivadas são necessárias, se as sessões seguras são usadas, se as confirmações de assinatura são necessárias e as configurações de proteção de mensagem. No WSE 3.0, uma declaração pronta para uso especifica os requisitos de segurança para um cliente ou serviço da Web — semelhante ao modo de autenticação de uma associação no WCF.
O exemplo de código a seguir define as propriedades
SecurityAssertion
,RequireDerivedKeys
,EstablishSecurityContext
eMessageProtectionOrder
que especificam a declaração pronta para uso do WSE, se as chaves derivadas são necessárias, se as sessões seguras são usadas, se as confirmações de assinatura são necessárias e o configurações de proteção de mensagens, respectivamente.private WseSecurityAssertion assertion; public WseSecurityAssertion SecurityAssertion { get { return assertion; } set { assertion = value; } } private bool requireDerivedKeys; public bool RequireDerivedKeys { get { return requireDerivedKeys; } set { requireDerivedKeys = value; } } private bool establishSecurityContext; public bool EstablishSecurityContext { get { return establishSecurityContext; } set { establishSecurityContext = value; } } private bool requireSignatureConfirmation; public bool RequireSignatureConfirmation { get { return requireSignatureConfirmation; } set { requireSignatureConfirmation = value; } } private MessageProtectionOrder messageProtectionOrder; public MessageProtectionOrder MessageProtectionOrder { get { return messageProtectionOrder; } set { messageProtectionOrder = value; } }
Public Property SecurityAssertion() As WseSecurityAssertion Get Return assertion End Get Set(ByVal value As WseSecurityAssertion) assertion = value End Set End Property Private m_requireDerivedKeys As Boolean Public Property RequireDerivedKeys() As Boolean Get Return m_requireDerivedKeys End Get Set(ByVal value As Boolean) m_requireDerivedKeys = value End Set End Property Private m_establishSecurityContext As Boolean Public Property EstablishSecurityContext() As Boolean Get Return m_establishSecurityContext End Get Set(ByVal value As Boolean) m_establishSecurityContext = value End Set End Property Private m_requireSignatureConfirmation As Boolean Public Property RequireSignatureConfirmation() As Boolean Get Return m_requireSignatureConfirmation End Get Set(ByVal value As Boolean) m_requireSignatureConfirmation = value End Set End Property Private m_messageProtectionOrder As MessageProtectionOrder Public Property MessageProtectionOrder() As MessageProtectionOrder Get Return m_messageProtectionOrder End Get Set(ByVal value As MessageProtectionOrder) m_messageProtectionOrder = value End Set End Property
Substitua o método CreateBindingElements para definir as propriedades de associação.
O exemplo de código a seguir especifica as configurações de transporte, codificação de mensagem e proteção de mensagem obtendo os valores das propriedades
SecurityAssertion
eMessageProtectionOrder
.public override BindingElementCollection CreateBindingElements() { //SecurityBindingElement sbe = bec.Find<SecurityBindingElement>(); BindingElementCollection bec = new BindingElementCollection(); // By default http transport is used SecurityBindingElement securityBinding; BindingElement transport; switch (assertion) { case WseSecurityAssertion.UsernameOverTransport: transport = new HttpsTransportBindingElement(); securityBinding = (TransportSecurityBindingElement)SecurityBindingElement.CreateUserNameOverTransportBindingElement(); if (establishSecurityContext == true) throw new InvalidOperationException("Secure Conversation is not supported for this Security Assertion Type"); if (requireSignatureConfirmation == true) throw new InvalidOperationException("Signature Confirmation is not supported for this Security Assertion Type"); break; case WseSecurityAssertion.MutualCertificate10: transport = new HttpTransportBindingElement(); securityBinding = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10); if (requireSignatureConfirmation == true) throw new InvalidOperationException("Signature Confirmation is not supported for this Security Assertion Type"); ((AsymmetricSecurityBindingElement)securityBinding).MessageProtectionOrder = messageProtectionOrder; break; case WseSecurityAssertion.UsernameForCertificate: transport = new HttpTransportBindingElement(); securityBinding = (SymmetricSecurityBindingElement)SecurityBindingElement.CreateUserNameForCertificateBindingElement(); // We want signatureconfirmation on the bootstrap process // either for the application messages or for the RST/RSTR ((SymmetricSecurityBindingElement)securityBinding).RequireSignatureConfirmation = requireSignatureConfirmation; ((SymmetricSecurityBindingElement)securityBinding).MessageProtectionOrder = messageProtectionOrder; break; case WseSecurityAssertion.AnonymousForCertificate: transport = new HttpTransportBindingElement(); securityBinding = (SymmetricSecurityBindingElement)SecurityBindingElement.CreateAnonymousForCertificateBindingElement(); ((SymmetricSecurityBindingElement)securityBinding).RequireSignatureConfirmation = requireSignatureConfirmation; ((SymmetricSecurityBindingElement)securityBinding).MessageProtectionOrder = messageProtectionOrder; break; case WseSecurityAssertion.MutualCertificate11: transport = new HttpTransportBindingElement(); securityBinding = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11); ((SymmetricSecurityBindingElement)securityBinding).RequireSignatureConfirmation = requireSignatureConfirmation; ((SymmetricSecurityBindingElement)securityBinding).MessageProtectionOrder = messageProtectionOrder; break; case WseSecurityAssertion.Kerberos: transport = new HttpTransportBindingElement(); securityBinding = (SymmetricSecurityBindingElement)SecurityBindingElement.CreateKerberosBindingElement(); ((SymmetricSecurityBindingElement)securityBinding).RequireSignatureConfirmation = requireSignatureConfirmation; ((SymmetricSecurityBindingElement)securityBinding).MessageProtectionOrder = messageProtectionOrder; break; default: throw new NotSupportedException("This supplied Wse security assertion is not supported"); } //Set defaults for the security binding securityBinding.IncludeTimestamp = true; // Derived Keys // set the preference for derived keys before creating SecureConversationBindingElement securityBinding.SetKeyDerivation(requireDerivedKeys); //Secure Conversation if (establishSecurityContext == true) { SymmetricSecurityBindingElement secureconversation = (SymmetricSecurityBindingElement)SymmetricSecurityBindingElement.CreateSecureConversationBindingElement( securityBinding, false); // This is the default //secureconversation.DefaultProtectionLevel = ProtectionLevel.EncryptAndSign; //Set defaults for the secure conversation binding secureconversation.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256; // We do not want signature confirmation on the application level messages // when secure conversation is enabled. secureconversation.RequireSignatureConfirmation = false; secureconversation.MessageProtectionOrder = messageProtectionOrder; secureconversation.SetKeyDerivation(requireDerivedKeys); securityBinding = secureconversation; } // Add the security binding to the binding collection bec.Add(securityBinding); // Add the message encoder. TextMessageEncodingBindingElement textelement = new TextMessageEncodingBindingElement(); textelement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004; //These are the defaults required for WSE //textelement.MessageVersion = MessageVersion.Soap11Addressing1; //textelement.WriteEncoding = System.Text.Encoding.UTF8; bec.Add(textelement); // Add the transport bec.Add(transport); // return the binding elements return bec; }
Public Overloads Overrides Function CreateBindingElements() As BindingElementCollection 'SecurityBindingElement sbe = bec.Find<SecurityBindingElement>(); Dim bec As New BindingElementCollection() ' By default http transport is used Dim securityBinding As SecurityBindingElement Dim transport As BindingElement Select Case assertion Case WseSecurityAssertion.UsernameOverTransport transport = New HttpsTransportBindingElement() securityBinding = DirectCast(SecurityBindingElement.CreateUserNameOverTransportBindingElement(), TransportSecurityBindingElement) If m_establishSecurityContext = True Then Throw New InvalidOperationException("Secure Conversation is not supported for this Security Assertion Type") End If If m_requireSignatureConfirmation = True Then Throw New InvalidOperationException("Signature Confirmation is not supported for this Security Assertion Type") End If Exit Select Case WseSecurityAssertion.MutualCertificate10 transport = New HttpTransportBindingElement() securityBinding = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10) If m_requireSignatureConfirmation = True Then Throw New InvalidOperationException("Signature Confirmation is not supported for this Security Assertion Type") End If DirectCast(securityBinding, AsymmetricSecurityBindingElement).MessageProtectionOrder = m_messageProtectionOrder Exit Select Case WseSecurityAssertion.UsernameForCertificate transport = New HttpTransportBindingElement() securityBinding = DirectCast(SecurityBindingElement.CreateUserNameForCertificateBindingElement(), SymmetricSecurityBindingElement) ' We want signatureconfirmation on the bootstrap process ' either for the application messages or for the RST/RSTR DirectCast(securityBinding, SymmetricSecurityBindingElement).RequireSignatureConfirmation = m_requireSignatureConfirmation DirectCast(securityBinding, SymmetricSecurityBindingElement).MessageProtectionOrder = m_messageProtectionOrder Exit Select Case WseSecurityAssertion.AnonymousForCertificate transport = New HttpTransportBindingElement() securityBinding = DirectCast(SecurityBindingElement.CreateAnonymousForCertificateBindingElement(), SymmetricSecurityBindingElement) DirectCast(securityBinding, SymmetricSecurityBindingElement).RequireSignatureConfirmation = m_requireSignatureConfirmation DirectCast(securityBinding, SymmetricSecurityBindingElement).MessageProtectionOrder = m_messageProtectionOrder Exit Select Case WseSecurityAssertion.MutualCertificate11 transport = New HttpTransportBindingElement() securityBinding = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11) DirectCast(securityBinding, SymmetricSecurityBindingElement).RequireSignatureConfirmation = m_requireSignatureConfirmation DirectCast(securityBinding, SymmetricSecurityBindingElement).MessageProtectionOrder = m_messageProtectionOrder Exit Select Case WseSecurityAssertion.Kerberos transport = New HttpTransportBindingElement() securityBinding = DirectCast(SecurityBindingElement.CreateKerberosBindingElement(), SymmetricSecurityBindingElement) DirectCast(securityBinding, SymmetricSecurityBindingElement).RequireSignatureConfirmation = m_requireSignatureConfirmation DirectCast(securityBinding, SymmetricSecurityBindingElement).MessageProtectionOrder = m_messageProtectionOrder Exit Select Case Else Throw New NotSupportedException("This supplied Wse security assertion is not supported") End Select 'Set defaults for the security binding securityBinding.IncludeTimestamp = True ' Derived Keys ' Set the preference for derived keys before creating the binding for SecureConversation. securityBinding.SetKeyDerivation(m_requireDerivedKeys) 'Secure Conversation If m_establishSecurityContext = True Then Dim secureconversation As SymmetricSecurityBindingElement = DirectCast(SymmetricSecurityBindingElement.CreateSecureConversationBindingElement(securityBinding, False), SymmetricSecurityBindingElement) ' This is the default 'secureconversation.DefaultProtectionLevel = ProtectionLevel.EncryptAndSign; 'Set defaults for the secure conversation binding secureconversation.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256 ' We do not want signature confirmation on the application level messages ' when secure conversation is enabled. secureconversation.RequireSignatureConfirmation = False secureconversation.MessageProtectionOrder = m_messageProtectionOrder secureconversation.SetKeyDerivation(m_requireDerivedKeys) securityBinding = secureconversation End If ' Add the security binding to the binding collection bec.Add(securityBinding) ' Add the message encoder. Dim textelement As New TextMessageEncodingBindingElement() textelement.MessageVersion = System.ServiceModel.Channels.MessageVersion.Soap11WSAddressingAugust2004 'These are the defaults required for WSE 'textelement.MessageVersion = MessageVersion.Soap11Addressing1; 'textelement.WriteEncoding = System.Text.Encoding.UTF8; bec.Add(textelement) ' Add the transport bec.Add(transport) ' return the binding elements Return bec End Function
No código do aplicativo cliente, inclua código para definir as propriedades de associação.
O exemplo de código a seguir especifica que o cliente WCF deve usar proteção e autenticação de mensagens conforme definido pela declaração de segurança pronta para uso do WSE 3.0
AnonymousForCertificate
. Além disso, são necessárias sessões seguras e chaves derivadas.static void CallWseService(bool usePolicyFile) { EndpointAddress address = new EndpointAddress(new Uri("http://localhost/WSSecurityAnonymousPolicy/WSSecurityAnonymousService.asmx"), EndpointIdentity.CreateDnsIdentity("WSE2QuickStartServer")); WseHttpBinding binding = new WseHttpBinding(); if (!usePolicyFile) { binding.SecurityAssertion = WseSecurityAssertion.AnonymousForCertificate; binding.EstablishSecurityContext = true; binding.RequireDerivedKeys = true; binding.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; } else { binding.LoadPolicy("..\\wse3policyCache.config", "ServerPolicy"); } WSSecurityAnonymousServiceSoapClient client = new WSSecurityAnonymousServiceSoapClient(binding, address);
Private Shared Sub CallWseService(ByVal usePolicyFile As Boolean) Dim address As New EndpointAddress(New Uri("http://localhost/WSSecurityAnonymousPolicy/WSSecurityAnonymousService.asmx"), EndpointIdentity.CreateDnsIdentity("WSE2QuickStartServer")) Dim binding As New WseHttpBinding() If Not usePolicyFile Then binding.SecurityAssertion = WseSecurityAssertion.AnonymousForCertificate binding.EstablishSecurityContext = True binding.RequireDerivedKeys = True binding.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt Else binding.LoadPolicy("..\wse3policyCache.config", "ServerPolicy") End If Dim client As New WSSecurityAnonymousServiceSoapClient(binding, address)
Exemplo
O exemplo de código a seguir define uma associação personalizada que expõe propriedades que correspondem às propriedades de uma declaração de segurança pronta para uso do WSE 3.0. Essa associação personalizada, denominada WseHttpBinding
, é então usada para especificar as propriedades de associação para um cliente WCF que se comunica com o exemplo WSSecurityAnonymous WSE 3.0 QuickStart.