Udostępnij za pośrednictwem


Wystawca uwierzytelnienia tokenów

W tym przykładzie pokazano, jak zaimplementować niestandardowy moduł uwierzytelniania tokenów. Wystawca uwierzytelnienia tokenu w programie Windows Communication Foundation (WCF) służy do weryfikowania tokenu używanego z komunikatem, sprawdzania, czy jest on spójny i uwierzytelniania tożsamości skojarzonej z tokenem.

Niestandardowe wystawcy uwierzytelniania tokenów są przydatne w różnych przypadkach, takich jak:

  • Jeśli chcesz zastąpić domyślny mechanizm uwierzytelniania skojarzony z tokenem.

  • Podczas tworzenia tokenu niestandardowego.

W tym przykładzie przedstawiono następujące elementy:

  • Jak klient może uwierzytelniać się przy użyciu pary nazwy użytkownika/hasła.

  • Jak serwer może zweryfikować poświadczenia klienta przy użyciu niestandardowego wystawcy uwierzytelniania tokenu.

  • Jak kod usługi WCF jest związany z modułem uwierzytelniającego token niestandardowy.

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

W tym przykładzie pokazano również, jak tożsamość obiektu wywołującego jest dostępna z poziomu programu WCF po procesie uwierzytelniania tokenu niestandardowego.

Usługa uwidacznia pojedynczy punkt końcowy do komunikowania się z usługą, zdefiniowany przy użyciu pliku konfiguracji App.config. Punkt końcowy składa się z adresu, powiązania i kontraktu. Powiązanie jest konfigurowane przy użyciu standardu wsHttpBinding, z trybem zabezpieczeń ustawionym na komunikat — domyślnym trybem wsHttpBinding. W tym przykładzie ustawiono standard wsHttpBinding uwierzytelniania nazwy użytkownika klienta. Usługa konfiguruje również certyfikat usługi przy użyciu serviceCredentials zachowania. Zachowanie securityCredentials umożliwia określenie 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 poniższych instrukcjach konfiguracji.

<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 address=""
                  binding="wsHttpBinding"
                  bindingConfiguration="Binding1"
                  contract="Microsoft.ServiceModel.Samples.ICalculator" />
      </service>
    </services>

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

    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="False" />
          <!--
          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>
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>

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 przy użyciu odpowiednich Mode ustawień i clientCredentialType.

<system.serviceModel>
    <client>
      <endpoint name=""
                address="http://localhost:8000/servicemodelsamples/service"
                binding="wsHttpBinding"
                bindingConfiguration="Binding1"
                contract="Microsoft.ServiceModel.Samples.ICalculator">
      </endpoint>
    </client>

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

Implementacja klienta ustawia nazwę użytkownika i hasło do użycia.

static void Main()
{
     ...
     client.ClientCredentials.UserNamePassword.UserName = username;
     client.ClientCredentials.UserNamePassword.Password = password;
     ...
}

Niestandardowy wystawca uwierzytelniającego token

Aby utworzyć niestandardowy wystawcę uwierzytelniającego token, wykonaj następujące czynności:

  1. Pisanie niestandardowego wystawcy uwierzytelniającego token.

    Przykład implementuje niestandardowy wystawcę uwierzytelniającego token, który sprawdza, czy nazwa użytkownika ma prawidłowy format poczty e-mail. Pochodzi on z klasy UserNameSecurityTokenAuthenticator. Najważniejszą metodą w tej klasie jest ValidateUserNamePasswordCore(String, String). W tej metodzie wystawca uwierzytelnienia weryfikuje format nazwy użytkownika, a także, że nazwa hosta nie pochodzi z nieautoryzowanych domen. Jeśli oba warunki zostaną spełnione, zwraca ona kolekcję IAuthorizationPolicy wystąpień tylko do odczytu, która jest następnie używana do dostarczania oświadczeń reprezentujących informacje przechowywane wewnątrz tokenu nazwy użytkownika.

    protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password)
    {
        if (!ValidateUserNameFormat(userName))
            throw new SecurityTokenValidationException("Incorrect UserName format");
    
        ClaimSet claimSet = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userName, Rights.PossessProperty));
        List<IIdentity> identities = new List<IIdentity>(1);
        identities.Add(new GenericIdentity(userName));
        List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
        policies.Add(new UnconditionalPolicy(ClaimSet.System, claimSet, DateTime.MaxValue.ToUniversalTime(), identities));
        return policies.AsReadOnly();
    }
    
  2. Podaj zasady autoryzacji zwracane przez moduł uwierzytelniania tokenu niestandardowego.

    Ten przykład zawiera własną implementację IAuthorizationPolicy wywołaną UnconditionalPolicy , która zwraca zestaw oświadczeń i tożsamości przekazanych do niego w konstruktorze.

    class UnconditionalPolicy : IAuthorizationPolicy
    {
        String id = Guid.NewGuid().ToString();
        ClaimSet issuer;
        ClaimSet issuance;
        DateTime expirationTime;
        IList<IIdentity> identities;
    
        public UnconditionalPolicy(ClaimSet issuer, ClaimSet issuance, DateTime expirationTime, IList<IIdentity> identities)
        {
            if (issuer == null)
                throw new ArgumentNullException("issuer");
            if (issuance == null)
                throw new ArgumentNullException("issuance");
    
            this.issuer = issuer;
            this.issuance = issuance;
            this.identities = identities;
            this.expirationTime = expirationTime;
        }
    
        public string Id
        {
            get { return this.id; }
        }
    
        public ClaimSet Issuer
        {
            get { return this.issuer; }
        }
    
        public DateTime ExpirationTime
        {
            get { return this.expirationTime; }
        }
    
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            evaluationContext.AddToTarget(this, this.issuance);
    
            if (this.identities != null)
            {
                object value;
                IList<IIdentity> contextIdentities;
                if (!evaluationContext.Properties.TryGetValue("Identities", out value))
                {
                    contextIdentities = new List<IIdentity>(this.identities.Count);
                    evaluationContext.Properties.Add("Identities", contextIdentities);
                }
                else
                {
                    contextIdentities = value as IList<IIdentity>;
                }
                foreach (IIdentity identity in this.identities)
                {
                    contextIdentities.Add(identity);
                }
            }
    
            evaluationContext.RecordExpirationTime(this.expirationTime);
            return true;
        }
    }
    
  3. Pisanie niestandardowego menedżera tokenów zabezpieczających.

    Element SecurityTokenManager służy do tworzenia SecurityTokenAuthenticator obiektu dla określonych SecurityTokenRequirement obiektów, które są przekazywane do niego w metodzie CreateSecurityTokenAuthenticator . Menedżer tokenów zabezpieczających jest również używany do tworzenia dostawców tokenów i serializatorów tokenów, ale nie są one objęte tym przykładem. W tym przykładzie niestandardowy menedżer tokenów zabezpieczających dziedziczy po ServiceCredentialsSecurityTokenManager klasie i zastępuje CreateSecurityTokenAuthenticator metodę zwracania niestandardowego wystawcy uwierzytelnienie tokenu nazwy użytkownika, gdy przekazane wymagania dotyczące tokenu wskazują, że żądana jest uwierzytelnianie nazwy użytkownika.

    public class MySecurityTokenManager : ServiceCredentialsSecurityTokenManager
    {
        MyUserNameCredential myUserNameCredential;
    
        public MySecurityTokenManager(MyUserNameCredential myUserNameCredential)
            : base(myUserNameCredential)
        {
            this.myUserNameCredential = myUserNameCredential;
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            if (tokenRequirement.TokenType ==  SecurityTokenTypes.UserName)
            {
                outOfBandTokenResolver = null;
                return new MyTokenAuthenticator();
            }
            else
            {
                return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
            }
        }
    }
    
  4. Napisz poświadczenia usługi niestandardowej.

    Klasa poświadczeń usługi służy do reprezentowania poświadczeń skonfigurowanych dla usługi i tworzy menedżera tokenów zabezpieczających, który jest używany do uzyskiwania wystawców uwierzytelnień tokenów, dostawców tokenów i serializatorów tokenów.

    public class MyUserNameCredential : ServiceCredentials
    {
    
        public MyUserNameCredential()
            : base()
        {
        }
    
        protected override ServiceCredentials CloneCore()
        {
            return new MyUserNameCredential();
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new MySecurityTokenManager(this);
        }
    
    }
    
  5. Skonfiguruj usługę tak, aby korzystała z poświadczeń usługi niestandardowej.

    Aby usługa korzystała z poświadczeń usługi niestandardowej, usuwamy domyślną klasę poświadczeń usługi po przechwyceniu certyfikatu usługi, który jest już wstępnie skonfigurowany w domyślnym poświadczeniu usługi, i skonfigurujemy nowe wystąpienie poświadczeń usługi do używania wstępnie skonfigurowanych certyfikatów usługi i dodamy to nowe wystąpienie poświadczeń usługi do zachowania usługi.

    ServiceCredentials sc = serviceHost.Credentials;
    X509Certificate2 cert = sc.ServiceCertificate.Certificate;
    MyUserNameCredential serviceCredential = new MyUserNameCredential();
    serviceCredential.ServiceCertificate.Certificate = cert;
    serviceHost.Description.Behaviors.Remove((typeof(ServiceCredentials)));
    serviceHost.Description.Behaviors.Add(serviceCredential);
    

Aby wyświetlić informacje elementu wywołującego, możesz użyć elementu PrimaryIdentity , jak pokazano w poniższym kodzie. Zawiera Current informacje o aktualnym obiekcie wywołującym.

static void DisplayIdentityInformation()
{
    Console.WriteLine("\t\tSecurity context identity  :  {0}",
            ServiceSecurityContext.Current.PrimaryIdentity.Name);
     return;
}

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 odpowiednimi certyfikatami 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.

    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 w magazynie zaufanych 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 root 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 CurrentUser -s TrustedPeople
    

    Uwaga

    Plik wsadowy instalatora jest przeznaczony do uruchamiania z wiersza polecenia zestawu Windows SDK. Wymaga to, aby zmienna środowiskowa MSSDK wskazywała katalog, w którym zainstalowano zestaw SDK. Ta zmienna środowiskowa jest automatycznie ustawiana w wierszu polecenia zestawu Windows SDK.

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

Aby uruchomić przykład na tym samym komputerze

  1. Uruchom Setup.bat z folderu instalacji przykładowej w wierszu polecenia programu Visual Studio otwartym 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 App.config usługi. Można go utworzyć przy użyciu Setup.bat, jeśli ustawisz zmienną %SERVER_NAME% na w pełni kwalifikowaną nazwę hosta komputera, na którym będzie uruchomiona usługa. Należy pamiętać, że plik setup.bat musi zostać uruchomiony z poziomu wiersza polecenia dewelopera dla programu Visual Studio otwartego z uprawnieniami administratora.

  4. Skopiuj certyfikat serwera do magazynu CurrentUser-Trusted Osoby klienta. Nie trzeba tego robić z wyjątkiem sytuacji, gdy certyfikat serwera jest wystawiany przez zaufanego wystawcę klienta.

  5. W pliku App.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 Client.exe z 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.