Udostępnij za pośrednictwem


Dostawca tokenów SAML

W tym przykładzie pokazano, jak zaimplementować niestandardowego dostawcę tokenu SAML klienta. Dostawca tokenów w programie Windows Communication Foundation (WCF) służy do dostarczania poświadczeń do infrastruktury zabezpieczeń. Dostawca tokenu ogólnie sprawdza cel i wystawia odpowiednie poświadczenia, aby infrastruktura zabezpieczeń mogła zabezpieczyć komunikat. Program WCF jest dostarczany z domyślnym dostawcą tokenów menedżera poświadczeń. Program WCF jest również dostarczany z dostawcą tokenów CardSpace. Niestandardowi dostawcy tokenów są przydatni w następujących przypadkach:

  • Jeśli masz magazyn poświadczeń, z którym ci dostawcy tokenów nie mogą działać.

  • Jeśli chcesz podać własny mechanizm niestandardowy do przekształcania poświadczeń z punktu, gdy użytkownik podaje szczegółowe informacje, kiedy struktura klienta WCF używa poświadczeń.

  • Jeśli tworzysz token niestandardowy.

W tym przykładzie pokazano, jak utworzyć niestandardowego dostawcę tokenu, który umożliwia używanie tokenu SAML uzyskanego spoza platformy klienta WCF.

Podsumowując, w tym przykładzie przedstawiono następujące kwestie:

  • Jak można skonfigurować klienta za pomocą niestandardowego dostawcy tokenów.

  • Jak można przekazać token SAML do niestandardowych poświadczeń klienta.

  • Sposób, w jaki token SAML jest dostarczany do platformy klienta WCF.

  • Sposób uwierzytelniania serwera przez klienta przy użyciu certyfikatu X.509 serwera.

Usługa uwidacznia dwa punkty końcowe do komunikowania się z usługą, zdefiniowane przy użyciu pliku konfiguracji App.config. Każdy punkt końcowy składa się z adresu, powiązania i kontraktu. Powiązanie jest konfigurowane przy użyciu standardu wsFederationHttpBinding, który używa zabezpieczeń komunikatów. Jeden punkt końcowy oczekuje, że klient będzie uwierzytelniany przy użyciu tokenu SAML, który używa klucza dowodowego symetrycznego, podczas gdy drugi oczekuje, że klient uwierzytelnia się przy użyciu tokenu SAML używającego klucza dowodowego asymetrycznego. Usługa konfiguruje również certyfikat usługi przy użyciu serviceCredentials zachowania. Zachowanie serviceCredentials umożliwia skonfigurowanie certyfikatu usługi. Certyfikat usługi jest używany przez klienta do uwierzytelniania usługi i zapewniania ochrony komunikatów. Poniższa konfiguracja odwołuje się do certyfikatu "localhost" zainstalowanego podczas przykładowej konfiguracji zgodnie z opisem w instrukcjach konfiguracji na końcu tego tematu. Zachowanie serviceCredentials pozwala również skonfigurować certyfikaty, które są zaufane do podpisywania tokenów SAML. Poniższa konfiguracja odwołuje się do certyfikatu "Alice" zainstalowanego podczas przykładu.

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

W poniższych krokach pokazano, jak utworzyć niestandardowego dostawcę tokenów SAML i zintegrować go z usługą WCF: struktura zabezpieczeń:

  1. Napisz niestandardowego dostawcę tokenu SAML.

    Przykład implementuje niestandardowego dostawcę tokenów SAML, który zwraca token zabezpieczający oparty na asercji SAML udostępnianej w czasie budowy.

    Aby wykonać to zadanie, niestandardowy dostawca tokenu pochodzi z SecurityTokenProvider klasy i zastępuje metodę GetTokenCore . Ta metoda tworzy i zwraca nowy SecurityTokenelement .

    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. Pisanie niestandardowego menedżera tokenów zabezpieczających.

    Klasa jest używana do utworzenia SecurityTokenManagerSecurityTokenProvider dla określonego SecurityTokenRequirement , który jest przekazywany do niej w CreateSecurityTokenProvider metodzie. Menedżer tokenów zabezpieczających jest również używany do tworzenia wystawców uwierzytelnień tokenów i serializatora tokenów, ale nie są one objęte tym przykładem. W tym przykładzie niestandardowy menedżer tokenów zabezpieczających dziedziczy z ClientCredentialsSecurityTokenManager klasy i zastępuje CreateSecurityTokenProvider metodę, aby zwrócić niestandardowego dostawcę tokenu SAML, gdy przekazane wymagania tokenu wskazują, że zażądano tokenu SAML. Jeśli klasa poświadczeń klienta (zobacz krok 3) nie określiła asercji, menedżer tokenów zabezpieczeń tworzy odpowiednie wystąpienie.

    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. Napisz niestandardowe poświadczenia klienta.

    Klasa poświadczeń klienta służy do reprezentowania poświadczeń skonfigurowanych dla serwera proxy klienta i tworzy menedżera tokenów zabezpieczających używany do uzyskiwania wystawców uwierzytelnień tokenów, dostawców tokenów i serializatora tokenów.

    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. Skonfiguruj klienta tak, aby używał niestandardowych poświadczeń klienta.

    Przykład usuwa domyślną klasę poświadczeń klienta i dostarcza nową klasę poświadczeń klienta, aby klient mógł używać niestandardowych poświadczeń klienta.

    // 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);
    

W usłudze wyświetlane są oświadczenia skojarzone z obiektem wywołującym. Po uruchomieniu przykładu żądania operacji i odpowiedzi są wyświetlane w oknie konsoli klienta. Naciśnij klawisz ENTER w oknie klienta, aby zamknąć klienta.

Konfigurowanie pliku wsadowego

Plik wsadowy Setup.bat dołączony do tego przykładu umożliwia skonfigurowanie serwera z odpowiednim certyfikatem w celu uruchomienia aplikacji hostowanej samodzielnie, która wymaga zabezpieczeń opartych na certyfikatach serwera. Ten plik wsadowy należy zmodyfikować tak, aby działał na komputerach lub działać w przypadku innym niż hostowany.

Poniżej przedstawiono krótkie omówienie różnych sekcji plików wsadowych, dzięki czemu można je zmodyfikować w celu uruchomienia w odpowiedniej konfiguracji.

  • Tworzenie certyfikatu serwera:

    Następujące wiersze z pliku wsadowego Setup.bat tworzą certyfikat serwera do użycia. Zmienna %SERVER_NAME% określa nazwę serwera. Zmień tę zmienną, aby określić własną nazwę serwera. Wartość domyślna w tym pliku wsadowym to localhost.

    Certyfikat jest przechowywany w magazynie My (Personal) w lokalizacji magazynu 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
    
  • Zainstalowanie certyfikatu serwera w zaufanym magazynie certyfikatów klienta:

    Następujące wiersze w pliku wsadowym Setup.bat skopiuj certyfikat serwera do magazynu zaufanych osób klienta. Ten krok jest wymagany, ponieważ certyfikaty generowane przez Makecert.exe nie są niejawnie zaufane przez system kliencki. Jeśli masz już certyfikat, który jest zakorzeniony w zaufanym certyfikacie głównym klienta — na przykład certyfikat wystawiony przez firmę Microsoft — ten krok wypełniania magazynu certyfikatów klienta przy użyciu certyfikatu serwera nie jest wymagany.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r LocalMachine -s TrustedPeople
    
  • Tworzenie certyfikatu wystawcy.

    Następujące wiersze z pliku wsadowego Setup.bat tworzą certyfikat wystawcy do użycia. Zmienna %USER_NAME% określa nazwę wystawcy. Zmień tę zmienną, aby określić własną nazwę wystawcy. Wartość domyślna w tym pliku wsadowym to Alice.

    Certyfikat jest przechowywany w moim magazynie w lokalizacji magazynu 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
    
  • Instalowanie certyfikatu wystawcy w magazynie zaufanych certyfikatów serwera.

    Następujące wiersze w pliku wsadowym Setup.bat skopiuj certyfikat serwera do magazynu zaufanych osób klienta. Ten krok jest wymagany, ponieważ certyfikaty generowane przez Makecert.exe nie są niejawnie zaufane przez system kliencki. Jeśli masz już certyfikat, który jest zakorzeniony w zaufanym certyfikacie głównym klienta — na przykład certyfikat wystawiony przez firmę Microsoft — ten krok wypełniania magazynu certyfikatów serwera przy użyciu certyfikatu wystawcy nie jest wymagany.

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

Aby skonfigurować i skompilować przykład

  1. Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.

  2. Aby skompilować rozwiązanie, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).

Uwaga

Jeśli używasz Svcutil.exe do ponownego wygenerowania konfiguracji dla tego przykładu, pamiętaj o zmodyfikowaniu nazwy punktu końcowego w konfiguracji klienta, aby był zgodny z kodem klienta.

Aby uruchomić przykład na tym samym komputerze

  1. Uruchom Setup.bat z folderu instalacji przykładowej w wierszu polecenia programu Visual Studio uruchom polecenie z uprawnieniami administratora. Spowoduje to zainstalowanie wszystkich certyfikatów wymaganych do uruchomienia przykładu.

    Uwaga

    Plik wsadowy Setup.bat jest przeznaczony do uruchamiania z poziomu wiersza polecenia programu Visual Studio. Zmienna środowiskowa PATH ustawiona w wierszu polecenia programu Visual Studio wskazuje katalog zawierający pliki wykonywalne wymagane przez skrypt Setup.bat.

  2. Uruchom Service.exe z pliku service\bin.

  3. Uruchom Client.exe z \client\bin. Działanie klienta jest wyświetlane w aplikacji konsolowej klienta.

  4. Jeśli klient i usługa nie mogą się komunikować, zobacz Rozwiązywanie problemów Wskazówki dla przykładów programu WCF.

Aby uruchomić przykład na komputerach

  1. Utwórz katalog na komputerze usługi dla plików binarnych usługi.

  2. Skopiuj pliki programu usługi do katalogu usługi na komputerze usługi. Skopiuj również pliki Setup.bat i Cleanup.bat na komputer usługi.

  3. Musisz mieć certyfikat serwera o nazwie podmiotu, który zawiera w pełni kwalifikowaną nazwę domeny komputera. Aby odzwierciedlić tę nową nazwę certyfikatu, należy zaktualizować plik Service.exe.config. Certyfikat serwera można utworzyć, modyfikując plik wsadowy Setup.bat. Należy pamiętać, że plik setup.bat musi być uruchamiany w wierszu polecenia dewelopera dla programu Visual Studio otwartym z uprawnieniami administratora. Należy ustawić zmienną %SERVER_NAME% na w pełni kwalifikowaną nazwę hosta komputera, który jest używany do hostowania usługi.

  4. Skopiuj certyfikat serwera do magazynu CurrentUser-Trusted Osoby klienta. Ten krok nie jest konieczny, gdy certyfikat serwera jest wystawiany przez zaufanego wystawcę klienta.

  5. W pliku Service.exe.config na komputerze usługi zmień wartość adresu podstawowego, aby określić w pełni kwalifikowaną nazwę komputera zamiast hosta lokalnego.

  6. Na komputerze usługi uruchom Service.exe z wiersza polecenia.

  7. Skopiuj pliki programu klienckiego z folderu \client\bin\ w folderze specyficznym dla języka na komputer kliencki.

  8. W pliku Client.exe.config na komputerze klienckim zmień wartość adresu punktu końcowego, aby był zgodny z nowym adresem usługi.

  9. Na komputerze klienckim uruchom polecenie Client.exe w oknie wiersza polecenia.

  10. Jeśli klient i usługa nie mogą się komunikować, zobacz Rozwiązywanie problemów Wskazówki dla przykładów programu WCF.

Aby wyczyścić po próbce

  1. Uruchom Cleanup.bat w folderze samples po zakończeniu uruchamiania przykładu.