Share via


방법: WCF 클라이언트를 사용하여 WSE 3.0 서비스에 액세스

WCF(Windows Communication Foundation) 클라이언트는 WCF 클라이언트가 2004년 8월 버전의 WS-Addressing 사양을 사용하도록 구성된 경우 Microsoft .NET 서비스용 WSE(Web Services Enhancements) 3.0과 유선 수준으로 호환됩니다. 그러나 WSE 3.0 서비스는 MEX(메타데이터 교환) 프로토콜을 지원하지 않으므로 ServiceModel 메타데이터 유틸리티 도구(Svcutil.exe)를 사용하여 WCF 클라이언트 클래스를 만들 때 보안 설정이 만들어진 WCF 클라이언트에 적용되지 않습니다. 그러므로 WCF 클라이언트가 생성된 후에 WSE 3.0 서비스를 사용하도록 보안 설정을 지정해야 합니다.

사용자 지정 바인딩을 사용하여 이러한 보안 설정을 적용함으로써 WSE 3.0 서비스와 WCF 클라이언트 간의 상호 운용 가능한 요구 사항 및 WSE 3.0 서비스의 요구 사항을 고려할 수 있습니다. 이러한 상호 운용성 요구 사항에는 앞에서 말한 August 2004 WS-Addressing 사양 및 WSE 3.0의 SignBeforeEncrypt 기본 메시지 보호를 사용하는 것이 포함됩니다. WCF의 기본 메시지 보호는 SignBeforeEncryptAndEncryptSignature입니다. 이 항목에서는 WSE 3.0 서비스와 상호 운용되는 WCF 바인딩을 만드는 방법을 자세히 설명합니다. WCF에서는 이 바인딩을 통합하는 샘플도 제공합니다. 이 샘플에 대한 자세한 내용은 ASMX 웹 서비스와의 상호 운용을 참조하세요.

WCF 클라이언트를 사용하여 WSE 3.0 웹 서비스에 액세스하려면

  1. ServiceModel 메타데이터 유틸리티 도구(Svcutil.exe)를 실행하여 WSE 3.0 웹 서비스용 WCF 클라이언트를 만듭니다.

    WSE 3.0 웹 서비스의 경우 WCF 클라이언트가 만들어집니다. WSE 3.0이 MEX 프로토콜을 지원하지 않으므로 해당 도구를 사용하여 웹 서비스에 대한 보안 요구 사항을 검색할 수 없습니다. 애플리케이션 개발자는 해당 클라이언트에 대한 보안 설정을 추가해야 합니다.

    WCF 클라이언트 만들기에 대한 자세한 내용은 방법: 클라이언트 만들기를 참조하세요.

  2. WSE 3.0 웹 서비스와 통신할 수 있는 바인딩을 나타내는 클래스를 만듭니다.

    다음 클래스는 WSE와 상호 운용 샘플의 일부입니다.

    1. Binding 클래스에서 파생되는 클래스를 만듭니다.

      다음 코드 예제에서는 WseHttpBinding 클래스로부터 파생되는 Binding이라는 클래스를 만듭니다.

      public class WseHttpBinding : Binding
      {
      
      Public Class WseHttpBinding
          Inherits Binding
      
    2. WSE 서비스에서 사용되는 WSE 턴키 어설션, 파생된 키가 필요한지 여부, 보안 세션이 사용되는지 여부, 서명 확인이 필요한지 여부 및 메시지 보호 설정을 지정하는 클래스에 속성을 추가합니다. WSE 3.0에서는 턴키 어설션이 클라이언트 또는 웹 서비스에 대한 보안 요구 사항을 지정하며, 이는 WCF에서 바인딩의 인증 모드와 유사합니다.

      다음 코드 예제에서는 WSE 턴키 어설션, 파생된 키가 필요한지 여부, 보안 세션이 사용되는지 여부, 서명 확인이 필요한지 여부 및 메시지 보호 설정을 각각 지정하는 SecurityAssertion, RequireDerivedKeys, EstablishSecurityContextMessageProtectionOrder 속성을 정의합니다.

      
      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
      
    3. CreateBindingElements 메서드를 재정의하여 바인딩 속성을 설정합니다.

      다음 코드 예제에서는 SecurityAssertionMessageProtectionOrder 속성의 값을 가져옴으로써 전송, 메시지 인코딩, 메시지 보호 설정을 지정합니다.

      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
      
  3. 클라이언트 애플리케이션 코드에서 바인딩 속성을 설정하기 위해 코드를 추가합니다.

    다음 코드 예에서는 WSE 3.0 AnonymousForCertificate 턴키 보안 어설션에 정의된 대로 WCF 클라이언트가 반드시 메시지 보호 및 인증을 사용하도록 지정합니다. 또한 보안 세션 및 파생된 키도 필요합니다.

    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)
    

예시

다음 코드 예제에서는 WSE 3.0 턴키 보안 어설션의 속성에 해당하는 속성을 노출하는 사용자 지정 바인딩을 정의합니다. 그러면 WSSecurityAnonymous WSE 3.0 QuickStart 샘플과 통신하는 WCF 클라이언트에 대한 바인딩 속성을 지정하는 데 WseHttpBinding이라는 사용자 지정 바인딩이 사용됩니다.

참고 항목