Exemplarische Vorgehensweise: Erstellen von benutzerdefinierten Client- und Dienstanmeldeinformationen
In diesem Thema wird gezeigt, wie benutzerdefinierte Client- und Dienstanmeldeinformationen implementiert und benutzerdefinierte Anmeldeinformationen aus Anwendungscode genutzt werden.
Erweiterbarkeitsklassen für Anmeldeinformationen
Die Klassen ClientCredentials und ServiceCredentials sind Haupteinstiegspunkte für die Windows Communication Foundation (WCF)-Sicherheitserweiterbarkeit. Diese Anmeldeinformationsklassen stellen die APIs bereit, die es dem Anmeldecode ermöglichen, Anmeldeinformationen einzurichten und Anmeldeinformationstypen in Sicherheitstoken zu konvertieren. (Sicherheitstoken werden verwendet, um innerhalb von SOAP-Nachrichten Anmeldeinformationen zu übertragen.) Die Verantwortungsbereiche dieser Klassen von Anmeldeinformationen können in zwei Bereiche geteilt werden:
Bereitstellung der APIs für Anwendungen zur Einrichtung von Anmeldeinformationen.
Funktion als Factory für SecurityTokenManager-Implementierungen.
Sowohl die ClientCredentials- als auch die ServiceCredentials-Klasse erben von der abstrakten SecurityCredentialsManager-Klasse, die den Vertrag für die Rückgabe des SecurityTokenManager definieren.
Weitere Informationen über zu den Klassen von Anmeldeinformationen und wie sie in die WCF-Sicherheitsarchitektur passen, finden Sie unter Sicherheitsarchitektur.
Die in WCF bereitgestellten Standardimplementierungen unterstützen die vom System bereitgestellten Anmeldeinformationstypen und erstellen einen Sicherheitstoken-Manager, der in der Lage ist, diese Anmeldeinformationstypen zu handhaben.
Gründe für eine Anpassung
Es gibt mehrere Gründe dafür, Client- oder Dienstanmeldeinformationsklassen anzupassen. Im Vordergrund steht die Notwendigkeit der Änderung des standardmäßigen WCF-Sicherheitsverhaltens in Bezug auf die Handhabung der vom System bereitgestellten Anmeldeinformationstypen, insbesondere aus folgenden Gründen:
Änderungen, die mit anderen Erweiterbarkeitspunkten nicht möglich sind.
Hinzufügen neuer Anmeldeinformationstypen.
Hinzufügen neuer benutzerdefinierter Typen von Sicherheitstoken.
Dieses Thema beschreibt, wie benutzerdefinierte Client- und Dienstanmeldeinformationen implementiert und im Anwendungscode genutzt werden.
Zuerst
Die Erstellung einer benutzerdefinierten Anmeldeinformationsklasse ist nur der erste Schritt, da der Grund für die Anpassung von Anmeldeinformationen in der Änderung des WCF-Verhaltens in Bezug auf die Bereitstellung von Anmeldeinformationen, die Serialisierung von Sicherheitstoken oder die Authentifizierung liegt. Andere Themen in diesem Abschnitt beschreiben, wie benutzerdefinierte Serialisierungsprogramme und Authentifizierer erstellt werden. In diesem Zusammenhang ist die Erstellung benutzerdefinierter Anmeldeinformationsklassen das erste Thema in der Reihe. Nachfolgende Aktionen (Erstellung von benutzerdefinierten Serialisierungsprogrammen und Authentifizierern) können nur durchgeführt werden, nachdem benutzerdefinierte Anmeldeinformationen erstellt wurden. Weitere Themen, die auf diesem Thema aufbauen:
Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenanbieters
Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenauthentifizierers
Prozeduren
So implementieren Sie benutzerdefinierte Clientanmeldeinformationen
Definieren Sie eine neue von der ClientCredentials-Klasse abgeleitete Klasse.
Optional. Fügen Sie Methoden oder Eigenschaften für neue Anmeldeinformationstypen hinzu. Wenn Sie keine neuen Anmeldeinformationstypen hinzufügen, können Sie diesen Schritt überspringen. Im folgenden Beispiel wird eine
CreditCardNumber
-Eigenschaft hinzugefügt.Überschreiben Sie die CreateSecurityTokenManager-Methode. Diese Methode wird automatisch von der WCF-Sicherheitsinfrastruktur aufgerufen, wenn die benutzerdefinierten Clientanmeldeinformationen verwendet werden. Diese Methode ist für die Erstellung und die Rückgabe einer Implementierungsinstanz der SecurityTokenManager-Klasse verantwortlich.
Hinweis: Wichtig: Beachten Sie, dass die CreateSecurityTokenManager-Methode überschrieben wird, um einen benutzerdefinierten Sicherheitstokenmanager zu erstellen. Der vom ClientCredentialsSecurityTokenManager abgeleitete Sicherheitstokenmanager muss einen benutzerdefinierten Sicherheitstokenanbieter zurückgeben, der vom SecurityTokenProvider abgeleitet wurde, um das eigentliche Sicherheitstoken zu erstellen. Befolgen Sie nicht diese Vorgehensweise zur Erstellung von Sicherheitstokens, funktioniert die Anwendung möglicherweise nicht korrekt, wenn ChannelFactory-Objekte zwischengespeichert werden, was das standardmäßige Verhalten von WCF-Clientproxys ist. Dies kann ggf. einen Angriff durch Rechteerweiterung zur Folge haben. Das benutzerdefinierte Anmeldedatenobjekt wird als Teil des ChannelFactory-Objekts zwischengespeichert. Der benutzerdefinierte SecurityTokenManager wird jedoch bei jedem Aufruf erstellt. So lange die Tokenerstellungslogik also im SecurityTokenManager platziert wird, wird die Sicherheitsbedrohung abgewehrt. Überschreiben Sie die CloneCore-Methode.
public class MyClientCredentials : ClientCredentials { string creditCardNumber; public MyClientCredentials() { // Perform client credentials initialization. } protected MyClientCredentials(MyClientCredentials other) : base(other) { // Clone fields defined in this class. this.creditCardNumber = other.creditCardNumber; } public string CreditCardNumber { get { return this.creditCardNumber; } set { if (value == null) { throw new ArgumentNullException("value"); } this.creditCardNumber = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { // Return your implementation of the SecurityTokenManager. return new MyClientCredentialsSecurityTokenManager(this); } protected override ClientCredentials CloneCore() { // Implement the cloning functionality. return new MyClientCredentials(this); } }
So implementieren Sie einen benutzerdefinierten Clientsicherheitstoken-Manager
Definieren Sie eine neue Klasse, die von ClientCredentialsSecurityTokenManager abgeleitet ist.
Optional. Überschreiben Sie die CreateSecurityTokenProvider-Methode, wenn eine benutzerdefinierte SecurityTokenProvider-Implementierung erstellt werden muss. Weitere Informationen über zu benutzerdefinierten Sicherheitstokenanbietern finden Sie unter Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenanbieters.
Optional. Überschreiben Sie die CreateSecurityTokenAuthenticator-Methode, wenn eine benutzerdefinierte SecurityTokenAuthenticator-Implementierung erstellt werden muss. Weitere Informationen über zu benutzerdefinierten Sicherheitstokenauthentifizierern finden Sie unter Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenauthentifizierers.
Optional. Überschreiben Sie die CreateSecurityTokenSerializer-Methode, wenn eine benutzerdefinierte SecurityTokenSerializer-Implementierung erstellt werden muss. Weitere Informationen über zu benutzerdefinierten Sicherheitstoken und Sicherheitstoken-Serialisierungsprogrammen finden Sie unter Vorgehensweise: Erstellen eines benutzerdefinierten Tokens.
internal class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager { MyClientCredentials credentials; public MyClientCredentialsSecurityTokenManager(MyClientCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider( SecurityTokenRequirement tokenRequirement) { // Return your implementation of the SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator( SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { // Return your implementation of the SecurityTokenAuthenticator, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { // Return your implementation of the SecurityTokenSerializer, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenSerializer(version); } }
So verwenden Sie benutzerdefinierte Clientanmeldeinformationen aus Anwendungscode
Erstellen Sie entweder eine Instanz des generierten Clients, die die Dienstschnittstelle darstellt, oder erstellen Sie eine Instanz der ChannelFactory, die auf den Dienst verweist, mit dem Sie kommunizieren möchten.
Entfernen Sie das vom System bereitgestellte Clientanmeldeinformationsverhalten aus der Behaviors-Sammlung, auf die von der Endpoint-Eigenschaft aus zugegriffen werden kann.
Erstellen Sie eine neue Instanz einer benutzerdefinierten Clientanmeldeinformationsklasse, und fügen Sie diese zur Behaviors-Sammlung hinzu, auf die über die Endpoint-Eigenschaft zugegriffen werden kann.
// Create a client with the client endpoint configuration. CalculatorClient client = new CalculatorClient(); // Remove the ClientCredentials behavior. client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>(); // Add a custom client credentials instance to the behaviors collection. client.ChannelFactory.Endpoint.Behaviors.Add(new MyClientCredentials());
Die zuvor genannte Prozedur zeigt, wie Clientanmeldeinformationen aus dem Anwendungscode genutzt werden können. WCF-Anmeldeinformationen können darüber hinaus mithilfe der Anwendungskonfigurationsdatei konfiguriert werden. Die Nutzung der Anwendungskonfiguration ist in vielen Fällen einer harten Codierung vorzuziehen, da hier eine Änderung der Anwendungsparameter ermöglicht wird, ohne dass ein Ändern der Quelle oder eine Neukompilierung und Neubereitstellung erforderlich sind.
Die nächste Prozedur beschreibt, wie eine Unterstützung für die Konfiguration von benutzerdefinierten Anmeldeinformationen erstellt wird.
Erstellen eines Konfigurationshandlers für benutzerdefinierte Clientanmeldeinformationen
Definieren Sie eine neue Klasse, die von ClientCredentialsElement abgeleitet ist.
Optional. Fügen Sie Eigenschaften für alle zusätzlichen Konfigurationsparameter hinzu, die Sie durch Anwendungskonfiguration verfügbar machen möchten. Im unten angegebenen Beispiel wird eine Eigenschaft mit dem Namen
CreditCardNumber
hinzugefügt.Überschreiben Sie die BehaviorType-Eigenschaft, um den Typ der benutzerdefinierten Clienanmeldeinformationsklasse zurückzugeben, der mithilfe des Konfigurationselements erstellt wurde.
Überschreiben der CreateBehavior-Methode. Die Methode ist basierend auf den von der Konfigurationsdatei geladenen Einstellungen für die Erstellung und Rückgabe einer Instanz der benutzerdefinierten Anmeldeinformationsklasse verantwortlich. Rufen Sie die grundlegende ApplyConfiguration-Methode von dieser Methode auf, um die vom System bereitgestellten Anmeldeinformationseinstellungen abzurufen, die in Ihre benutzerdefinierte Clientanmeldeinformationsinstanz geladen sind.
Optional. Wenn Sie in Schritt 2 zusätzliche Eigenschaften hinzugefügt haben, müssen Sie die Properties-Eigenschaft zum Registrieren Ihrer zusätzlichen Konfigurationseinstellungen überschreiben, damit der Konfigurationsframework diese erkennt. Kombinieren Sie Ihre Eigenschaften mit den grundlegenden Klasseneigenschaften, um zu ermöglichen, dass die vom System bereitgestellten Einstellungen über das Konfigurationselement dieser benutzerdefinierten Clientanmeldeinformationen konfiguriert werden können.
public class MyClientCredentialsConfigHandler : ClientCredentialsElement { ConfigurationPropertyCollection properties; public override Type BehaviorType { get { return typeof(MyClientCredentials); } } public string CreditCardNumber { get { return (string)base["creditCardNumber"]; } set { if (String.IsNullOrEmpty(value)) { value = String.Empty; } base["creditCardNumber"] = value; } } protected override ConfigurationPropertyCollection Properties { get { if (this.properties == null) { ConfigurationPropertyCollection properties = base.Properties; properties.Add(new ConfigurationProperty( "creditCardNumber", typeof(System.String), string.Empty, null, new StringValidator(0, 32, null), ConfigurationPropertyOptions.None)); this.properties = properties; } return this.properties; } } protected override object CreateBehavior() { MyClientCredentials creds = new MyClientCredentials(); creds.CreditCardNumber = CreditCardNumber; base.ApplyConfiguration(creds); return creds; } }
Sobald Sie die Konfigurationshandlerklasse besitzen, kann diese in das WCF-Konfigurationsframework integriert werden. Dies ermöglicht die Verwendung benutzerdefinierter Clientanmeldeinformationen in den Clientendpunktverhaltens-Elementen, wie in der nächsten Prozedur gezeigt wird.
Registrieren und Verwenden eines benutzerdefinierten Clientanmeldeinformationen-Konfigurationshandlers in der Anwendungskonfiguration
Fügen Sie ein <extensions>-Element und ein <behaviorExtensions>-Element in die Konfigurationsdatei ein.
Fügen Sie ein <add>-Element zum <behaviorExtensions>-Element hinzu, und setzen Sie das name-Attribut auf einen angemessenen Wert fest.
Legen Sie das type-Attribut auf den vollqualifizierten Typnamen fest. Binden Sie ebenfalls den Assemblynamen und andere Assemblyattribute ein.
<system.serviceModel> <extensions> <behaviorExtensions> <add name="myClientCredentials" type="Microsoft.ServiceModel.Samples.MyClientCredentialsConfigHandler, CustomCredentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </behaviorExtensions> </extensions> <system.serviceModel>
Nach der Registrierung Ihres Konfigurationshandlers kann das benutzerdefinierte Anmeldeinformationselement innerhalb derselben Konfigurationsdatei anstelle des vom System bereitgestellten <clientCredentials>-Elements verwendet werden. Sie können sowohl die vom System bereitgestellten Eigenschaften als auch neue Eigenschaften verwenden, die Sie in Ihre Konfigurationshandlerimplementierung eingefügt haben. Im folgenden Beispiel wird der Wert einer benutzerdefinierten Eigenschaft mithilfe des creditCardNumber-Attributs eingerichtet.
<behaviors> <endpointBehaviors> <behavior name="myClientCredentialsBehavior"> <myClientCredentials creditCardNumber="123-123-123"/> </behavior> </endpointBehaviors> </behaviors>
So implementieren Sie benutzerdefinierte Dienstanmeldeinformationen
Definieren Sie eine neue Klasse, die von ServiceCredentials abgeleitet ist.
Optional. Fügen Sie neue Eigenschaften hinzu, um APIs für neue Werte für die Anmeldeinformationen bereitzustellen, die hinzugefügt werden. Wenn Sie keine neuen Anmeldeinformationswerte hinzufügen, können Sie diesen Schritt überspringen. Im folgenden Beispiel wird die
AdditionalCertificate
-Eigenschaft hinzugefügt.Überschreiben der CreateSecurityTokenManager-Methode. Diese Methode wird automatisch von der WCF-Infrastruktur aufgerufen, wenn die benutzerdefinierten Clientanmeldeinformationen verwendet werden. Die Methode ist für die Erstellung und die Rückgabe einer Implementierungsinstanz der SecurityTokenManager-Klasse verantwortlich (wie in der nächsten Prozedur beschrieben).
Optional. Überschreiben Sie die CloneCore-Methode. Dies ist nur erforderlich, wenn neue Eigenschaften oder interne Felder zur benutzerdefinierten Clientanmeldeinformations-Implementierung hinzugefügt werden.
public class MyServiceCredentials : ServiceCredentials { X509Certificate2 additionalCertificate; public MyServiceCredentials() { } protected MyServiceCredentials(MyServiceCredentials other) : base(other) { this.additionalCertificate = other.additionalCertificate; } public X509Certificate2 AdditionalCertificate { get { return this.additionalCertificate; } set { if (value == null) { throw new ArgumentNullException("value"); } this.additionalCertificate = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { return base.CreateSecurityTokenManager(); } protected override ServiceCredentials CloneCore() { return new MyServiceCredentials(this); } }
So implementieren Sie einen benutzerdefinierten Dienstsicherheitstoken-Manager
Definieren Sie eine neue Klasse, die von der ServiceCredentialsSecurityTokenManager-Klasse abgeleitet ist.
Optional. Überschreiben Sie die CreateSecurityTokenProvider-Methode, wenn eine benutzerdefinierte SecurityTokenProvider-Implementierung erstellt werden muss. Weitere Informationen über zu benutzerdefinierten Sicherheitstokenanbietern finden Sie unter Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenanbieters.
Optional. Überschreiben Sie die CreateSecurityTokenAuthenticator-Methode, wenn eine benutzerdefinierte SecurityTokenAuthenticator-Implementierung erstellt werden muss. Weitere Informationen über zu benutzerdefinierten Sicherheitstokenauthentifizierern finden Sie im Thema Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenauthentifizierers.
Optional. Überschreiben Sie die CreateSecurityTokenSerializer-Methode, wenn eine benutzerdefinierte SecurityTokenSerializer-Implementierung erstellt werden muss. Weitere Informationen über zu benutzerdefinierten Sicherheitstoken und Sicherheitstoken-Serialisierungsprogrammen finden Sie unter Vorgehensweise: Erstellen eines benutzerdefinierten Tokens.
internal class MyServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager { MyServiceCredentials credentials; public MyServiceCredentialsSecurityTokenManager(MyServiceCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenSerializer(version); } }
So verwenden Sie benutzerdefinierte Dienstanmeldeinformationen aus Anwendungscode
Erstellen Sie eine ServiceHost-Instanz.
Entfernen Sie das vom System bereitgestellte Dienstanmeldeinformationsverhalten aus der Behaviors-Sammlung.
Erstellen Sie eine neue Instanz der benutzerdefinierten Dienstanmeldeinformationsklasse, und fügen Sie diese der Behaviors-Sammlung hinzu.
// Create a service host with a service type. ServiceHost serviceHost = new ServiceHost(typeof(Service)); // Remove the default ServiceCredentials behavior. serviceHost.Description.Behaviors.Remove<ServiceCredentials>(); // Add a custom service credentials instance to the collection. serviceHost.Description.Behaviors.Add(new MyServiceCredentials());
Fügen Sie anhand der in den Prozeduren "To create a configuration handler for custom client credentials" und "To register and use a custom client credentials configuration handler in the application configuration" bereits beschriebenen Schritte die Unterstützung für Konfiguration hinzu. Der einzige Unterschied liegt in der Verwendung der ServiceCredentialsElement-Klasse anstelle der ClientCredentialsElement-Klasse als Basisklasse für den Konfigurationshandler. Das benutzerdefinierte Dienstanmeldeinformationselement kann immer verwendet werden, wenn das vom System bereitgestellte <serviceCredentials>
-Element genutzt wird.
Siehe auch
Aufgaben
Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenanbieters
Verweis
ClientCredentials
ServiceCredentials
SecurityCredentialsManager
SecurityTokenManager
ClientCredentialsElement
ServiceCredentialsElement
Konzepte
Vorgehensweise: Erstellen eines benutzerdefinierten Sicherheitstokenauthentifizierers
Vorgehensweise: Erstellen eines benutzerdefinierten Tokens