MSDN Magazin > Home > Ausgaben > 2009 > MSDN Magazin Januar 2009 >  Erstellen eines Sicherheitstokendiensts (STS) m...
Geneva Framework
Erstellen eines benutzerdefinierten Sicherheitstokendiensts
Michele Leroux Bustamante

Dieser Artikel basiert auf der Vorabversion von „Geneva“ Framework. Änderungen an allen Informationen in diesem Artikel sind vorbehalten.

Themen in diesem Artikel:
  • Implementieren des Sicherheitstokendiensts mit Geneva Framework
  • Verbundsicherheit
  • Anspruchstransformation
In diesem Artikel werden folgende Technologien verwendet:
Windows Communication Foundation, ASP.NET, Geneva Framework
Die Plattformstrategie von Microsoft mit Zugriff auf der Grundlage von Ansprüchen (Claims-Based Access, CBA), dessen Codename „Geneva“ lautet, umfasst „Geneva“ Framework, „Geneva“ Server und Windows CardSpace „Geneva“. Geneva Framework bietet Entwicklertools für das Erstellen anspruchsbasierter Anwendungen und Dienste, die Token beinhalten, die von einem Sicherheitstokendienst (Security Token Service, STS) ausgestellt werden, sowie Tools für das Erstellen eines benutzerdefinierten STS und von Windows CardSpace-fähigen Anwendungen. Geneva Server ist ein Unternehmens-STS, während Geneva Framework ermöglicht, einen benutzerdefinierten STS für Umgebungen zu erstellen, für die keine Features auf Unternehmensebene erforderlich sind. Windows CardSpace Geneva ist die Weiterentwicklung von Windows CardSpace als Identitätsauswahl und Identitätsanbieter auf Windows-Clientcomputern.
In meinem letzten Artikel über Geneva Framework wurde eine bessere Möglichkeit beschrieben, um anspruchsbasierte WCF-Dienste (Windows Communication Foundation) zu erstellen, die auf von einem STS ausgestellten Token basieren. Im Folgenden wird mit Geneva Framework ein benutzerdefinierter STS erstellt.
Vor dem Weiterlesen empfiehlt sich die Lektüre des Artikels Geneva Framework-Whitepaper für Entwickler von Keith Braun und Sesha Mani und meines letzten Artikels Geneva Framework: Ein besserer Ansatz zum Erstellen anspruchsbasierter WCF-Dienste.

Einführung in Sicherheitstokendienste
Unabhängig davon, ob der STS auf Geneva Server basiert oder mit Geneva Framework erstellt wurde, seine primäre Rolle besteht darin, als Sicherheitsgateway für das Authentifizieren von Aufrufern zu fungieren und Sicherheitstoken auszustellen, die Ansprüche beinhalten, die den Aufrufer beschreiben. Wie in den oben genannten Artikeln beschrieben, gibt es mehrere Szenarios, die von der STS-Authentifizierung unterstützt werden:
  • Das Entkoppeln von Anwendungen und Diensten vom Authentifizierungsmechanismus, damit diese sich auf die Autorisierung der relevanten Ansprüche konzentrieren können.
  • Die Unterstützung mehrerer Anmeldeinformationstypen, ohne die Implementierung von Anwendungen und Diensten zu erschweren.
  • Die Unterstützung von Verbundszenarios, bei denen Benutzer von ihrer Domäne authentifiziert werden und Zugriff auf Ressourcen in einer anderen Domäne erhalten, indem eine Vertrauensstellung zwischen den STS der einzelnen Domänen hergestellt wird.
  • Das Vereinfachen der Identitätsdelegierungsszenarios, bei denen dem authentifizierten Benutzer Zugriff auf nachgeschaltete Dienste gewährt wird.
  • Das Vereinfachen der Anspruchstransformation, damit für die Autorisierung bei Anwendungen und Diensten relevante Ansprüche verfügbar sind.
Jedes dieser Szenarios kann auf einem passiven Verbund (browserbasiert) oder aktiven Verbund (Windows-clientbasiert) basieren. Als Nächstes werden diese Szenarios näher erläutert, wobei beschrieben wird, wie Sie eine relevante Logik in einen benutzerdefinierten, mit Geneva Framework erstellten STS einarbeiten.
Doch bevor die Implementierung eines STS näher betrachtet wird, sollen zunächst einige Grundlagen wiederholt werden. Ein STS, der in einem aktivem Verbund verwendet wird, ist eine Implementierung des „WS-Federation Active Requestor Profile“ (siehe WS-Federation TC) und (hauptsächlich) die WS-Trust-Spezifikation (siehe WS-Trust 1.3).
Allgemein betrachtet beschreibt WS-Trust einen Vertrag mit vier Dienstvorgängen: Ausstellen, Überprüfen, Erneuern und Abbrechen. Dementsprechend werden diese Vorgänge von Clients aufgerufen, um ein Sicherheitstoken anzufordern, ein Sicherheitstoken zu überprüfen, ein abgelaufenes Sicherheitstoken zu erneuern oder ein Sicherheitstoken, das nicht mehr verwendet werden sollte, abzubrechen. Jedem Vorgang werden Nachrichten in Form einer Anforderung für ein Sicherheitstoken (Request for Security Token, RST) und Antwortnachrichten in Form einer RST-Antwort (RST Response, RSTR) entsprechend der WS-Trust-Spezifikation gesendet. In diesem Artikel wird davon ausgegangen, dass das ausgestellte Token ein SAML (Security Assertion Markup Language) 1.1- oder ein SAML 2.0-Token ist.
Abbildung 1 zeigt die zentralen Inhalte von RST und RSTR für die aktive Tokenausstellung. Die RST-Nachricht enthält die für die Anforderung des Sicherheitstokens erforderlichen Informationen, einschließlich der Art des auszustellenden Tokens (im Folgenden SAML), die von der vertrauenden Seite (Relying Party, RP) angeforderten Ansprüche, die im ausgestellten Token enthalten sein sollen, die Informationen zur RP (AppliesTo), einschließlich der URL und in der Regel des Zertifikats zur Identifizierung der RP, und optional (nicht gezeigt) das Schlüsselmaterial, das für den Schlüssel zum Beweis des Besitzes (Beweisschlüssel), der mit der RST-Antwort zurückgegeben wird, verwendet wird.
Abbildung 1 Tokenausstellung für ein aktives Verbundszenario
Wenn die Tokenausstellung erfolgreich ist, enthält die RST-Antwort das ausgestellte SAML-Token und den Beweisschlüssel (vorausgesetzt, der STS entscheidet, welcher Beweisschlüssel verwendet werden soll und gibt ihn folglich in der RST-Antwort zurück). Das SAML-Token enthält relevante Ansprüche für die authentifizierte Partei, wird vom STS signiert, um das Token vor Manipulation zu schützen, enthält den Beweisschlüssel, der für die RP verschlüsselt wird, und wird selbst für die RP verschlüsselt, damit nur der beabsichtigte Empfänger das Token verarbeiten kann.
Der Client verwendet den Beweisschlüssel, um die Nachricht an die RP zu signieren. Die RP muss den Beweisschlüssel innerhalb des SAML-Tokens entschlüsseln können oder die Nachricht ablehnen. Wenn der Beweisschlüssel innerhalb des Tokens mit der Signatur für die Nachricht übereinstimmt, beweist dies, dass der Aufruf der RP von der Partei gesendet wurde, die das Token angefordert hat.
Passive Verbundszenarios basieren auf einem „WS-Federation Passive Requestor Profile“ mit einer browserbasierten Kommunikation. Das zugrunde liegende Messaging basiert weiterhin auf WS-Trust. Doch die Anforderung für ein Sicherheitstoken (RST) wird auf der STS-URL in Abfragezeichenfolgeparameter unterteilt, und die RST-Antwort wird der RP in der Regel als Form-Parameter bereitgestellt. Der passive STS und die RP fangen diese Parameter mit Verbundwebhandlern ab. Der passive STS verarbeitet WS-Trust-Anforderungen möglicherweise direkt oder übergibt sie einer zugrunde liegenden WS-Trust-Implementierung. Abbildung 2 zeigt, wie die RST und die RST-Antwort in einem passiven Verbundszenario behandelt werden.
Abbildung 2 Tokenausgabe für ein passives Verbundszenario
Ein relevanter Unterschied zwischen den aktiven und passiven Verbundszenarios ist die Art des ausgestellten SAML-Tokens. Der aktive Verbund beruht meistens auf einem SAML-Token, das eine Subjektbestätigung vom Typ „Inhaber des Schlüssels“ verwendet, d. h. es wird, wie oben beschrieben, ein Beweisschlüssel verwendet, um zu beweisen, dass es sich bei dem Client, der das zu authentifizierende Token sendet, um das Subjekt handelt, das das Token angefordert hat (auch ActAs-Verhalten genannt). Passive Verbundszenarios beinhalten meist ein SAML-Token mit einer Subjektbestätigung des Typs „Träger“ (auch Trägertoken genannt). Diese Art von Token enthält keinen Beweisschlüssel und wird manchmal als schlüsselloses Token bezeichnet. Es verlässt sich auf den Transport, um den Beweisschlüssel vom STS zu erhalten und der RP weiterzuleiten.
Diese Konzepte – WS-Verbund, WS-Trust und SAML-Token – stellen wichtige Hintergrundinformationen für die folgende Behandlung dar. Zuerst wird beschrieben, wie Sie einen aktiven STS unter Verwendung von Geneva Framework erstellen. Anschließend wird untersucht, wie Sie einen passiven STS erstellen, und abschließend werden einige erweiterte Szenarios für jeden STS erläutert.

Erstellen eines benutzerdefinierten aktiven STS
In einem einfachen aktiven Verbundszenario, wie z. B. in Abbildung 3, sind in der Regel die folgenden Teilnehmer vorhanden:
  • Eine RP, die den von einem Client aufgerufenen Dienst darstellt.
  • Ein einzelner STS, ebenfalls als Dienst implementiert, der das WS-Trust-Protokoll unterstützt. Dieser STS authentifiziert Aufrufer und stellt ein Sicherheitstoken mit Ansprüchen aus, die den Aufrufer identifizieren. Er wird auch Identitätsanbieter oder IP-STS genannt.
  • Ein Client, in diesem Fall eine Windows-basierte Anwendung, der auf einem Proxy basiert, um bei einem STS zu authentifizieren, um das daraus resultierende ausgestellte Token abzurufen und um der RP, die das ausgestellte Token zur Authentifizierung und Autorisierung bereitstellt, Nachrichten zu senden.
Abbildung 3 Ein einfaches Verbundszenario mit einer einzelnen RP und einem aktiven IP-STS
Abbildung 4 zeigt die beweglichen Teile dieser Implementierung. Enthalten sind eine benutzerdefinierte SecurityTokenService-Implementierung, die Verwendung einer ServiceHost-Erweiterung (WSTrustServiceHost), um die Laufzeit für den Verbund zu initialisieren, die Konfiguration eines oder mehrerer WS-Trust-Endpunkte unter Verwendung einer Ableitung des WSTrustContract-Typs und andere verwandte Konfigurationseinstellungen für die Identitätsmodelllaufzeit. In den nachfolgenden Abschnitten werden die einzelnen Elemente einer benutzerdefinierten, auf Geneva Framework basierten STS-Implementierung erläutert.
Abbildung 4 Implementierungsarchitektur für einen benutzerdefinierten aktiven STS und einen aktiven IP-STS

Erweitern eines SecurityTokenService
Geneva Framework bietet die zentrale Funktionalität für das Erstellen eines benutzerdefinierten STS durch den SecurityTokenService-Typ vom Microsoft.IdentityModel.SecurityTokenService-Namespace. Diese abstrakte Klasse erledigt die mühsame Arbeit der Verarbeitung der RST- und RSTR-Nachrichten und das Generieren von Sicherheitstoken. Ein benutzerdefinierter STS-Typ erbt diese Klasse und stellt (mindestens) die folgende Funktionalität bereit:
  • Einen Konstruktor, der eine benutzerdefinierte SecurityTokenServiceConfiguration-Instanz akzeptiert, um einige grundlegende Features des STS zu konfigurieren (mehr dazu weiter unten).
  • Eine Außerkraftsetzung für GetScope, um die Ziel-RP für die Anforderung zu überprüfen und geeignete Verschlüsselungsanmeldeinformationen für die RP und Signaturanmeldeinformationen für das Sicherheitstoken bereitzustellen.
  • Eine Außerkraftsetzung für GetOutputClaimsIdentity, um Ansprüche für das resultierende Sicherheitstoken bereitzustellen.
Abbildung 5 zeigt einen Code für eine einfache benutzerdefinierte STS-Implementierung mit dieser Funktionalität. Denken Sie an den Kommunikationsfluss für einen aktiven STS aus den Abbildungen 1 und 2 zurück. Die STS-Implementierung, IdentitySTS, überprüft die eingehende Anforderung für ein Sicherheitstoken, wenn GetScope aufgerufen wird, indem sie überprüft, dass das AppliesTo-Element der RST tatsächlich auf einen vertrauenswürdigen URI verweist. Vermutlich verwaltet der STS eine Liste vertrauenswürdiger RPs, für die Token ausgestellt werden können, sowie ihre jeweiligen Zertifikate. GetScope legt die EncryptingCredentials-Eigenschaft des Bereichs auf das geeignete Zertifikat fest, wenn AppliesTo die Prüfung besteht, in diesem Fall „RPKey“. Außerdem ist die SigningCredentials-Eigenschaft auf das geeignete Zertifikat festgelegt, das zum Signieren des ausgestellten Tokens verwendet werden soll. Dies ist in der Regel der private Schlüssel des STS, in diesem Fall „IPKey“.
public class IdentitySTS : SecurityTokenService
{
    public IdentitySTS(SecurityTokenServiceConfiguration config)
        : base( config )
    {
    }

    protected override IClaimsIdentity GetOutputClaimsIdentity(
        IClaimsPrincipal principal, RequestSecurityToken request, 
        Scope scope)
    {
        IClaimsIdentity claimsIdentity = new ClaimsIdentity();

        claimsIdentity.Claims.Add(new Claim(ClaimTypes.Name, 
            principal.Identity.Name));
        claimsIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Users"));

        return claimsIdentity;
    }

    protected override Scope  GetScope(
        Microsoft.IdentityModel.Claims.IClaimsPrincipal principal, 
        RequestSecurityToken request)
    {

        Scope scope = new Scope(request);
        scope.EncryptingCredentials = this.GetCredentialsForAppliesTo(
                                                     request.AppliesTo);
        scope.SigningCredentials = new 
          X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, 
          StoreLocation.LocalMachine, "CN=IPKey"));
        return scope;
    }

    private X509EncryptingCredentials GetCredentialsForAppliesTo(Endpoint
        Address appliesTo)
    {
        if (appliesTo == null || appliesTo.Uri ==null || 
          string.IsNullOrEmpty(appliesTo.Uri.AbsolutePath))
        {
            throw new InvalidRequestException(
                "AppliesTo must be supplied in the RST.");
        }

        X509EncryptingCredentials creds = null;
        if (appliesTo.Uri.AbsoluteUri.StartsWith(
            "http://localhost:8000/RelyingPartyService"))
        {
            creds = new X509EncryptingCredentials(
                CertificateUtil.GetCertificate(StoreName.TrustedPeople, 
                StoreLocation.LocalMachine, 
                "CN=RPKey"));
        }
        else
            throw new InvalidRequestException(String.Format(
                "Invalid relying party address: {0}", 
                appliesTo.Uri.AbsoluteUri));

        return creds;
    }
}
Wenn GetOutputClaimsIdentity aufgerufen wird, wird von der Laufzeit ein ClaimsPrincipal mit der Identität des authentifizierten Aufrufers übergeben. Mit dieser Identität werden in der Regel die entsprechenden Ansprüche bestimmt, die dem Aufrufer gewährt werden sollen. In Abbildung 5 generiert der Code einen Namensanspruch und einen hartcodierten Rollenanspruch für den Aufrufer und gibt dies in Form einer ClaimsIdentity zurück. Diese ClaimsIdentity stellt der Laufzeit Ansprüche für das Token bereit, das ausgestellt werden soll.
Diese STS-Implementierung könnte auch mit der folgenden Funktionalität erweitert werden:
  • GetOutputClaimsIdentity könnte Code für die Suche des Benutzers in einem benutzerdefinierten Anmeldeinformationsspeicher und für die Suche nach zusätzlichen Ansprüchen enthalten. Dazu gehören beispielsweise eine Liste der Rollen, andere relevante Details über den Benutzer, z. B. die E-Mail-Adresse, oder benutzerdefinierte Ansprüche, die detailliertere Anwendungsberechtigungen wie Erstellen, Lesen, Aktualisieren oder Löschen darstellen.
  • GetScope könnte den AppliesTo-URI in einer benutzerdefinierten Datenbank suchen, in der alle vertrauenswürdigen RPs mit ihren zugeordneten Zertifikaten auflistet sind.

Hosten und Konfigurieren eines STS
Wenn Sie mit WCF vertraut sind, wissen Sie, dass ein oder mehrere Endpunkte konfiguriert werden müssen, damit Clients einem Dienst Nachrichten senden. Im Fall eines STS muss der für jeden Endpunkt zu verwendende Dienstvertrag auf dem WS-Trust-Protokoll basieren, das vier Vorgänge umfasst: Ausstellen, Überprüfen, Erneuern und Abbrechen. Eigentlich gibt es zwei Versionen des WS-Trust-Protokolls, die von einem STS implementiert werden könnten:
  • WS-Trust 1.3: die aktuelle Version der WS-Trust-Spezifikation.
  • WS-Trust Februar 2005: Die Version von WS-Trust, die von vielen Branchenpartnern während des Ratifizierungszeitraums des Standards implementiert wurde.
Sie können – neben anderen Methoden – auch asynchrone Implementierungen für GetScope(), GetOutputClaimsIdentity() in Ihrem SecurityTokenService-Typ bereitstellen. Dadurch verbessert sich die Skalierbarkeit für E/A-intensive Vorgänge, z. B. das Zugreifen auf Zertifikate oder die Interaktion mit Anspruchsdaten. Wenn Sie Endpunkte für den STS konfigurieren, müssen Sie auswählen, welcher Vertrag für den Endpunkt verfügbar gemacht werden soll. Der Microsoft.IdentityModel.Protocols-Namespace enthält diese beiden Dienstverträge für STS-Endpunkte: „IWSTrust13SyncContract“ und „IWSTrustFeb2005SyncContract“. Abbildung 6 zeigt die Konfiguration für einen STS-Dienst mit zwei Endpunkten, einen für jeden Vertrag. Beachten Sie, dass es auch asynchrone Versionen des Vertrags gibt, um einen asynchronen Proxy zu implementieren: „IWSTrust13AsyncContract“ und „IWSTrustFeb2005AsyncContract“.
<service name=
  "Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract" 
  behaviorConfiguration="stsBehavior">
  <endpoint address="WSTrustFeb05" binding="wsHttpBinding" 
    contract="Microsoft.IdentityModel.Protocols.WSTrust.
    IWSTrustFeb2005SyncContract"/>
  <endpoint address="WSTrust13" binding="wsHttpBinding"  
    contract="Microsoft.IdentityModel.Protocols.WSTrust.
    IWSTrust13SyncContract"/>
</service>
Der STS muss einen Endpunkt verfügbar machen, der zur Abwärtskompatibilität mit bereits vorhandenen Clients auf dem „WS-Trust Februar 2005“ basiert. Der Diensttyp, der beide Verträge implementiert, ist der WSTrustServiceContract-Typ im Microsoft.IdentityModel.Protocols.WSTrust-Namespace. Dies ist der Typ, auf den im Konfigurationsabschnitt <service> für den STS verwiesen werden muss.
Wie im Diagramm in Abbildung 4 dargestellt, werden die <service>-Konfiguration und ihre Endpunkte verwendet, um den Host mit dem richtigen WSTrustServiceContract-Typ zu initialisieren. Dieser Typ wird außerdem mit einem Verweis auf die benutzerdefinierte SecurityTokenService-Implementierung während der Hostinitialisierung initialisiert. So sendet die Laufzeit dem benutzerdefinierten STS Nachrichten.
In Abbildung 6 basieren beide STS-Endpunkte auf den Windows-Anmeldeinformationen, um den Aufrufer zu authentifizieren (das Standardverhalten von wsHttpBinding). Der STS kann mehrere Endpunkte mit alternativen Bindungskonfigurationen verfügbar machen, um verschiedene Anmeldeinformationstypen zu unterstützen. Dazu gehört auch das Konfigurieren eines geeigneten Sicherheitstokenhandlers für jeden Anmeldeinformationstyp. Die Konfigurationseinstellungen für Tokenhandler werden in Kürze behandelt.
Geneva Framework stellt einen benutzerdefinierten ServiceHost-Typ, WSTrustServiceHost, zum Hosten von STS-Instanzen bereit. Der folgende Code zeigt, wie Sie den WSTrustServiceHost-Typ in einer Self-Hosting-Umgebung erstellen:
WSTrustServiceHost stsHost = 
  new WSTrustServiceHost(new IdentitySTSConfiguration());
stsHost.Open();
WSTrustServiceHost basiert auf einer benutzerdefinierten SecurityTokenServiceConfiguration-Instanz, um die Laufzeit mit WS-Trust-Endpunkten zu initialisieren, um das Metadatenaustauschverhalten für den STS zu ermöglichen und einen Endpunkt für den Metadatenaustausch zu konfigurieren.
Beim Hosten in IIS wird der WSTrustServiceHostFactory-Typ verwendet, um die gleichen Ergebnisse zu erzielen. In der .svc-Datei gibt die @ServiceHost-Konfiguration den Zuordnungsinstanztyp und den benutzerdefinierten SecurityTokenServiceConfiguration-Typ folgendermaßen an:
<%@ ServiceHost Factory="Microsoft.IdentityModel.Protocols.WSTrust. 
  WSTrustServiceHostFactory" 
  Service="STS.IdentitySTSConfiguration"  %>
Die Zuordnungsinstanz initialisiert bei Aktivierung den WSTrustServiceHost mit der angegebenen Konfiguration.
Ein benutzerdefinierter SecurityTokenServiceConfiguration-Typ ist erforderlich, um den WSTrustServiceHost für einen STS zu initialisieren. Abbildung 7 zeigt eine benutzerdefinierte Implementierung namens „IdentitySTSConfiguration“.
public class IdentitySTSConfiguration: SecurityTokenServiceConfiguration
{

    public IdentitySTSConfiguration(): base("http://localhost:8010/sts")
    {

      this.TokenIssuerName = "http://localhost:8010/sts";

      this.SigningCredentials = new 
        X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, 
        StoreLocation.LocalMachine, "CN=IPKey"));

      this.SecurityTokenService = typeof( IdentitySTS);

    }

}
Dieser Typ muss einen URI für den STS, Signaturanmeldeinformationen und einen Verweis auf den STS-Typ bereitstellen, mit dem die Konfiguration verbunden ist. Die URL muss gültig sein, falls der STS verwaltete Karten ausstellt, damit Windows CardSpace diese Karten importieren kann. Der Basistyp erfordert, dass dem Konstruktor für TokenIssuerName ein Zeichenfolgewert übergeben wird, aber ich empfehle, dies im Code außer Kraft zu setzen, damit Sie den URI von der Konfiguration dynamisch einstellen können, anstatt diesen dem Konstruktor übergebenen Wert hartzucodieren.
Der SecurityTokenServiceConfiguration-Typ macht außerdem Eigenschaften verfügbar, mit denen Standardeinstellungen für die Schlüsselgröße und den Tokentyp festgelegt, der Zugriff auf Metadaten deaktiviert, die Tokengültigkeitsdauer und Zeitabweichung kontrolliert, benutzerdefinierte RST- und RSTR-Serialisierer festgelegt, Tokenhandler konfiguriert, die Aufrufer authentifizieren, und WS-Trust-Endpunkte konfiguriert werden können.
Das folgende Beispiel zeigt, wie Sie den Metadatenzugriff deaktivieren und die WS-Trust-Endpunkte (wie diejenigen in Abbildung 6) programmgesteuert initialisieren können, anstatt sich auf die <service>-Konfigurationseinstellungen zu verlassen:
IdentitySTSConfiguration config = new IdentitySTSConfiguration();
config.DisableWsdl = true;
config.TrustEndpoints.Add(new 
  ServiceHostEndpointConfiguration("WSTrustFeb05", new WSHttpBinding(),  
  typeof(IWSTrustFeb2005SyncContract)));
config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration(
  "WSTrust13", new WSHttpBinding(), 
  typeof(IWSTrust13SyncContract)));

WSTrustServiceHost stsHost = new WSTrustServiceHost(config);
Der grundlegende SecurityTokenServiceConfiguration-Typ liest außerdem den Konfigurationsabschnitt <microsoft.identityModel>, um die relevanten STS-Konfigurationseinstellungen zu initialisieren. Einstellungen, die deklarativ für einen benutzerdefinierten STS konfiguriert werden können, enthalten die maximale Zeitabweichung, die Sicherheitstokenhandler für die Authentifizierung und Ausstellung, einen Manager für die Anspruchsauthentifizierung, eine Registrierung des Ausstellernamens und Tokenauflösungen. Abbildung 8 zeigt einige nützliche Einstellungen, die für einen STS konfiguriert wurden.
<microsoft.identityModel>
  <maximumClockSkew value="00:05:00"/>
  <claimsAuthenticationManager type="STS.
    CustomClaimsAuthenticationManager, STS"/>
  <securityTokenHandlers>
    <remove type="Microsoft.IdentityModel.Tokens.
      WindowsUserNameSecurityTokenHandler, 
      Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35" />
    <add type="Microsoft.IdentityModel.Tokens.
      MembershipUserNameSecurityTokenHandler, 
      Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35">
        <usernameSecurityTokenHandlerRequirement 
          membershipProvider="CustomProviders.CustomMembershipProvider, 
          CustomProviders, Version=1.0.0.0, Culture=neutral,
           PublicKeyToken=c03h5a64f15d0b3f" />
    </add>
  </securityTokenHandlers>
</microsoft.identityModel>
Ein benutzerdefinierter ClaimsAuthenticationManager-Typ wird für Nicht-Windows-Anmeldeinformationen aufgerufen, wodurch Sie die Option erhalten, der Laufzeit vor dem Ausstellen der Ansprüche in GetOutputClaimsIdentity einen benutzerdefinierten ClaimsPrincipal bereitzustellen. Benutzerdefinierte Sicherheitstokenhandler können gegebenenfalls konfiguriert werden, um Einstellungen bereitzustellen, die das Standardverhalten eines bestimmten Handlers außer Kraft setzen oder die Auswahl von Sicherheitstokenhandlern für einen bestimmten Anmeldeinformationstyp verändern.

Sicherheitstokenhandler
Sie erwarten wahrscheinlich, dass durch eine Dienstverhaltenskonfiguration festgelegt wird, wie die Authentifizierung und Autorisierung für jeden STS-Endpunkt stattfindet. Wie in meinem letzten Artikel erläutert, sehen die Vorgänge bei Geneva Framework etwas anders aus. Im Fall der Authentifizierung legt die Sammlung <securityTokenHandlers> die Security­TokenHandler-Typen fest, die für die Authentifizierung der eingehenden Anforderungen verfügbar sind.
Diese Sammlung kann nur einen Eintrag für jeden SecurityTokenHandler-Typ enthalten. Zum Beispiel kann nur ein KerberosSecurityToken­Handler, UserNameSecurityTokenHandler, X509SecurityTokenHandler, Saml11SecurityTokenHandler oder Saml2SecurityTokenHandler registriert werden, um die Anforderungen für den jeweiligen Anmeldeinformationstyp zu verarbeiten. Wenn der STS-Endpunkt UserName-Anmeldeinformationen erwartet, ist der standardmäßig registrierte UserNameSecurityTokenHandler der Windows­UserNameSecurityTokenHandler. Abbildung 8 zeigt das Entfernen von WindowsUserNameSecurityTokenHandler und seine Ersetzung durch das Hinzufügen von Membership­UserNameSecurityTokenHandler – einschließlich verwandter Konfigurationseinstellungen für den Mitgliedschaftsanbieter.
Sie können außerdem benutzerdefinierte SecurityTokenHandler-Typen erstellen. Denken Sie an Folgendes: Solange von der geeigneten Basisklasse abgeleitet wird, die der Tokenkategorie (z. B. UserNameSecurityTokenHandler) entspricht, können Sie den Standardhandler durch den neuen benutzerdefinierten Handler ersetzen. Abbildung 9 zeigt eine benutzerdefinierte UserNameSecurityTokenHandler-Implementierung namens „CustomUserNameSecurity­TokenHandler“.
public class CustomUserNameSecurityTokenHandler:   
  UserNameSecurityTokenHandler
{
  public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
  {
    UserNameSecurityToken userNameToken = token as UserNameSecurityToken;
    AuthenticateUser(userNameToken.UserName, userNameToken.Password);

    return new ClaimsIdentityCollection(new IClaimsIdentity[] {
      new ClaimsIdentity(
        new Claim(System.IdentityModel.Claims.ClaimTypes.Name,
         userNameToken.UserName), "CustomUserNameSecurityTokenHandler")});
  }

  public override bool CanValidateToken
  {
    get { return true; }
  }
}
Zumindest müssen ValidateToken und CanValidateToken in der benutzerdefinierten SecurityTokenHandler-Implementierung außer Kraft gesetzt werden. Im ValidateToken sind Sie für das Authentifizieren anhand des geeigneten Anmeldeinformationsspeichers verantwortlich. Das Ergebnis dieser Authentifizierung muss ein Satz von Ansprüchen sein, der an die Laufzeit zurückgegeben werden kann, um dem ClaimsPrincipal für den Anforderungsthread angefügt zu werden.
Abbildung 10 Ein einfaches Verbundszenario mit einer einzelnen RP und einem passiven IP-STS
Es ist zudem sehr wichtig, dass CanValidateToken außer Kraft gesetzt und „True“ zurückgegeben wird. Ohne diese Außerkraftsetzung wird der Tokenhandler in der Sammlung nicht registriert und nie aufgerufen.

Erstellen eines benutzerdefinierten passiven STS
In einem einfachen passiven Verbundszenario sind die gleichen Teilnehmer vorhanden wie in einem aktiven Verbundszenario (siehe Abbildung 3), mit den Ausnahmen, dass der Client ein Browser ist, die RP eine Webanwendung ist und dem IP-STS zudem eine Webanwendung vorgeschaltet ist, um die HTTP-basierte Kommunikation zu verarbeiten. Abbildung 10 zeigt die Teilnehmer und den Kommunikationsfluss für den passiven Verbund.
Die beweglichen Teile dieses Szenarios sind so ähnlich wie die in Abbildung 4 gezeigten, was den zentralen STS angeht, aber es gibt einige offensichtliche Unterschiede in der Weise, wie der passive STS die Authentifizierung behandelt und wie die zugrunde liegende STS-Funktionalität aufgerufen wird. Im Diagramm in Abbildung 10 werden diese Unterschiede allgemein aufgezeigt. Der passive STS ist als eine Website implementiert, die für die Sicherung des Tokenausstellungsprozesses SSL-Verschlüsselung erfordert. Die Standardseite (Default.aspx) hostet ein Steuerelement, das die Kommunikation mit dem zugrunde liegenden benutzerdefinierten STS vereinfacht, der so wie ein aktiver STS konfiguriert ist.
Die STS-Website muss den Aufrufer vor der Tokenausstellung authentifizieren, und hier kommt die klassische ASP.NET-Konfiguration für die Authentifizierung und Autorisierung ins Spiel. In Abbildung 11 wird die STS-Anwendung für die Formularauthentifizierung konfiguriert. Deshalb werden Anforderungen an eine Anmeldeseite (Login.aspx) umgeleitet, wenn sie vom FormsAuthenticationModule noch nicht authentifiziert wurden.
Ein passiver STS kann die gleiche zentrale STS-Implementierung nutzen wie ein aktiver STS – mit einer kleinen Änderung. In der GetScope-Außerkraftsetzung (siehe Abbildung 5) muss ein passiver STS die ReplyToAddress-Eigenschaft festlegen, damit der STS nach der Ausstellung des Tokens umleiten kann. Meist wird dies auf die Standardseite für die RP festgelegt und basiert auf der AppliesTo-Adresse, die mit der RST bereitgestellt wird:
Scope scope = new Scope(request);
scope.ReplyToAddress = scope.AppliesToAddress + "/default.aspx";
// other scope settings
Abbildung 11 Implementierungsarchitektur für einen passiven STS mittels Formularauthentifizierung
Die Geneva Framework-Konfiguration für einen passiven STS unterscheidet sich in keiner Weise von einem aktiven STS. Der STS wird mit einem SecurityTokenServiceConfiguration-Typ initialisiert (siehe Abbildung 7), und alle relevanten Einstellungen im <microsoft.identityModel>-Konfigurationsabschnitt werden ebenfalls berücksichtigt.

FederatedPassiveTokenService-Steuerelement
Geneva Framework stellt ein Steuerelement bereit, das die erforderliche Funktionalität eines passiven STS implementiert. Das heißt, es verarbeitet HTTP-Anforderungen beim An- und Abmelden, konvertiert jede Anforderung in eine RST und ruft anschließend die zugrunde liegende STS-Implementierung auf. Das Steuerelement verarbeitet außerdem RST-Antworten und behandelt die Umleitung zur RP. Zudem schreibt es das Sitzungscookie für authentifizierte Aufrufer.
Platzieren Sie dieses Steuerelement auf der Standardseite für die passive STS-Website, und setzen Sie die Diensteigenschaft des Steuerelements auf die benutzerdefinierte SecurityTokenServiceConfiguration-Implementierung, indem Sie folgendermaßen vorgehen:
<idfx:FederatedPassiveTokenService ID="FederatedPassiveTokenService1" 
  runat="server" Service="STS.IdentityProviderSTSConfiguration, STS">
</idfx:FederatedPassiveTokenService>
Das Steuerelement erfordert, dass der Benutzer authentifiziert wird, und überprüft dies im PreRender-Ereignis. Es wird erwartet, dass die STS-Website entsprechend konfiguriert ist, um sicherzustellen, dass Benutzer zur Authentifizierung umgeleitet werden, bevor sie diese Standardseite erreichen.
Solange authentifizierte Benutzer immer zu dieser Standardseite umgeleitet werden, ist keine andere Konfiguration erforderlich, um Anforderungen zu verarbeiten. Das Steuerelement bietet außerdem die Error-, PreSignInRequested-, PostSignInRequested-, PreSignOutRequested- und PostSignOut­Requested-Ereignisse, um Ausnahmen zu behandeln sowie An- und Abmeldeanforderungen einzubinden.

SessionAuthenticationModule
Als Alternative zum FederatedPassiveTokenService-Steuerelement können Sie programmgesteuert eine passive STS-Funktionalität aktivieren. Aktivieren Sie zuerst die Verbundauthentifizierung im <microsoft.identityModel>-Konfigurationsabschnitt:
<microsoft.identityModel>
  <federatedAuthentication enabled="true"/>
</microsoft.identityModel>
Aktivieren Sie als Nächstes das Verbundmodul für einen passiven STS, das SessionAuthenticationModule vom Microsoft.IdentityModel.Web-Namespace:
<modules>
  <add name="SessionAuthentication" 
    type="Microsoft.IdentityModel.Web.SessionAuthenticationModule,
    Microsoft.IdentityModel, Version=0.5.1.0,
    Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</modules>
Dadurch wird das gleiche Ergebnis erzielt wie vom FederatedPassiveTokenService-Steuerelement für Anforderungen, die an eine beliebige Seite auf der STS-Website gesendet werden. Das Modul leitet nicht authentifizierte Aufrufer an die Anmeldeseite weiter. Bei erfolgreicher Anmeldung werden Aufrufer zur ursprünglich angeforderten STS-Seite weitergeleitet. Dieser programmgesteuerte Ansatz gibt Entwicklern zusätzliche Kontrollmöglichkeiten, die über die vom FederatedPassiveTokenService-Steuerelement bereitgestellte Kontrolle hinausgehen. Zum Beispiel macht das Modul die folgenden Ereignisse verfügbar, um mit der Initialisierung, der Sicherheitstokenverwaltung, der Anmeldung und der Abmeldung zu interagieren: ConfigurationLoading, ConfigurationLoaded, SecurityTokenReceived, SecurityTokenValidated, SessionSecurityTokenCreated, SessionSecurityTokenReceived, SignedIn, SigningOut, SignedOut, SignInError und SignOutError.

Benutzerauthentifizierung
Die STS-Website ist für das Authentifizieren von Benutzern entsprechend der unterstützten Anmeldeinformationstypen verantwortlich. Während ein aktiver, mit WCF implementierter STS problemlos mehrere Endpunkte konfigurieren kann, um verschiedene Authentifizierungsmechanismen zu unterstützen, kann ein passiver STS aufgrund der Beschaffenheit der ASP.NET-Websitekonfiguration nur einen Authentifizierungsmechanismus unterstützen. Folglich muss für jeden unterstützten Authentifizierungsmechanismus eine andere passive STS-Website bereitgestellt werden. Diese Websites können selbstverständlich alle die gleiche zentrale STS-Implementierung nutzen.
Die passive STS-Authentifizierung basiert auf den ASP.NET-Konfigurationsverfahren. Ausgewählt werden in der Regel die Windows-Authentifizierung, die Formularauthentifizierung und die Windows CardSpace-Authentifizierung. Bei der Windows-Authentifizierung wird die folgende Konfiguration verwendet:
<authentication mode="Windows"/>
<authorization>
  <deny users="?"/>
</authorization>
Der Benutzer wird vor dem Erreichen der STS-Standardseite durch interaktive Dialogfelder authentifiziert. Deshalb ist eine benutzerdefinierte Anmeldeseite in diesem Fall nicht erforderlich.
Abbildung 11 zeigt ein Beispiel, bei dem die Formularauthentifizierung verwendet wird. Das FormsAuthenticationModule leitet nicht authentifizierte Aufrufe an die Anmeldeseite weiter, auf der vom Benutzer Anmeldeinformationen bereitgestellt werden können. Nach der Authentifizierung wird die Anmeldeseite zur STS-Standardseite umgeleitet, auf der das Verbundsteuerelement die Verarbeitung der ursprünglichen Anforderung fortsetzt. Die ASP.NET-Konfiguration dafür würde folgendermaßen aussehen:
<authentication mode="Forms"/>
<authorization>
  <deny users="?"/>
</authorization>
Bei der Windows CardSpace-Authentifizierung kann die STS-Website für die Formularauthentifizierung konfiguriert werden, aber die Anmeldeseite enthält dann ein InformationCard-Steuerelement für die Windows CardSpace-Authentifizierung.

Anspruchstransformation
Die Anspruchstransformation ist ein wesentlicher Bestandteil der Verbundsicherheit und kann an verschiedenen Stellen im Verbundfluss erfolgen. In einem einfachen Verbundszenario, bei dem der IP-STS und die RP derselben Domäne angehören, ist der IP-STS für die Transformation der Ansprüche verantwortlich, und zwar vom anfänglichen Satz der Identitätsansprüche, die der Benutzer während der Authentifizierung anzeigt, bis zu denjenigen, auf denen die RP zur Autorisierung von Aufrufen basiert. Benutzer können beliebige unterstützte Anmeldeinformationstypen verwenden, um sich beim IP-STS zu authentifizieren, wobei für die Bewertung jeweils ein Satz von Ansprüchen herangezogen wird, der den Anmeldeinformationen entspricht.
Der IP-STS transformiert diese Ansprüche in einen normalisierten Satz von Anwendungsansprüchen, aufgrund derer die RP Aufrufe autorisiert. Dies können Rollen oder detailliertere Ansprüche wie das Erstellen, Lesen, Aktualisieren oder Löschen von Berechtigungen sein. Das Diagramm in Abbildung 12 zeigt ein solches Szenario: Der Administratorbenutzer meldet sich an, und ihm bzw. ihr werden ein Rollenanspruch und mehrere Aktionsansprüche gewährt, einschließlich Erstellen, Lesen, Aktualisieren oder Löschen.
Abbildung 12 Anspruchstransformation am IP-STS
Diese Art von Anspruchstransformation ist insofern nützlich, als eine Authentifizierung bei einem STS zu einem Token führt, das alle Ansprüche beinhaltet, die dem Benutzer gewährt werden. Es gibt Fälle, in denen ein alternativer Ansatz zur Anspruchstransformation erforderlich ist, zum Beispiel, um die Ausstellung der Ansprüche auf die für den aktuellen Aufrufkontext relevanten Ansprüche zu begrenzen, um die Datensicherheit der Ansprüche zu gewährleisten oder um einen domänenübergreifenden Verbund zu ermöglichen.
Es ist nicht immer wünschenswert oder angebracht, einem authentifizierten Aufrufer eine lange Liste von Ansprüchen in Bezug auf alle Features zu gewähren, die von der RP verfügbar gemacht werden. Die Liste könnte nicht nur sehr lang ausfallen, sondern es ist auch möglich, dass die auszustellenden Ansprüche vom Aufrufkontext abhängen und folglich nicht ohne diesen Kontext ausgestellt werden sollten. Zum Beispiel ist es denkbar, dass einer Benutzerin der Löschanspruch nur dann gewährt wird, wenn sie Kundenbestellungen verarbeitet. Wenn sie aber direkt mit Kundendatensätzen interagiert, wird ihr diese Berechtigung möglicherweise nicht gewährt.
In Fällen wie diesen kann es nützlich sein, wenn die RP nur einige Ansprüche vom IP-STS anfordert, um den Aufrufer zu identifizieren, und dann ein neues Token mit einem spezifischen Satz zusätzlicher Ansprüche nur für den Kontext des Aufrufs anfordert. Wenn der Benutzer zum Beispiel den DeleteCustomer-Vorgang für einen RP-Dienst aufruft, ruft die RP vor dem Autorisieren des Zugriffs auf den Vorgang den RP-STS auf, reicht das Token vom IP-STS ein und fordert den Löschanspruch im Kontext des DeleteCustomer-Vorgangs an. Wenn der Anspruch vorhanden ist, wird der Aufruf autorisiert. Das Diagramm in Abbildung 13 veranschaulicht dieses Beispiel.
Es gibt auch Fälle, in denen die durch einen STS ausgestellten Ansprüche nicht an die RP direkt freigegeben werden sollten. Anstatt zum Beispiel einen Altersanspruch auszustellen, sodass die RP das Alter des Benutzers kennt, kann die RP den IsOver13-Anspruch anfordern, um sicherzustellen, dass der Aufrufer alt genug ist, um die RP-Funktionalität zu verwenden. Folglich bleibt der eigentliche Wert für den Altersanspruch immer beim STS. Selbstverständlich impliziert dies, dass der STS Ansprüche bereitstellt, bei denen die Freigabe persönlicher Details vermieden wird und die trotzdem für die RP nützliche Daten enthalten.
Abbildung 13 Anspruchstransformation am RP-STS
Die Anspruchstransformation findet auch in einem Verbundszenario statt, bei dem Benutzern, die einer Domäne angehören, der Zugriff auf eine RP in einer anderen Domäne gewährt wird. In diesem Fall sind zwei STS daran beteiligt – der IP-STS der Benutzerdomäne und der RP-STS für die Domäne, der die RP gehört.
In diesem Fall gewährt der IP-STS außerdem einige vereinbarte Ansprüche, die der RP-STS verstehen kann. Es ist jedoch unwahrscheinlich, dass diese Ansprüche in der RP-Anwendung direkt nützlich sind. Stattdessen wäre der RP-STS für die Transformation eines anderen vertrauenswürdigen Satzes von Ansprüchen verantwortlich, die in der RP-Domäne verstanden werden.
Abbildung 14 zeigt dieses Szenario. Wenn Joe versucht, ohne ein Token auf die RP zuzugreifen, meldet er sich am IP-STS in seiner eigenen Domäne (Domäne B) an. Die Anforderung fordert Ansprüche an, die die RP versteht, in diesem Fall RPClaim, damit der IP-STS weiß, dass er ein Token ausstellen muss, das der RP verwenden kann. Wenn der RP-STS dieses Token erhält, transformiert er die Ansprüche in RP-spezifische Ansprüche. Damit dieses Verbundszenario funktioniert, muss zwischen dem RP-STS und dem IP-STS eine Vertrauensstellung vorhanden sein, und sie müssen sich auf einen Satz von Ansprüchen einigen, den der IP-STS für seine Benutzer, denen Zugriff auf die RP gewährt wird, ausstellen sollte.
Abbildung 14 Anspruchstransformation in einem Verbundszenario

Zusammenfassung
Geneva Framework ist ein sehr willkommenes Dienstprogramm für diejenigen, die am Erstellen eines benutzerdefinierten STS interessiert sind und keine voll funktionsfähige STS-Plattform wie Geneva Server benötigen. Einen benutzerdefinierten STS zu erstellen, ist – auch mit Geneva Framework – keine triviale Angelegenheit, und die Empfehlung lautet immer, dass Sie wenn möglich einen voll funktionsfähigen STS verwenden, um das Risikopotenzial zu verringern.
Unabhängig von der Plattform bleibt der Kommunikationsfluss für aktive und passive STS-Implementierungen der gleiche. Das gilt auch für die Begriffe hinter der Anspruchstransformation. Einige zusätzliche Konzepte in Bezug auf STS-Implementierungen umfassen die Identitätsdelegierung und die Aufwärtsauthentifizierung. Sie finden Beispiele und Dokumentation zu diesen und anderen Konzepten im Geneva Framework SDK.

Michele Leroux Bustamante ist leitende Architektin bei IDesign Inc., Microsoft Regional Director für San Diego und Microsoft-MVP für verbundene Systeme. Ihr aktuelles Buch ist Learning WCF. Sie erreichen sie unter mlb@idesign.net, oder besuchen Sie idesign.net. Michele Leroux Bustamante führt einen Blog unter dasblonde.net.

Page view tracker