Веб-приложение MVC (https) вызывает службу WCF (https), которая также требует SSL-сертификат для аутентификации. - PullRequest
2 голосов
/ 29 ноября 2011

У меня проблема с получением веб-приложения MVC с HTTPS для вызова службы WCF, которая также использует HTTPS.Веб-приложение MVC должно пройти проверку подлинности с помощью сертификата службы WCF.

Я использую Windows 7, IIS 7.5, VS 2010 с C # и .NET Framework 4.0.

Вот что яуже сделано:

  1. Я создал центр сертификации под названием «Центр разработки»:

    makecert -pe -n "CN=Development Authority" -ss my -sr LocalMachine -a sha1 -sky signature -r "c:\Development Authority.cer"
    

    Я импортировал новый сертификат с помощью инструмента MMC вПапка «Доверенные корневые центры сертификации» и в папке «Сторонние корневые центры сертификации» (локальный компьютер).Этот сертификат также можно найти в папке «Personal».

    Я видел, что если я импортирую CA только в «Trusted Root CA», он все равно выдаст предупреждение «not trust».После импорта ЦС в папку «Сторонний корневой ЦС» предупреждение исчезло.

  2. Я создал два других сертификата (подписанных вновь созданным ЦС), используя следующую команду:

    makecert -pe -n "CN=mvc.localhost" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in "Development Authority" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 c:\mvc.localhost.cer
    

    Таким образом, я создал сертификаты 'mvc.localhost' и 'wcf.localhost'.Я импортировал их в папку «Личные» (для локального компьютера) с помощью инструмента MMC.

  3. В файлах хостов Windows я создал два псевдонима для двух приложений, которые будутразмещены с IIS (приложение MVC и приложение службы WCF).Я обновил свой файл hosts следующими строками:

    #development
    127.0.0.1 mvc.localhost
    127.0.0.1 wcf.localhost 
    
  4. В IIS я сопоставил новый веб-сайт mvc.localhost с очень простым веб-приложением MVC.Я также сопоставил новый веб-сайт 'wcf.localhost' с базовой вновь созданной службой WCF.

    mcv.localhost:

    • Пул приложений: .NET Framework 4.0, запущенная с использованием ApplicationPoolIdentity.

    • Анонимная аутентификация : включена и установлена ​​на «Определенный пользователь»: «IUSR».

    • Привязки:

      HTTP (имя хоста 'mvc.localhost', порт 80) -> может получить доступ с помощью http://mvc.localhost/'

      HTTPS (имя хоста 'mvc.localhost ', порт 1234) -> может получить доступ с помощью' https://mvc.localhost:1234/'., добавленного с сертификатом 'mvc.localhost'.

    wcf.localhost:

    • Пул приложений: .NET Framework 4.0, работающий с использованием ApplicationPoolIdentity.

    • Анонимная аутентификация : включен и установлен на «Определенный пользователь»':' IUSR '.

    • Привязки:

      HTTP (имя хоста' wcf.localhost ', порт 80) -> можно получить с помощью'http://wcf.localhost/'

      HTTPS (имя хоста 'wcf.localhost ', порт 443) -> может получить доступ с помощью https://wcf.localhost/'., добавленного с сертификатом' wcf.localhost '.

    Чтобы изменить имена хостов для привязок HTTPS, я использовал следующую команду:

    c:\Windows\System32\inetsrv>appcmd set site /site.name:"wcf.localhost" /bindings.[protocol='https',bindingInformation='*:443:'].bindingInformation:*:443:wcf.localhost
    
  5. Я проверил два веб-сайта отдельно с HTTPS, и они работали без проблем (за исключением Firefox, который имеет строгую политику, когда я обращаюсь к локальным сертификатам, созданным для целей тестирования, и дает вампредупреждение 'sec_error_unknown_issuer', но пока это не моя проблема).

  6. Конфигурация службы WCF для проверки подлинности сертификата:

    <bindings> 
      <wsHttpBinding>
        <binding name="wsHttpEndpointBinding">
          <security mode="Transport">
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding> 
    </bindings>
    
    <services>
      <service name="wcf.localhost.WelcomeService"  behaviorConfiguration="wcf.localhost.WelcomeServiceBehavior">    
        <endpoint address="https://wcf.localhost/WelcomeService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="wcf.localhost.IWelcomeService"> 
        </endpoint>
        <!--<endpoint address="mex" binding="mexHttpsBinding" 
        name="mexEndpoint" contract="IMetadataExchange"/>-->
      </service>
    </services>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="wcf.localhost.WelcomeServiceBehavior">
          <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
    
          <serviceCredentials>
            <clientCertificate>
              <authentication revocationMode="NoCheck" certificateValidationMode="PeerOrChainTrust" />
            </clientCertificate>
            <serviceCertificate findValue="<<wcf.localhost Certificate Thumbprint inserted here>>" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    

    В IIS для настроек SSL я устанавливаю «Требовать SSL» с опцией «Требовать».

    Служба WelcomeService предоставляет метод под названием «SayHello (string)», который объединяет «Hello» свходной параметр и возвращает новую строку.

    Я могу достичь 'https://wcf.localhost/welcomeservice.svc' без проблем.

  7. Веб-приложение MVC конфигурация:

    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IWelcomeService" 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="Transport">
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    
    <client>
      <endpoint address="https://wcf.localhost/WelcomeService.svc"
        binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWelcomeService"
        contract="WelcomeService.IWelcomeService" name="WSHttpBinding_IWelcomeService" behaviorConfiguration="CustomBehavior">        
      </endpoint>
    </client>
    
    <behaviors>
      <endpointBehaviors>
        <behavior name="CustomBehavior" >
          <clientCredentials>
            <clientCertificate findValue="<<mvc.localhost Certificate Thumbprint inserted here>>"
            storeLocation="LocalMachine"
            storeName="My"
            x509FindType="FindByThumbprint"/>
            <serviceCertificate>
              <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck"></authentication>
            </serviceCertificate>
          </clientCredentials>          
        </behavior>
      </endpointBehaviors>
    </behaviors>
    

  8. Теперь к проблеме: После использования приложения MVC для вызова службы WCF я получаю следующую ошибку:

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

    Exception Details: System.Net.WebException: The remote server returned an error: (403) Forbidden.
    
    Source Error: 
    
    
    Line 48:         
    Line 49:         public void SayHello(string name) {
    Line 50:             base.Channel.SayHello(name);
    Line 51:         }
    Line 52:     }
    
    Source File: C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs    Line: 50 
    
    Stack Trace: 
    
    
    [WebException: The remote server returned an error: (403) Forbidden.]
       System.Net.HttpWebRequest.GetResponse() +7859156
       System.ServiceModel.Channels.HttpChannelRequest.WaitForReply(TimeSpan timeout) +99
    
    [MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'.]
       System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +4727747
       System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +1725
       mvc.localhost.WelcomeService.IWelcomeService.SayHello(String name) +0
       mvc.localhost.WelcomeService.WelcomeServiceClient.SayHello(String name) in C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs:50
       mvc.localhost.Controllers.HomeController.CallService(HomeModel model) in C:\Projects\ssl.research\mvc.localhost\Controllers\HomeController.cs:33
       lambda_method(Closure , ControllerBase , Object[] ) +127
       System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +264
       System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
       System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +129
       System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +826410
       System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +314
       System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +825632
       System.Web.Mvc.Controller.ExecuteCore() +159
       System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +335
       System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +62
       System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +20
       System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +54
       System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +469
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +375
    
    Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.237
    

На стороне клиента я тоже пробовал:

  • ServicePointManager.ServerCertificateValidationCallback += customXertificateValidation
    ...
    private static bool customXertificateValidation(object sender, X509Certificate cert,
    X509Chain chain, SslPolicyErrors error)
        {
            return true;
        }
  • Использование отпечатка сертификата службы для аутентификации в службе.
  • Различные значения CertificateValidationMode.

Ничего не работает.

Я использовал SSL Diagnostics 1.1 для проверки двух веб-приложений и их сертификатов.Ошибок не было показано.Симуляция SSL Handshake прошла нормально, без ошибок.

Я чувствую, что довольно близка к завершению тестового проекта (решив другие проблемы на этом пути).

При поиске в Интернете я мог найти только службы HTTP WCF или службы WCF, которые не используют сертификат для проверки подлинности, или службы WCF, которые используют проверку подлинности сертификата, но являются HTTP.

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

Многие замечательные статьи помогли мне решить другие проблемы сэтот проект.

Теперь я застрял и не могу найти решение.

Любое предложение приветствуется.

Спасибо, Богдан.

ОБНОВЛЕНИЕ

Я заметил, что оба моих сертификата имеют свои цели: «Обеспечивает идентификацию удаленного компьютера» (serverAuth) но я не вижу ничего о clientAuth.

Кроме того, браузер Chrome предлагает мне выбрать сертификат при доступе к веб-приложению MVC.В списке сертификатов я не вижу двух сертификатов, которые я создал.

Я вижу только один сертификат, который имеет одну из своих целей (но отличается от сертификата, который я планирую использовать!): «Подтверждает вашу личность на удаленном компьютере»

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

Есть мысли?Если я прав, как я могу добавить цель clientAuth к любому из моих сертификатов?Спасибо

Ответы [ 3 ]

3 голосов
/ 29 ноября 2011

Вместе с Раджешем я смог найти решение.

Проблема была в клиентском сертификате (mvc.localhost), который был сгенерирован с использованием атрибута "-eku", который дал сертификату цель "Обеспечивает идентификацию удаленного компьютера" (serverAuth), но не соответствовал цели " Аутентификация клиента ".

Вы можете проверить назначение сертификата на вкладке «Общие» в его деталях.

Итак, мне пришлось сгенерировать новый клиентский сертификат, исключив атрибут "-eku", который дал цели сертификата "Все политики приложений" (включая проверку подлинности клиента).

Я сделал это с помощью следующей команды:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>makecert -sr LocalMachine
 -ss my  -a sha1 -n "CN=mvc.localhost" -sky exchange -pe -in "Development Author
ity" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider"
 -sy 12 c:\mvc.localhost.cer
Succeeded

Будьте осторожны! После создания сертификатов с помощью инструмента makecert они появятся в хранилище «Локальный компьютер / Личный». Всякий раз, когда вам нужно скопировать / импортировать определенный сертификат в другое хранилище, обязательно сначала экспортируйте исходный сертификат (хранилище «Локальный компьютер / Личное») в виде файла .pfx. Затем вы можете импортировать файл .pfx в другие хранилища, а не файл .cer !!

После этого просто добавьте два сертификата в нужные хранилища:

Локальный компьютер -> Личное хранилище -> имеет два сертификата (автоматически добавляются при создании сертификатов с помощью инструмента makecert). IIS выбирает сертификаты из этого хранилища (чтобы использовать их при создании привязки https), поэтому я не рекомендую удалять сертификат клиента.

Локальный компьютер -> Доверенные люди -> импортированные mvc.localhost.pfx

Текущий пользователь -> Личное хранилище -> импортированный mvc.localhost.pfx (при этом также импортируется CA mvc.localhost в этой папке)

Текущий пользователь -> Центр доверенных корневых сертификатов -> импортированный wcf.localhost.pfx

Спасибо Раджеш.

PS: вы также можете проверить решение здесь: Тема форума WCF

1 голос
/ 29 ноября 2011

При использовании сертификатов для аутентификации вам необходимо убедиться, что сертификаты размещены в соответствующем хранилище.

Вам необходимо иметь сертификат клиента следующим образом:

На клиентском компьютере:

Текущий пользователь -> Личная папка должна иметь установленный клиентский сертификат mvc.localhost.pfx

На серверах:

Локальный компьютер -> TrustPeople должен иметь mvc.localhostУстановлен .cer

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


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

Локальный компьютер -> Личное хранилище должно иметь сертификат сервера (wcf.localhost)

Локальный компьютер -> Хранилище доверенных лицчтобы иметь сертификат клиента (mvc.localhost)

Текущий пользователь -> Личное хранилище, чтобы иметь сертификат клиента (mvc.localhost)

Текущий пользователь -> Доверенный корневой сертификат.иметь сертификат сервера (wcf.localhost)

Если у вас есть следующие, попробуйте перейти к службе из IE, и вы сможете увидеть службу и ее wsdl.

Также перейдите кIE, а затем Сервис -> Свойства обозревателя -> Безопасность -> Интернет -> Пользовательский уровень

Теперь прокрутите вниз до раздела «Разное», чтобы найти параметр «Не запрашивать выбор сертификата клиента при отсутствии сертификата».или только один сертификат присутствует "Diable.

Теперь перезапустите IE и перейдите к службе, и IE должен попросить вас выбрать сертификат клиента из списка.ersonal store, и вам нужно выбрать mvc.localhost.

Если mvc.localhost не видно, значит ваш клиентский сертификат отсутствует в соответствующем хранилище.

0 голосов
/ 14 октября 2016

Добавляя к прекрасному ответу Богдана (поскольку у меня была такая же проблема), я добавил OID_PKIX_KP_CLIENT_AUTH OID (1.3.6.1.5.5.7.3.2) к аргументу -eku, который дал мне обе цели, а это то, что вы, вероятно, хотите, а не грубая сила "Все политики приложений" .

например (удалить явные разрывы строк)

makecert -iv SignRoot.pvk -ic signroot.cer -cy end -pe -n CN="DEV dual purpose" 
         -eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2 -ss my 
         -sr localmachine -sky exchange 
         -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12    
...