Udostępnij za pośrednictwem


Zasady autoryzacji

W tym przykładzie pokazano, jak zaimplementować niestandardowe zasady autoryzacji oświadczeń i skojarzonego niestandardowego menedżera autoryzacji usługi. Jest to przydatne, gdy usługa sprawdza dostęp oparty na oświadczeniach do operacji usługi i przed sprawdzaniem dostępu udziela wywołującym pewnych praw. W tym przykładzie przedstawiono zarówno proces dodawania oświadczeń, jak i proces sprawdzania dostępu względem sfinalizowanego zestawu oświadczeń. Wszystkie komunikaty aplikacji między klientem a serwerem są podpisane i szyfrowane. Domyślnie z powiązaniem wsHttpBinding nazwa użytkownika i hasło dostarczone przez klienta są używane do logowania się do prawidłowego konta systemu Windows. W tym przykładzie pokazano, jak używać niestandardowego UserNamePasswordValidator do uwierzytelniania klienta. Ponadto w tym przykładzie pokazano, jak klient uwierzytelnia się w usłudze przy użyciu certyfikatu X.509. W tym przykładzie pokazano implementację IAuthorizationPolicy i ServiceAuthorizationManager, które wspólnie zapewniają dostęp do konkretnych metod usługi dla określonych użytkowników. Ten przykład opiera się na nazwie użytkownika zabezpieczeń komunikatów, ale pokazuje, jak przeprowadzić transformację roszczenia przed wywołaniem ServiceAuthorizationManager.

Uwaga / Notatka

Procedura instalacji i instrukcje kompilacji dla tego przykładu znajdują się na końcu tego tematu.

Podsumowując, w tym przykładzie pokazano, jak:

  • Klienta można uwierzytelnić za pomocą nazwy użytkownika i hasła.

  • Klienta można uwierzytelnić przy użyciu certyfikatu X.509.

  • Serwer weryfikuje poświadczenia klienta względem niestandardowego walidatora UsernamePassword.

  • Serwer jest uwierzytelniany przy użyciu certyfikatu X.509 serwera.

  • Serwer może użyć ServiceAuthorizationManager do kontrolowania dostępu do określonych metod w usłudze.

  • Jak zaimplementować metodę IAuthorizationPolicy.

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. Jedno wiązanie jest konfigurowane z użyciem standardowego wsHttpBinding wiązania, które korzysta z WS-Security i uwierzytelniania nazwy użytkownika klienta. Drugie wiązanie jest skonfigurowane przy użyciu standardowego wsHttpBinding wiązania, które wykorzystuje WS-Security i uwierzytelnianie certyfikatem klienta. <Sposób działania> określa, że poświadczenia użytkownika mają być używane do uwierzytelniania usługi. Certyfikat serwera musi zawierać tę samą wartość właściwości SubjectName jako findValue atrybut w <serviceCertificate>.

<system.serviceModel>
  <services>
    <service name="Microsoft.ServiceModel.Samples.CalculatorService"
             behaviorConfiguration="CalculatorServiceBehavior">
      <host>
        <baseAddresses>
          <!-- configure base address provided by host -->
          <add baseAddress ="http://localhost:8001/servicemodelsamples/service"/>
        </baseAddresses>
      </host>
      <!-- use base address provided by host, provide two endpoints -->
      <endpoint address="username"
                binding="wsHttpBinding"
                bindingConfiguration="Binding1"
                contract="Microsoft.ServiceModel.Samples.ICalculator" />
      <endpoint address="certificate"
                binding="wsHttpBinding"
                bindingConfiguration="Binding2"
                contract="Microsoft.ServiceModel.Samples.ICalculator" />
    </service>
  </services>

  <bindings>
    <wsHttpBinding>
      <!-- Username binding -->
      <binding name="Binding1">
        <security mode="Message">
    <message clientCredentialType="UserName" />
        </security>
      </binding>
      <!-- X509 certificate binding -->
      <binding name="Binding2">
        <security mode="Message">
          <message clientCredentialType="Certificate" />
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>

  <behaviors>
    <serviceBehaviors>
      <behavior name="CalculatorServiceBehavior" >
        <serviceDebug includeExceptionDetailInFaults ="true" />
        <serviceCredentials>
          <!--
          The serviceCredentials behavior allows one to specify a custom validator for username/password combinations.
          -->
          <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.MyCustomUserNameValidator, service" />
          <!--
          The serviceCredentials behavior allows one to specify authentication constraints on client certificates.
          -->
          <clientCertificate>
            <!--
            Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate
            is in the user's Trusted People store, then it will be trusted without performing a
            validation of the certificate's issuer chain. This setting is used here for convenience so that the
            sample can be run without having to have certificates issued by a certification authority (CA).
            This setting is less secure than the default, ChainTrust. The security implications of this
            setting should be carefully considered before using PeerOrChainTrust in production code.
            -->
            <authentication certificateValidationMode="PeerOrChainTrust" />
          </clientCertificate>
          <!--
          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.
          -->
          <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
        </serviceCredentials>
        <serviceAuthorization serviceAuthorizationManagerType="Microsoft.ServiceModel.Samples.MyServiceAuthorizationManager, service">
          <!--
          The serviceAuthorization behavior allows one to specify custom authorization policies.
          -->
          <authorizationPolicies>
            <add policyType="Microsoft.ServiceModel.Samples.CustomAuthorizationPolicy.MyAuthorizationPolicy, PolicyLibrary" />
          </authorizationPolicies>
        </serviceAuthorization>
      </behavior>
    </serviceBehaviors>
  </behaviors>

</system.serviceModel>

Każda konfiguracja punktu końcowego klienta składa się z nazwy konfiguracji, bezwzględnego adresu punktu końcowego usługi, powiązania i kontraktu. Powiązanie klienta jest konfigurowane z odpowiednim trybem zabezpieczeń, jak określono w tym przypadku w <zabezpieczeniach> i clientCredentialType jak określono w <komunikacie>.

<system.serviceModel>

    <client>
      <!-- Username based endpoint -->
      <endpoint name="Username"
            address="http://localhost:8001/servicemodelsamples/service/username"
    binding="wsHttpBinding"
    bindingConfiguration="Binding1"
                behaviorConfiguration="ClientCertificateBehavior"
                contract="Microsoft.ServiceModel.Samples.ICalculator" >
      </endpoint>
      <!-- X509 certificate based endpoint -->
      <endpoint name="Certificate"
                        address="http://localhost:8001/servicemodelsamples/service/certificate"
                binding="wsHttpBinding"
            bindingConfiguration="Binding2"
                behaviorConfiguration="ClientCertificateBehavior"
                contract="Microsoft.ServiceModel.Samples.ICalculator">
      </endpoint>
    </client>

    <bindings>
      <wsHttpBinding>
        <!-- Username binding -->
      <binding name="Binding1">
        <security mode="Message">
          <message clientCredentialType="UserName" />
        </security>
      </binding>
        <!-- X509 certificate binding -->
        <binding name="Binding2">
          <security mode="Message">
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
    </wsHttpBinding>
    </bindings>

    <behaviors>
      <behavior name="ClientCertificateBehavior">
        <clientCredentials>
          <serviceCertificate>
            <!--
            Setting the certificateValidationMode to PeerOrChainTrust
            means that if the certificate
            is in the user's Trusted People store, then it will be
            trusted without performing a
            validation of the certificate's issuer chain. This setting
            is used here for convenience so that the
            sample can be run without having to have certificates
            issued by a certification authority (CA).
            This setting is less secure than the default, ChainTrust.
            The security implications of this
            setting should be carefully considered before using
            PeerOrChainTrust in production code.
            -->
            <authentication certificateValidationMode = "PeerOrChainTrust" />
          </serviceCertificate>
        </clientCredentials>
      </behavior>
    </behaviors>

  </system.serviceModel>

W przypadku punktu końcowego opartego na nazwie użytkownika implementacja klienta ustawia nazwę użytkownika i hasło do użycia.

// Create a client with Username endpoint configuration
CalculatorClient client1 = new CalculatorClient("Username");

client1.ClientCredentials.UserName.UserName = "test1";
client1.ClientCredentials.UserName.Password = "1tset";

try
{
    // Call the Add service operation.
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client1.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
    ...
}
catch (Exception e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
}

client1.Close();

W przypadku punktu końcowego opartego na certyfikatach implementacja klienta ustawia certyfikat klienta do użycia.

// Create a client with Certificate endpoint configuration
CalculatorClient client2 = new CalculatorClient("Certificate");

client2.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "test1");

try
{
    // Call the Add service operation.
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client2.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
    ...
}
catch (Exception e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
}

client2.Close();

W tym przykładzie użyto niestandardowego UserNamePasswordValidator do weryfikowania nazw użytkowników i haseł. Przykład implementuje metodę MyCustomUserNamePasswordValidator, pochodzącą z elementu UserNamePasswordValidator. Zobacz dokumentację dotyczącą UserNamePasswordValidator, aby uzyskać więcej informacji. Na potrzeby demonstrowania integracji z UserNamePasswordValidator, ten niestandardowy przykład walidatora implementuje metodę Validate, która akceptuje pary nazwy użytkownika/hasła, w których nazwa użytkownika jest taka sama jak hasło, jak pokazano w poniższym kodzie.

public class MyCustomUserNamePasswordValidator : UserNamePasswordValidator
{
  // This method validates users. It allows in two users,
  // test1 and test2 with passwords 1tset and 2tset respectively.
  // This code is for illustration purposes only and
  // MUST NOT be used in a production environment because it
  // is NOT secure.
  public override void Validate(string userName, string password)
  {
    if (null == userName || null == password)
    {
      throw new ArgumentNullException();
    }

    if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
    {
      throw new SecurityTokenException("Unknown Username or Password");
    }
  }
}

Po zaimplementowaniu walidatora w kodzie usługi, host usługi musi zostać poinformowany o instancji walidatora, który ma być użyty. Odbywa się to przy użyciu następującego kodu:

Servicehost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new MyCustomUserNamePasswordValidatorProvider();

Możesz też wykonać te same czynności w konfiguracji:

<behavior>
    <serviceCredentials>
      <!--
      The serviceCredentials behavior allows one to specify a custom validator for username/password combinations.
      -->
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.MyCustomUserNameValidator, service" />
    ...
    </serviceCredentials>
</behavior>

Program Windows Communication Foundation (WCF) udostępnia bogaty model oparty na oświadczeniach na potrzeby przeprowadzania kontroli dostępu. Obiekt ServiceAuthorizationManager służy do sprawdzania dostępu i określania, czy oświadczenia skojarzone z klientem spełniają wymagania niezbędne do uzyskania dostępu do metody usługi.

Na potrzeby demonstracji ten przykład pokazuje implementację ServiceAuthorizationManager, implementującą metodę CheckAccessCore, umożliwiającą użytkownikowi dostęp do metod na podstawie twierdzeń typu http://example.com/claims/allowedoperation, gdzie wartością jest identyfikator URI akcji operacji, która może być wywoływana.

public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
  protected override bool CheckAccessCore(OperationContext operationContext)
  {
    string action = operationContext.RequestContext.RequestMessage.Headers.Action;
    Console.WriteLine("action: {0}", action);
    foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
    {
      if ( cs.Issuer == ClaimSet.System )
      {
        foreach (Claim c in cs.FindClaims("http://example.com/claims/allowedoperation", Rights.PossessProperty))
        {
          Console.WriteLine("resource: {0}", c.Resource.ToString());
          if (action == c.Resource.ToString())
            return true;
        }
      }
    }
    return false;
  }
}

Po zaimplementowaniu niestandardowego ServiceAuthorizationManager należy poinformować hosta usługi, który ServiceAuthorizationManager ma być używany. Odbywa się to tak, jak pokazano w poniższym kodzie.

<behavior>
    ...
    <serviceAuthorization serviceAuthorizationManagerType="Microsoft.ServiceModel.Samples.MyServiceAuthorizationManager, service">
        ...
    </serviceAuthorization>
</behavior>

Podstawową metodą do zaimplementowania jest metoda IAuthorizationPolicy.

public class MyAuthorizationPolicy : IAuthorizationPolicy
{
    string id;

    public MyAuthorizationPolicy()
    {
    id =  Guid.NewGuid().ToString();
    }

    public bool Evaluate(EvaluationContext evaluationContext,
                                            ref object state)
    {
        bool bRet = false;
        CustomAuthState customstate = null;

        if (state == null)
        {
            customstate = new CustomAuthState();
            state = customstate;
        }
        else
            customstate = (CustomAuthState)state;
        Console.WriteLine("In Evaluate");
        if (!customstate.ClaimsAdded)
        {
           IList<Claim> claims = new List<Claim>();

           foreach (ClaimSet cs in evaluationContext.ClaimSets)
              foreach (Claim c in cs.FindClaims(ClaimTypes.Name,
                                         Rights.PossessProperty))
                  foreach (string s in
                        GetAllowedOpList(c.Resource.ToString()))
                  {
                       claims.Add(new
               Claim("http://example.com/claims/allowedoperation",
                                    s, Rights.PossessProperty));
                            Console.WriteLine("Claim added {0}", s);
                      }
                   evaluationContext.AddClaimSet(this,
                           new DefaultClaimSet(this.Issuer,claims));
                   customstate.ClaimsAdded = true;
                   bRet = true;
                }
         else
         {
              bRet = true;
         }
         return bRet;
     }
...
}

Poprzedni kod pokazuje, jak Evaluate(EvaluationContext, Object) metoda sprawdza, czy nie dodano żadnych nowych oświadczeń, które wpływają na przetwarzanie i dodaje określone oświadczenia. Dozwolone uprawnienia są uzyskiwane z GetAllowedOpList metody, której zadaniem jest zwrócenie określonej listy operacji, które użytkownik może wykonać. Zasady autoryzacji dodają roszczenia do uzyskania dostępu do konkretnej operacji. Jest on później używany przez program ServiceAuthorizationManager do podejmowania decyzji dotyczących kontroli dostępu.

Po zaimplementowaniu niestandardowego IAuthorizationPolicy, należy poinformować hosta usługi o zasadach autoryzacji, które mają być używane.

<serviceAuthorization>
       <authorizationPolicies>
            <add policyType='Microsoft.ServiceModel.Samples.CustomAuthorizationPolicy.MyAuthorizationPolicy, PolicyLibrary' />
       </authorizationPolicies>
</serviceAuthorization>

Po uruchomieniu przykładu żądania operacji i odpowiedzi są wyświetlane w oknie konsoli klienta. Klient pomyślnie wywołuje metody Add, Subtract i Multiple i otrzymuje komunikat "Odmowa dostępu" podczas próby wywołania metody Divide. Naciśnij ENTER w oknie klienta, aby zamknąć klienta.

Skonfiguruj plik wsadowy

Plik wsadowy Setup.bat dołączony do tego przykładu umożliwia skonfigurowanie serwera z odpowiednimi certyfikatami w celu uruchomienia aplikacji hostowanej samodzielnie, która wymaga zabezpieczeń opartych na certyfikatach serwera.

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 to localhost.

    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
    
  • Instalowanie certyfikatu serwera do magazynu zaufanych certyfikatów klienta.

    Następujące wiersze w pliku wsadowym Setup.bat kopiują certyfikat serwera do magazynu zaufanych certyfikatów klienta. Ten krok jest wymagany, ponieważ certyfikaty generowane przez Makecert.exe nie są automatycznie zaufane przez system klienta. Jeśli masz już certyfikat osadzony w zaufanym certyfikacie głównym klienta — na przykład certyfikat wystawiony przez firmę Microsoft — ten krok dodawania certyfikatu serwera do magazynu certyfikatów klienta nie jest wymagany.

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

    Następujące wiersze z pliku wsadowego Setup.bat tworzą certyfikat klienta do użycia. Zmienna %USER_NAME% określa nazwę serwera. Ta wartość jest ustawiona na "test1", ponieważ IAuthorizationPolicy szuka tej nazwy. Jeśli zmienisz wartość %USER_NAME% musisz zmienić odpowiednią wartość w metodzie IAuthorizationPolicy.Evaluate .

    Certyfikat jest przechowywany w magazynie Mój (osobisty) w lokalizacji magazynu CurrentUser.

    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%CLIENT_NAME% -sky exchange -pe
    
  • Instalowanie certyfikatu klienta w magazynie zaufanych certyfikatów serwera.

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

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

Aby skonfigurować i skompilować przykład

  1. 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).

  2. Aby uruchomić przykład w konfiguracji pojedynczej lub między komputerami, skorzystaj z poniższych instrukcji.

Uwaga / Notatka

Jeśli używasz Svcutil.exe, aby ponownie wygenerować konfigurację dla tego przykładu, pamiętaj o zmianie nazwy punktu końcowego w konfiguracji klienta, aby odpowiadała ona kodowi klienta.

Aby uruchomić przykład na tym samym komputerze

  1. Otwórz wiersz polecenia dewelopera dla programu Visual Studio z uprawnieniami administratora i uruchom Setup.bat z przykładowego folderu instalacji. To instaluje wszystkie certyfikaty wymagane do uruchomienia próbki.

    Uwaga / Notatka

    Plik wsadowy Setup.bat jest przeznaczony do uruchamiania z poziomu wiersza polecenia dla deweloperów dla programu Visual Studio. Zmienna środowiskowa PATH ustawiona w wierszu polecenia dewelopera dla 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.

Jeśli klient i usługa nie mogą się komunikować, sprawdź sekcję „Wskazówki dotyczące rozwiązywania problemów z przykładami programu WCF”.

Aby uruchomić próbkę na komputerach

  1. Utwórz katalog na komputerze usługi.

  2. Skopiuj pliki programu usługi z \service\bin do katalogu na komputerze usługi. Skopiuj również pliki Setup.bat, Cleanup.bat, GetComputerName.vbs i ImportClientCert.bat na komputer usługi.

  3. Utwórz katalog na komputerze klienckim dla plików binarnych klienta.

  4. Skopiuj pliki programu klienckiego do katalogu klienta na komputerze klienckim. Skopiuj również pliki Setup.bat, Cleanup.bati ImportServiceCert.bat do klienta.

  5. Na serwerze uruchom polecenie setup.bat service w wierszu polecenia dla deweloperów dla programu Visual Studio otwarte z uprawnieniami administratora.

    Uruchomienie setup.bat z argumentem service powoduje utworzenie certyfikatu usługi z w pełni kwalifikowaną nazwą domeny komputera i eksportuje certyfikat usługi do pliku o nazwie Service.cer.

  6. Edytuj Service.exe.config, aby odzwierciedlić nową nazwę certyfikatu (w atrybucie findValue w <serviceCertificate>), która jest taka sama jak w pełni kwalifikowana nazwa domeny komputera. Zmień również nazwę komputera w elemecie <service>/<baseAddresses> z localhost na w pełni kwalifikowaną nazwę komputera usługi.

  7. Skopiuj plik Service.cer z katalogu usługi do katalogu klienta na komputerze klienckim.

  8. Na kliencie uruchom polecenie setup.bat client w wierszu polecenia dla deweloperów dla programu Visual Studio otwarte z uprawnieniami administratora.

    Uruchomienie setup.bat z argumentem client powoduje utworzenie certyfikatu klienta o nazwie test1 i wyeksportowanie certyfikatu klienta do pliku o nazwie Client.cer.

  9. W pliku Client.exe.config na komputerze klienckim zmień wartość adresu punktu końcowego, aby odpowiadała nowemu adresowi usługi. W tym celu należy zastąpić localhost w pełni kwalifikowaną nazwą domeny serwera.

  10. Skopiuj plik Client.cer z katalogu klienta do katalogu usługi na serwerze.

  11. Na kliencie uruchom ImportServiceCert.bat w wierszu polecenia dla deweloperów dla programu Visual Studio otwartym z uprawnieniami administratora.

    Spowoduje to zaimportowanie certyfikatu usługi z pliku Service.cer do magazynu CurrentUser: TrustedPeople.

  12. Na serwerze uruchom ImportClientCert.bat w wierszu polecenia dewelopera dla programu Visual Studio otwartym z uprawnieniami administratora.

    Spowoduje to zaimportowanie certyfikatu klienta z pliku Client.cer do magazynu LocalMachine — TrustedPeople .

  13. Na komputerze serwera uruchom Service.exe w oknie wiersza polecenia.

  14. Na komputerze klienckim uruchom Client.exe w oknie wiersza polecenia.

    Jeśli klient i usługa nie mogą się komunikować, sprawdź sekcję „Wskazówki dotyczące rozwiązywania problemów z przykładami programu WCF”.

Czyszczenie po przykładzie

Aby wyczyścić po uruchomieniu próbki, uruchom Cleanup.bat w folderze z próbkami po zakończeniu działania próbki. Spowoduje to usunięcie certyfikatów serwera i klienta z magazynu certyfikatów.

Uwaga / Notatka

Ten skrypt nie usuwa certyfikatów usługi na kliencie podczas uruchamiania tego przykładu na komputerach. Jeśli uruchamiałeś przykłady WCF korzystające z certyfikatów na różnych komputerach, pamiętaj o wyczyszczeniu certyfikatów usługi, które zostały zainstalowane w magazynie CurrentUser - TrustedPeople. W tym celu użyj następującego polecenia: certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> Na przykład: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.