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


Поставщик токенов SAML

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

  • Если у вас есть хранилище учетных данных, с которыми эти поставщики токенов не могут работать.

  • Если вы хотите предоставить собственный механизм для преобразования учетных данных, начиная с момента, когда пользователь вводит свои данные, и до их использования в рамках клиентской платформы WCF.

  • Если вы создаете пользовательский токен.

В этом примере показано, как создать настраиваемого поставщика маркеров, позволяющего использовать токен SAML, полученный за пределами клиентской инфраструктуры WCF.

В этом примере показано следующее:

  • Как клиент может быть настроен с помощью пользовательского поставщика токенов.

  • Как токен SAML можно передать пользовательским учетным данным клиента.

  • Как токен SAML предоставляется клиентской платформе WCF.

  • Как сервер проходит проверку подлинности клиентом с помощью сертификата X.509 сервера.

Служба предоставляет две конечные точки для взаимодействия со службой, определяемой с помощью файла конфигурации App.config. Каждая конечная точка состоит из адреса, привязки и контракта. Привязка настроена с использованием стандарта wsFederationHttpBinding, использующего безопасность сообщений. Одна конечная точка ожидает, что клиент будет проходить проверку подлинности с помощью токена SAML, использующего симметричный ключ доказательства, а другая ожидает, что клиент будет проходить проверку подлинности с помощью токена SAML, использующего асимметричный ключ доказательства. Служба также настраивает сертификат службы, используя поведение serviceCredentials. Поведение serviceCredentials позволяет настроить сертификат службы. Сертификат службы используется клиентом для проверки подлинности службы и предоставления защиты сообщений. Следующая конфигурация ссылается на сертификат localhost, установленный во время примера установки, как описано в инструкциях по настройке в конце этого раздела. Это serviceCredentials поведение также позволяет настроить сертификаты, которым доверяют для подписания токенов SAML. Следующая конфигурация ссылается на сертификат Alice, установленный во время примера.

<system.serviceModel>
 <services>
  <service
          name="Microsoft.ServiceModel.Samples.CalculatorService"
          behaviorConfiguration="CalculatorServiceBehavior">
   <host>
    <baseAddresses>
     <!-- configure base address provided by host -->
     <add
  baseAddress="http://localhost:8000/servicemodelsamples/service/" />
    </baseAddresses>
   </host>
   <!-- use base address provided by host -->
   <!-- Endpoint that expect SAML tokens with Symmetric proof keys -->
   <endpoint address="calc/symm"
             binding="wsFederationHttpBinding"
             bindingConfiguration="Binding1"
             contract="Microsoft.ServiceModel.Samples.ICalculator" />
   <!-- Endpoint that expect SAML tokens with Asymmetric proof keys -->
   <endpoint address="calc/asymm"
             binding="wsFederationHttpBinding"
             bindingConfiguration="Binding2"
             contract="Microsoft.ServiceModel.Samples.ICalculator" />
  </service>
 </services>

 <bindings>
  <wsFederationHttpBinding>
   <!-- Binding that expect SAML tokens with Symmetric proof keys -->
   <binding name="Binding1">
    <security mode="Message">
     <message negotiateServiceCredential ="false"
              issuedKeyType="SymmetricKey"
              issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"  />
    </security>
   </binding>
   <!-- Binding that expect SAML tokens with Asymmetric proof keys -->
   <binding name="Binding2">
    <security mode="Message">
     <message negotiateServiceCredential ="false"
              issuedKeyType="AsymmetricKey"
              issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"  />
    </security>
   </binding>
  </wsFederationHttpBinding>
 </bindings>

 <behaviors>
  <serviceBehaviors>
   <behavior name="CalculatorServiceBehavior">
    <!--
    The serviceCredentials behavior allows one to define a service certificate.
    A service certificate is used by a client to authenticate the service and provide message protection.
    This configuration references the "localhost" certificate installed during the setup instructions.
    -->
    <serviceCredentials>
     <!-- Set allowUntrustedRsaIssuers to true to allow self-signed, asymmetric key based SAML tokens -->
     <issuedTokenAuthentication allowUntrustedRsaIssuers ="true" >
      <!-- Add Alice to the list of certs trusted to issue SAML tokens -->
      <knownCertificates>
       <add storeLocation="LocalMachine"
            storeName="TrustedPeople"
            x509FindType="FindBySubjectName"
            findValue="Alice"/>
      </knownCertificates>
     </issuedTokenAuthentication>
     <serviceCertificate storeLocation="LocalMachine"
                         storeName="My"
                         x509FindType="FindBySubjectName"
                         findValue="localhost"  />
    </serviceCredentials>
   </behavior>
  </serviceBehaviors>
 </behaviors>

</system.serviceModel>

Ниже показано, как разработать пользовательский поставщик токенов SAML и интегрировать его с инфраструктурой безопасности WCF.

  1. Напишите собственный поставщик токенов SAML.

    В примере реализуется настраиваемый поставщик токенов SAML, который возвращает токен безопасности на основе утверждения SAML, предоставленного во время создания.

    Для выполнения этой задачи поставщик настраиваемых маркеров является производным от SecurityTokenProvider класса и переопределяет GetTokenCore метод. Этот метод создает и возвращает новое SecurityToken.

    protected override SecurityToken GetTokenCore(TimeSpan timeout)
    {
     // Create a SamlSecurityToken from the provided assertion
     SamlSecurityToken samlToken = new SamlSecurityToken(assertion);
    
     // Create a SecurityTokenSerializer that will be used to
     // serialize the SamlSecurityToken
     WSSecurityTokenSerializer ser = new WSSecurityTokenSerializer();
     // Create a memory stream to write the serialized token into
     // Use an initial size of 64Kb
     MemoryStream s = new MemoryStream(UInt16.MaxValue);
    
     // Create an XmlWriter over the stream
     XmlWriter xw = XmlWriter.Create(s);
    
     // Write the SamlSecurityToken into the stream
     ser.WriteToken(xw, samlToken);
    
     // Seek back to the beginning of the stream
     s.Seek(0, SeekOrigin.Begin);
    
     // Load the serialized token into a DOM
     XmlDocument dom = new XmlDocument();
     dom.Load(s);
    
     // Create a KeyIdentifierClause for the SamlSecurityToken
     SamlAssertionKeyIdentifierClause samlKeyIdentifierClause = samlToken.CreateKeyIdentifierClause<SamlAssertionKeyIdentifierClause>();
    
    // Return a GenericXmlToken from the XML for the
    // SamlSecurityToken, the proof token, the valid from and valid
    // until times from the assertion and the key identifier clause
    // created above
    return new GenericXmlSecurityToken(dom.DocumentElement, proofToken, assertion.Conditions.NotBefore, assertion.Conditions.NotOnOrAfter, samlKeyIdentifierClause, samlKeyIdentifierClause, null);
    }
    
  2. Напишите пользовательский менеджер токенов безопасности.

    Класс SecurityTokenManager используется для создания SecurityTokenProvider определенного SecurityTokenRequirement объекта, передаваемого в него в CreateSecurityTokenProvider методе. Диспетчер маркеров безопасности также используется для создания аутентификаторов и сериализаторов маркеров, однако эти функции не охватываются данным примером. В этом примере специализированный менеджер маркеров безопасности наследует от ClientCredentialsSecurityTokenManager класса и переопределяет CreateSecurityTokenProvider метод, чтобы возвращать пользовательского поставщика токенов SAML, когда требования к токенам указывают, что запрашивается маркер SAML. Если класс учетных данных клиента (см. шаг 3) не установил утверждение, менеджер токенов безопасности создает соответствующий экземпляр.

    public class SamlSecurityTokenManager : ClientCredentialsSecurityTokenManager
    {
     SamlClientCredentials samlClientCredentials;
    
     public SamlSecurityTokenManager ( SamlClientCredentials samlClientCredentials)
      : base(samlClientCredentials)
     {
      // Store the creating client credentials
      this.samlClientCredentials = samlClientCredentials;
     }
    
     public override SecurityTokenProvider CreateSecurityTokenProvider ( SecurityTokenRequirement tokenRequirement )
     {
      // If token requirement matches SAML token return the
      // custom SAML token provider
      if (tokenRequirement.TokenType == SecurityTokenTypes.Saml ||
          tokenRequirement.TokenType == "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1")
      {
       // Retrieve the SAML assertion and proof token from the
       // client credentials
       SamlAssertion assertion = this.samlClientCredentials.Assertion;
       SecurityToken prooftoken = this.samlClientCredentials.ProofToken;
    
       // If either the assertion of proof token is null...
       if (assertion == null || prooftoken == null)
       {
        // ...get the SecurityBindingElement and then the
        // specified algorithm suite
        SecurityBindingElement sbe = null;
        SecurityAlgorithmSuite sas = null;
    
        if ( tokenRequirement.TryGetProperty<SecurityBindingElement> ( "http://schemas.microsoft.com/ws/2006/05/servicemodel/securitytokenrequirement/SecurityBindingElement", out sbe))
        {
         sas = sbe.DefaultAlgorithmSuite;
        }
    
        // If the token requirement is for a SymmetricKey based token..
        if (tokenRequirement.KeyType == SecurityKeyType.SymmetricKey)
        {
         // Create a symmetric proof token
         prooftoken = SamlUtilities.CreateSymmetricProofToken ( tokenRequirement.KeySize );
         // and a corresponding assertion based on the claims specified in the client credentials
         assertion = SamlUtilities.CreateSymmetricKeyBasedAssertion ( this.samlClientCredentials.Claims, new X509SecurityToken ( samlClientCredentials.ClientCertificate.Certificate ), new X509SecurityToken ( samlClientCredentials.ServiceCertificate.DefaultCertificate ), (BinarySecretSecurityToken)prooftoken, sas);
        }
        // otherwise...
        else
        {
         // Create an asymmetric proof token
         prooftoken = SamlUtilities.CreateAsymmetricProofToken();
         // and a corresponding assertion based on the claims
         // specified in the client credentials
         assertion = SamlUtilities.CreateAsymmetricKeyBasedAssertion ( this.samlClientCredentials.Claims, prooftoken, sas );
        }
       }
    
       // Create a SamlSecurityTokenProvider based on the assertion and proof token
       return new SamlSecurityTokenProvider(assertion, prooftoken);
      }
      // otherwise use base implementation
      else
      {
       return base.CreateSecurityTokenProvider(tokenRequirement);
      }
    }
    
  3. Напишите пользовательские учетные данные клиента.

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

    public class SamlClientCredentials : ClientCredentials
    {
     ClaimSet claims;
     SamlAssertion assertion;
     SecurityToken proofToken;
    
     public SamlClientCredentials() : base()
     {
      // Set SupportInteractive to false to suppress Cardspace UI
      base.SupportInteractive = false;
     }
    
     protected SamlClientCredentials(SamlClientCredentials other) : base ( other )
     {
      // Just do reference copy given sample nature
      this.assertion = other.assertion;
      this.claims = other.claims;
      this.proofToken = other.proofToken;
     }
    
     public SamlAssertion Assertion { get { return assertion; } set { assertion = value; } }
    
     public SecurityToken ProofToken { get { return proofToken; } set { proofToken = value; } }
     public ClaimSet Claims { get { return claims; } set { claims = value; } }
    
     protected override ClientCredentials CloneCore()
     {
      return new SamlClientCredentials(this);
     }
    
     public override SecurityTokenManager CreateSecurityTokenManager()
     {
      // return custom security token manager
      return new SamlSecurityTokenManager(this);
     }
    }
    
  4. Настройте клиент для использования пользовательских учетных данных клиента.

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

    // Create new credentials class
    SamlClientCredentials samlCC = new SamlClientCredentials();
    
    // Set the client certificate. This is the cert that will be used to sign the SAML token in the symmetric proof key case
    samlCC.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "Alice");
    
    // Set the service certificate. This is the cert that will be used to encrypt the proof key in the symmetric proof key case
    samlCC.ServiceCertificate.SetDefaultCertificate(StoreLocation.CurrentUser, StoreName.TrustedPeople, X509FindType.FindBySubjectName, "localhost");
    
    // Create some claims to put in the SAML assertion
    IList<Claim> claims = new List<Claim>();
    claims.Add(Claim.CreateNameClaim(samlCC.ClientCertificate.Certificate.Subject));
    ClaimSet claimset = new DefaultClaimSet(claims);
    samlCC.Claims = claimset;
    
    // set new credentials
    client.ChannelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
    client.ChannelFactory.Endpoint.Behaviors.Add(samlCC);
    

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

Настройка пакетного файла

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

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

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

    Следующие строки из пакетного файла Setup.bat создают используемый сертификат сервера. Переменная %SERVER_NAME% задает имя сервера. Измените эту переменную, чтобы указать собственное имя сервера. Значение по умолчанию в этом пакетном файле — localhost.

    Сертификат хранится в хранилище «My store (Личном хранилище)» в расположении LocalMachine.

    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
    
  • Установка сертификата сервера в доверенное хранилище сертификатов клиента:

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

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r LocalMachine -s TrustedPeople
    
  • Создание сертификата издателя.

    Следующие строки из пакетного файла Setup.bat создают сертификат издателя, который будет использоваться. Переменная %USER_NAME% задает имя издателя. Измените эту переменную, чтобы указать собственное имя издателя. Значением по умолчанию в этом пакетном файле является Алиса.

    Сертификат хранится в хранилище "Мое" в расположении хранилища "CurrentUser".

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr CurrentUser -ss My -a sha1 -n CN=%USER_NAME% -sky exchange -pe
    
  • Установка сертификата издателя в доверенное хранилище сертификатов сервера.

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

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

Для настройки и сборки примера

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

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

Замечание

Если вы используете Svcutil.exe для повторного создания конфигурации для этого примера, обязательно измените имя конечной точки в конфигурации клиента, чтобы соответствовать коду клиента.

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

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

    Замечание

    Пакетный файл Setup.bat предназначен для запуска из командной строки Visual Studio. Переменная среды PATH в командной строке Visual Studio указывает на каталог, содержащий исполняемые файлы, необходимые скрипту Setup.bat.

  2. Запустите Service.exe из service\bin.

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

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

Для запуска примера на нескольких компьютерах

  1. Создайте каталог на компьютере сервиса для файлов двоичного кода сервиса.

  2. Скопируйте файлы программы службы в каталог службы на компьютере службы. Кроме того, скопируйте файлы Setup.bat и Cleanup.bat на компьютер службы.

  3. У вас должен быть сертификат сервера с именем субъекта, который содержит полное доменное имя компьютера. Файл Service.exe.config необходимо обновить, чтобы отразить это новое имя сертификата. Вы можете создать сертификат сервера, изменив Setup.bat пакетный файл. Обратите внимание, что файл setup.bat должен быть запущен в командной строке разработчика для Visual Studio, открываемом с правами администратора. Необходимо задать переменной %SERVER_NAME% полное имя узла компьютера, который используется для размещения службы.

  4. Скопируйте сертификат сервера в хранилище CurrentUser-TrustedPeople клиента. Этот шаг не требуется, если сертификат сервера выдан доверенным издателем клиента.

  5. В файле Service.exe.config на компьютере службы измените значение базового адреса, чтобы указать полное имя компьютера вместо localhost.

  6. На компьютере службы запустите Service.exe из командной строки.

  7. Скопируйте файлы клиентской программы из папки \client\bin\ в папку, соответствующую конкретному языку, на клиентский компьютер.

  8. В файле Client.exe.config на клиентском компьютере измените значение адреса конечной точки на соответствие новому адресу службы.

  9. На клиентском компьютере запустите Client.exe из окна командной строки.

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

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

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