Служба WCF с использованием клиентских сертификатов требует анонимного доступа в IIS и, следовательно, на самом деле не работает? - PullRequest
3 голосов
/ 22 февраля 2012

У меня есть служба WCF (.NET 4), размещенная в IIS (7.5 в Windows Server 2008 R2). Наш клиент (для которого мы создаем сервис) требует, чтобы все клиенты сервиса были аутентифицированы с использованием сертификатов Verisign. То есть клиент покупает сертификат у Verisign и предоставляет нам открытый ключ. Служба должна принимать запросы, которые могут быть проверены только с использованием одного из открытых ключей, которые мы получили от клиентов.

Проблема, с которой я сталкиваюсь, заключается в том, что IIS требует включения анонимной аутентификации. В противном случае «Параметры безопасности для этой службы требуют« анонимной »аутентификации, но она не включена для приложения IIS, в котором размещена эта служба». ошибка повышена Однако, если я включаю анонимную аутентификацию, любой вызов в службу, которая предоставляет любой сертификат, разрешен. Нам нужно ограничить его разрешением только тех вызовов, которые предоставляют определенные сертификаты (т.е. те, для которых нам был предоставлен открытый ключ).

В IIS нам требуются сертификаты SSL и клиента (в разделе «Настройки SSL»), и (в разделе «Аутентификация») вся аутентификация отключена (кроме анонимной).

Файл web.config:

  <system.web>
    <compilation debug="false" targetFramework="4.0" />
    <authentication mode="Windows" />
    <authorization>
      <deny users="?" />
      <allow users="*" />
    </authorization>
    <customErrors mode="Off" />
    <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
    <identity impersonate="false" />
  </system.web>

  <system.serviceModel>
    <services>
      <service behaviorConfiguration="XXXServiceBehavior" name="XXXService.NewService">
        <endpoint address=""
                  binding="wsHttpBinding"
                  bindingConfiguration="XXXServiceBinding"
                  contract="XXXService.INewService"
                  bindingNamespace="http://XXXX.com.au/XXXService/NewService">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="XXXXServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="PeerTrust" mapClientCertificateToWindowsAccount="true" />
            </clientCertificate>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="XXXServiceBinding" maxReceivedMessageSize="1000000" maxBufferPoolSize="1000000">
          <readerQuotas maxStringContentLength="1000000" />
          <security mode="Transport">
            <transport clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>

Если кто-то может заставить этот сценарий работать, не могли бы вы сообщить мне, какие настройки вы используете в IIS и в вашей конфигурации?

1 Ответ

1 голос
/ 24 февраля 2012

Оказывается, мне нужно было использовать режим безопасности привязки TransportWithMessageCredential и message clientCredentialType Certificate (см. Полный список конфигурации ниже).

При такой конфигурации привязки мне не нужно требовать основных разрешений или сопоставления сертификатов с учетными записями Windows, поскольку служба не будет запущена, если вызывающая сторона не предоставит распознанный сертификат (т. Е. Сертификат, открытый ключ которого). был импортирован в хранилище «Надежные люди» на сервере на уровне компьютера.

Единственное другое изменение настроек - в IIS и настройках SSL. Мне пришлось изменить настройку «Сертификат клиента» с «Требовать» на «Принять». (Если оставить значение «Требовать», клиент получит сообщение об ошибке «HTTP-запрос был запрещен при схеме проверки подлинности клиента« Аноним ».) Я не уверен, почему это так, но я так не думаю» является проблемой, так как WCF потребует сертификат.

Итак, вот соответствующий конфиг. Это конфигурация сервера:

<system.web>
  <compilation debug="false" targetFramework="4.0" />
  <authentication mode="Windows" />
  <authorization>
    <deny users="?" />
    <allow users="*" />
  </authorization>
  <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
  <identity impersonate="false" />
</system.web>

<system.serviceModel>
  <services>
    <service behaviorConfiguration="XXXWebServiceBehavior" name="XXXWebService.NewService">
      <endpoint address="" binding="wsHttpBinding" bindingConfiguration="XXXWebServiceBinding" contract="XXXWebService.INewService" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="XXXWebServiceBehavior">
        <serviceDebug includeExceptionDetailInFaults="false" />
        <serviceCredentials>
          <clientCertificate>
            <authentication certificateValidationMode="PeerTrust" />
          </clientCertificate>
        </serviceCredentials>
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <bindings>
    <wsHttpBinding>
      <binding name="XXXWebServiceBinding" maxReceivedMessageSize="1000000" maxBufferPoolSize="1000000">
        <readerQuotas maxStringContentLength="1000000" />
        <security mode="TransportWithMessageCredential">
          <message clientCredentialType="Certificate" />
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
</system.serviceModel>

А вот клиентский конфиг (в основном, сгенерированный Visual Studio):

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="WSHttpBinding_INewService" closeTimeout="00:01:00"
               openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
               bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
               maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
               messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
               allowCookies="false">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                      maxBytesPerRead="4096" maxNameTableCharCount="16384" />
        <reliableSession ordered="true" inactivityTimeout="00:10:00"
                         enabled="false" />
        <security mode="TransportWithMessageCredential">
          <message clientCredentialType="Certificate" />
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
  <client>
    <endpoint address="https://XXXX.XXXX.com.au/XXXServices/NewService.svc"
              binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_INewService"
              contract="ServiceReference1.INewService" name="WSHttpBinding_INewService">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
  </client>
</system.serviceModel>
...