Поделиться через


Доверенная фасадная служба

В примере TrustedFacade демонстрируется передача информации об идентификации вызывающего объекта из одной службы в другую посредством инфраструктуры безопасности Windows Communication Foundation (WCF).

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

Этот пример состоит из следующих компонентов:

  • Клиент калькулятора

  • Служба интерфейса калькулятора

  • Серверная служба калькулятора

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

Это важно

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

Внедрение

В этом примере есть два пути связи. Первый — между клиентом и службой фасада, а второй — между службой фасада и серверной службой.

Путь взаимодействия между клиентом и службой фасадов

Клиент в пути связи с фасадной службой использует wsHttpBinding с типом учетных данных клиента UserName. Это означает, что клиент использует имя пользователя и пароль для проверки подлинности в службе фасада, а служба фасада использует сертификат X.509 для проверки подлинности клиента. Конфигурация привязки выглядит следующим образом.

<bindings>
  <wsHttpBinding>
    <binding name="Binding1">
      <security mode="Message">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>

Служба интерфейса проверяет подлинность вызывающего объекта с помощью пользовательской UserNamePasswordValidator реализации. В демонстрационных целях проверка подлинности гарантирует, что имя пользователя совпадает с представленным паролем. В реальной ситуации пользователь, вероятно, проходит проверку подлинности с помощью Active Directory или пользовательского поставщика членства ASP.NET. Реализация валидатора находится в FacadeService.cs файле.

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // check that username matches password
        if (null == userName || userName != password)
        {
            Console.WriteLine("Invalid username or password");
            throw new SecurityTokenValidationException(
                       "Invalid username or password");
        }
    }
}

Настраиваемый валидатор настроен для использования внутри serviceCredentials поведения в файле конфигурации фасадной службы. Это поведение также используется для настройки сертификата X.509 службы.

<behaviors>
  <serviceBehaviors>
    <behavior name="FacadeServiceBehavior">
      <!--The serviceCredentials behavior allows you to define -->
      <!--a service certificate. -->
      <!--A service certificate is used by the service to  -->
      <!--authenticate itself to its clients and to provide  -->
      <!--message protection. -->
      <!--This configuration references the "localhost"  -->
      <!--certificate installed during the setup instructions. -->
      <serviceCredentials>
        <serviceCertificate
               findValue="localhost"
               storeLocation="LocalMachine"
               storeName="My"
               x509FindType="FindBySubjectName" />
        <userNameAuthentication userNamePasswordValidationMode="Custom"
            customUserNamePasswordValidatorType=
           "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator,
            FacadeService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

Путь связи между сервисом фасада и бэкенд-сервисом

Служба фасада для пути обмена данными серверной службы использует элемент customBinding , состоящий из нескольких элементов привязки. Эта привязка выполняет две задачи. Происходит аутентификация фасадного сервиса и серверного сервиса для обеспечения безопасности связи и подтверждения, что она поступает из надежного источника. Кроме того, он передает идентичность исходного вызывающего абонента внутри токена безопасности. В этом случае только имя пользователя инициатора вызова передается в серверную часть, при этом пароль не включен в сообщение. Это связано с тем, что серверная служба доверяет фасадной службе аутентификацию вызывающего перед пересылкой ему запроса. Так как служба фасада проходит проверку подлинности в серверной службе, серверная служба может доверять сведениям, содержащимся в переадресованном запросе.

Ниже приведена конфигурация привязки для этого пути связи.

<bindings>
  <customBinding>
    <binding name="ClientBinding">
      <security authenticationMode="UserNameOverTransport"/>
      <windowsStreamSecurity/>
      <tcpTransport/>
    </binding>
  </customBinding>
</bindings>

Компонент <привязки безопасности> отвечает за передачу и извлечение имени пользователя первоначального вызывающего. <windowsStreamSecurity> и <tcpTransport> заботятся о проверке подлинности фасадных и внутренних служб и защите сообщений.

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

В следующем коде показано, как метод GetCallerIdentity реализуется в службе фасада. Другие методы используют тот же шаблон.

public string GetCallerIdentity()
{
    CalculatorClient client = new CalculatorClient();
    client.ClientCredentials.UserName.UserName = ServiceSecurityContext.Current.PrimaryIdentity.Name;
    string result = client.GetCallerIdentity();
    client.Close();
    return result;
}

Как показано в предыдущем коде, пароль не задан в ClientCredentials свойстве, задано только имя пользователя. Инфраструктура безопасности WCF создает маркер безопасности имени пользователя без пароля в этом случае, что именно необходимо в этом сценарии.

В серверной службе сведения, содержащиеся в маркере безопасности имени пользователя, должны пройти проверку подлинности. По умолчанию безопасность WCF пытается сопоставить пользователя с учетной записью Windows с помощью предоставленного пароля. В этом случае пароль отсутствует, и серверной службе не требуется проверять подлинность имени пользователя, так как проверка подлинности уже была выполнена службой фасада. Для реализации этой функции в WCF предоставляется настраиваемый элемент UserNamePasswordValidator, который гарантирует, что имя пользователя указано в токене и не выполняет дополнительных проверок подлинности.

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // Ignore the password because it is empty,
        // we trust the facade service to authenticate the client.
        // Accept the username information here so that the
        // application gets access to it.
        if (null == userName)
        {
            Console.WriteLine("Invalid username");
            throw new
             SecurityTokenValidationException("Invalid username");
        }
    }
}

Настраиваемый валидатор настроен для использования внутри serviceCredentials поведения в файле конфигурации фасадной службы.

<behaviors>
  <serviceBehaviors>
    <behavior name="BackendServiceBehavior">
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom"
           customUserNamePasswordValidatorType=
          "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator,
           BackendService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

Чтобы извлечь сведения о имени пользователя и сведения о доверенной учетной записи службы фасада, реализация серверной службы использует ServiceSecurityContext класс. В следующем коде показано, как метод GetCallerIdentity реализуется.

public string GetCallerIdentity()
{
    // Facade service is authenticated using Windows authentication.
    //Its identity is accessible.
    // On ServiceSecurityContext.Current.WindowsIdentity.
    string facadeServiceIdentityName =
          ServiceSecurityContext.Current.WindowsIdentity.Name;

    // The client name is transmitted using Username authentication on
    //the message level without the password
    // using a supporting encrypted UserNameToken.
    // Claims extracted from this supporting token are available in
    // ServiceSecurityContext.Current.AuthorizationContext.ClaimSets
    // collection.
    string clientName = null;
    foreach (ClaimSet claimSet in
        ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
    {
        foreach (Claim claim in claimSet)
        {
            if (claim.ClaimType == ClaimTypes.Name &&
                                   claim.Right == Rights.Identity)
            {
                clientName = (string)claim.Resource;
                break;
            }
        }
    }
    if (clientName == null)
    {
        // In case there was no UserNameToken attached to the request.
        // In the real world implementation the service should reject
        // this request.
        return "Anonymous caller via " + facadeServiceIdentityName;
    }

    return clientName + " via " + facadeServiceIdentityName;
}

Сведения об учетной записи службы фасада извлекаются свойством ServiceSecurityContext.Current.WindowsIdentity. Для доступа к сведениям об исходном вызывающем абоненте серверная служба использует ServiceSecurityContext.Current.AuthorizationContext.ClaimSets свойство. Он ищет Identity утверждение с типом Name. Это утверждение автоматически создается системой безопасности WCF из информации, содержащейся в маркере безопасности Username.

Запуск примера

При запуске примера запросы и ответы операции отображаются в окне консоли клиента. Нажмите клавишу ВВОД в окне клиента, чтобы завершить работу клиента. Чтобы завершить работу служб, можно нажать клавишу ВВОД в окнах фасадной и серверной консоли службы.

Username authentication required.
Provide a valid machine or domain ac
   Enter username:
user
   Enter password:
****
user via MyMachine\testaccount
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714

Press <ENTER> to terminate client.

Пакетный файл Setup.bat, включенный в пример сценария доверенного фасада, позволяет настроить сервер с соответствующим сертификатом для запуска службы фасада, требующей безопасности на основе сертификатов для проверки подлинности самого клиента. Дополнительные сведения см. в процедуре установки в конце этого раздела.

Ниже приведен краткий обзор различных разделов пакетных файлов.

  • Создание сертификата сервера.

    Следующие строки из пакетного файла Setup.bat создают используемый сертификат сервера.

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    

    Переменная %SERVER_NAME% задает имя сервера — значение по умолчанию — localhost. Сертификат хранится в хранилище LocalMachine.

  • Установка сертификата службы фасада в доверенное хранилище сертификатов клиента.

    В следующей строке сертификат службы фасада копируется в хранилище доверенных пользователей клиента. Этот шаг необходим, так как сертификаты, созданные Makecert.exe, не являются неявно доверенными клиентской системой. Если у вас уже есть сертификат, который основывается на корневом сертификате, которому доверяет клиент, например, выданный корпорацией Microsoft, то этап добавления серверного сертификата в хранилище клиентских сертификатов не требуется.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    

Настройка, сборка и запуск примера

  1. Убедитесь, что вы выполнили процедуру настройки One-Time для образцов Windows Communication Foundation.

  2. Чтобы создать версию решения на C# или Visual Basic .NET, следуйте инструкциям по сборке примеров Windows Communication Foundation .

Запуск примера на том же компьютере

  1. Убедитесь, что путь содержит папку, в которой находится Makecert.exe.

  2. Запустите Setup.bat из папки установки примера. При этом устанавливаются все сертификаты, необходимые для выполнения примера.

  3. Запустите BackendService.exe из каталога \BackendService\bin в отдельном окне консоли

  4. Запустите FacadeService.exe из каталога \FacadeService\bin в отдельном окне консоли

  5. Запустите Client.exe из \client\bin. Действие клиента отображается в клиентском консольном приложении.

  6. Если клиент и служба не могут взаимодействовать, см. рекомендации по устранению неисправностей для примеров WCF.

Очистка после образца

  1. Запустите Cleanup.bat в папке примеров после завершения работы примера.