Потоковое вложение MTOM в WCF и аутентификация сертификата - PullRequest
0 голосов
/ 17 августа 2011

Я ищу окончательный ответ относительно того, поддерживается ли то, что я пытаюсь сделать, или нет.

По сути, я использую WCF для потоковой передачи больших вложений MTOM (200 Мб), это прекрасно работает. Требования безопасности для службы должны использовать HTTPS и аутентификацию на основе сертификатов. Я могу запустить службу через HTTPS без каких-либо проблем, но как только я установлю в IIS значение «Принимать сертификаты клиента» или «Требовать сертификаты клиента» (без изменений в коде), выдается следующая ошибка (но только после того, как вложения прекратятся 80 Мб или около того):

The socket connection was aborted. 
This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. 
Local socket timeout was '00:30:00'.

Я нашел некоторые ресурсы, извините, не могу найти их сейчас, которые указали, что сбой, вероятно, связан с тем фактом, что входящие сообщения либо не могут быть подписаны цифровой подписью, либо проверены из-за потоковой природы содержимого сообщения. Я полагаю, что службе потребуется хэшировать все содержимое сообщения для проверки сертификата, но этого не может быть достигнуто, потому что части сообщения находятся в процессе передачи, пока выполняется попытка проверки.

Я настроил контракт сообщений так, чтобы тело было одним элементом Stream, а другие элементы содержались в заголовке:

   <MessageContract()>
Public Class StreamAttachmentRequest

    <MessageHeader(MustUnderstand:=True)>
    Public Property AttachmentName As String

    <MessageBodyMember(Order:=1)>
    Public Property Attachment As Stream

End Class

Конфигурация службы выглядит следующим образом:

<system.serviceModel>

<!-- BINDING -->
<bindings>
<basicHttpBinding>
  <binding name="TestCaseBasicBinding"
           messageEncoding="Mtom"
           transferMode="StreamedRequest"
           maxReceivedMessageSize="2147483647"
           closeTimeout="00:30:00"
           openTimeout="00:30:00"
           receiveTimeout="00:30:00"
           sendTimeout="00:30:00">
    <security mode="Transport">
      <transport clientCredentialType="None"></transport>
    </security>
    <readerQuotas maxDepth="32"
                      maxStringContentLength="8192"
                      maxArrayLength="16384"
                      maxBytesPerRead="4096"
                      maxNameTableCharCount="16384" />
  </binding>
</basicHttpBinding>
</bindings>

<!-- BEHAVIORS -->
<behaviors>
  <serviceBehaviors>

    <!-- TEST CASE SECURE BEHAVIOR -->
    <behavior name="TestCaseSecureBehavior">
      <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
      <serviceDebug includeExceptionDetailInFaults="true"/>
      <serviceCredentials>
        <serviceCertificate
            storeLocation="LocalMachine"
            storeName="My"
            findValue="DistinguishedNameOfCert"
            x509FindType="FindBySubjectDistinguishedName" />
        <clientCertificate>
          <authentication certificateValidationMode="ChainTrust"/>
        </clientCertificate>
      </serviceCredentials>
    </behavior>

  </serviceBehaviors>
</behaviors>

<!-- SERVICES -->
<services>
  <service name="StreamingMutualAuthTestCase.Web.Service.TestCaseServiceImplementation" 
           behaviorConfiguration="TestCaseSecureBehavior">
    <!-- SERVICE -->
    <endpoint address=""
              binding="basicHttpBinding"
              bindingConfiguration="TestCaseBasicBinding"
              contract="StreamingMutualAuthTestCase.Web.Service.ITestCaseService" />

    <endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" />

  </service>
</services>    

<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

Конфигурация клиента выглядит следующим образом:

 <system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_ITestCaseService" closeTimeout="00:30:00"
                openTimeout="00:30:00" receiveTimeout="00:30:00" sendTimeout="00:30:00"
                maxReceivedMessageSize="2147483647" messageEncoding="Mtom"
                transferMode="Streamed">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="Certificate" realm="" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>

  <!-- BEHAVIORS -->
  <behaviors>
    <endpointBehaviors>
      <behavior name="SecureClientBehavior">
        <clientCredentials>
          <clientCertificate
            storeLocation="LocalMachine"
            storeName="My"
            findValue="DistinguishedNameOfCert"
            x509FindType="FindBySubjectDistinguishedName"/>
          <serviceCertificate>
            <authentication certificateValidationMode="ChainTrust"/>
          </serviceCertificate>
        </clientCredentials>
      </behavior>
    </endpointBehaviors>
  </behaviors>

    <client>
        <endpoint address="https://test7/TestCaseService/TestCaseService.svc" 
                  binding="basicHttpBinding" 
                  bindingConfiguration="BasicHttpBinding_ITestCaseService"
                  contract="TestCaseService.ITestCaseService" 
                  name="BasicHttpBinding_ITestCaseService" 
                  behaviorConfiguration="SecureClientBehavior"/>
    </client>
</system.serviceModel>

Еще раз, это будет работать нормально, пока я не установлю для Сертификатов клиента IIS значение Принять или Требовать.

Также в журнале IIS произошла ошибка 413 ...

2011-08-18 15:00:06 W3SVC1 10.39.8.111 POST /TestCaseService/TestCaseService.svc - 443 - 10.75.13.81 - - - test7 413 0 0

Я уже разработал службу аутентификации поверх службы загрузки файлов, чтобы обойти проблемы; но я действительно хотел бы знать, «то, что я пытаюсь сделать, это« выполнимо »или нет.

Спасибо за тонну - Патрик

1 Ответ

2 голосов
/ 17 августа 2011

Если вы хотите включить клиентские сертификаты в IIS, вы должны сделать то же самое для вашей службы (и клиента):

<security mode="Transport">
  <transport clientCredentialType="Certificate" />
</security>

Ваш клиент должен предоставить сертификат прокси-серверу:

yourProxy.ClientCredentials.ClientCertificate.SetCertificate(...);

Также ваш сервер должен доверять этим сертификатам, поэтому сертификаты клиентов должны выдаваться центром сертификации, которому доверяет сервер, или они должны быть установлены в хранилище LocalMachine \ Trusted people непосредственно на сервере.

Конечные точки WCF не поддерживают «Принять клиентские сертификаты» - вы должны либо использовать клиентские сертификаты, либо нет.

...