开发者

Streaming MTOM Attachments in WCF and Certificate Authentication

I'm looking for a definitive answer as to whether what I'm trying to do is supported or not.

Basically, I'm using WCF to stream large MTOM attachments (200 Mb), this works perfectly fine. The security requirements for the service is to use HTTPS and certificate-based authentication. I can run the service over HTTPS without any problems, but once I set IIS to “Accept client certificates” or “Require client certificates” (no change in the code), the following error is thrown (but only once the attachments get over about 80 Mb or so):

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'.

I found some resources, sorry can't find them now, that indicated that the failure is probably related to the fact that the incoming messages either cannot be digitally signed, or verified due to the streaming nature of the message contents. I believe the service would have to hash the whole message contents to verify the cert, but this can't be achieved because portions of the message are in transit while validation is trying to occur.

I've setup the message contract so that the body is a single Stream element, and the other elements are contained within the header:

   <MessageContract()>
Public Class StreamAttachmentRequest

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

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

End Class

The service configuration looks as follows:

<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">
    <!-- SERVIC开发者_Python百科E -->
    <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" />

The client configuration looks like this:

 <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>

Once again, this will work just fine until I set IIS Client Certs to either Accept or Require.

Also, there is a 413 error in the IIS log...

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

I've already designed an authentication service on top of my file upload service to work around the issues; but I'd really like to know if what I'm trying to do is 'do-able' or not.

Thanks a ton - Patrick


If you want to turn on client certificates in IIS you must do the same for your service (and client):

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

Your client must provide certificate to the proxy:

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

Also your server must trust these certificates so client certificates must be either issued by certification authority trusted by the server or they must be installed to LocalMachine\Trusted people store directly on the server.

WCF endpoints don't support "Accept client certificates" - you must either use client certificates or not.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜