Benutzerdefiniertes TokenCustom Token

Dieses Beispiel veranschaulicht, wie einer benutzerdefinierten tokenimplementierung in eine Windows Communication Foundation (WCF)-Anwendung.This sample demonstrates how to add a custom token implementation into a Windows Communication Foundation (WCF) application. Im Beispiel wird ein CreditCardToken verwendet, um Informationen über Clientkreditkarten sicher an den Dienst zu übergeben.The example uses a CreditCardToken to securely pass information about client credit cards to the service. Das Token wird an den WS-Sicherheits-Nachrichtenkopf übergeben und zusammen mit Nachrichtentext und anderen Nachrichtenköpfen mithilfe des symmetrischen Sicherheitsbindungselements signiert und verschlüsselt.The token is passed in the WS-Security message header and is signed and encrypted using the symmetric security binding element along with message body and other message headers. Dies ist in Fällen nützlich, in denen die integrierten Token nicht ausreichen.This is useful in cases where the built-in tokens are not sufficient. In diesem Beispiel wird veranschaulicht, wie anstelle eines der integrierten Token ein benutzerdefiniertes Sicherheitstoken für einen Dienst bereitgestellt werden kann.This sample demonstrates how to provide a custom security token to a service instead of using one of the built-in tokens. Der Dienst implementiert einen Vertrag, der ein Anforderungs-Antwort-Kommunikationsmuster definiert.The service implements a contract that defines a request-reply communication pattern.

Hinweis

Die Setupprozedur und die Buildanweisungen für dieses Beispiel befinden sich am Ende dieses Themas.The setup procedure and build instructions for this sample are located at the end of this topic.

Kurz gesagt, veranschaulicht dieses Beispiel folgende Punkte:To summarize, this sample demonstrates the following:

  • Wie ein Client ein benutzerdefiniertes Sicherheitstoken an einen Dienst übergeben kann.How a client can pass a custom security token to a service.

  • Wie der Dienst ein benutzerdefiniertes Sicherheitstoken verwenden und überprüfen kann.How the service can consume and validate a custom security token.

  • Wie der WCF-Dienstcode die Informationen zu empfangenen Sicherheitstoken, die das benutzerdefinierte Sicherheitstoken einschließlich abrufen kann.How the WCF service code can obtain the information about received security tokens including the custom security token.

  • Wie das X.509-Zertifikat des Servers dazu verwendet wird, den zur Nachrichtenverschlüsselung und für die Signatur verwendeten symmetrischen Schlüssel zu schützen.How the server's X.509 certificate is used to protect the symmetric key used for message encryption and signature.

Sicherheitsauthentifizierung mithilfe eines benutzerdefinierten SicherheitstokensClient Authentication Using a Custom Security Token

Der Dienst macht einen einzelnen Endpunkt verfügbar, der programmgesteuert mithilfe der BindingHelper-Klasse und der EchoServiceHost-Klasse erstellt wird.The service exposes a single endpoint that is programmatically created using BindingHelper and EchoServiceHost classes. Der Endpunkt besteht aus einer Adresse, einer Bindung und einem Vertrag.The endpoint consists of an address, a binding, and a contract. Die Bindung wird mit einer benutzerdefinierten Bindung unter Verwendung von SymmetricSecurityBindingElement und HttpTransportBindingElement konfiguriert.The binding is configured with a custom binding using SymmetricSecurityBindingElement and HttpTransportBindingElement. In diesem Beispiel wird SymmetricSecurityBindingElement so eingestellt, dass es ein X.509-Zertifikat für den Dienst verwendet, um den symmetrischen Schlüssel während der Übertragung zu schützen und um in einem WS-Sicherheits-Nachrichtenkopf ein benutzerdefiniertes CreditCardToken als signiertes und verschlüsseltes Sicherheitstoken zu übergeben.This sample sets the SymmetricSecurityBindingElement to use a service's X.509 certificate to protect the symmetric key during transmission and to pass a custom CreditCardToken in a WS-Security message header as a signed and encrypted security token. Das Verhalten legt die Dienstanmeldeinformationen fest, die zur Clientauthentifizierung verwendet werden sollen, sowie Informationen über das X.509-Zertifikat des Diensts.The behavior specifies the service credentials that are to be used for client authentication and also information about the service X.509 certificate.

public static class BindingHelper  
{  
    public static Binding CreateCreditCardBinding()  
    {  
        HttpTransportBindingElement httpTransport = new HttpTransportBindingElement();  

        // The message security binding element will be configured to require a credit card.  
        // The token that is encrypted with the service's certificate.   
        SymmetricSecurityBindingElement messageSecurity = new SymmetricSecurityBindingElement();  
        messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CreditCardTokenParameters());  
        X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();  
        x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never;  
        messageSecurity.ProtectionTokenParameters = x509ProtectionParameters;  
        return new CustomBinding(messageSecurity, httpTransport);  
    }  
}  

Um ein Kreditkartentoken in der Nachricht zu nutzen, werden im Beispiel benutzerdefinierte Dienstanmeldeinformationen verwendet, um diese Funktion anzugeben.To consume a credit card token in the message, the sample uses custom service credentials to provide this functionality. Die Dienstanmeldeinformationsklasse befindet sich in der Klasse CreditCardServiceCredentials und wird zu den Verhaltensauflistungen des Diensthosts in der EchoServiceHost.InitializeRuntime-Methode hinzugefügt.The service credentials class is located in the CreditCardServiceCredentials class and is added to the behaviors collections of the service host in the EchoServiceHost.InitializeRuntime method.

class EchoServiceHost : ServiceHost  
{  
    string creditCardFile;  

    public EchoServiceHost(parameters Uri[] addresses)  
        : base(typeof(EchoService), addresses)  
    {  
        creditCardFile = ConfigurationManager.AppSettings["creditCardFile"];  
        if (string.IsNullOrEmpty(creditCardFile))  
        {  
            throw new ConfigurationErrorsException("creditCardFile not specified in service config");  
        }  

        creditCardFile = String.Format("{0}\\{1}", System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, creditCardFile);  

    }  

    override protected void InitializeRuntime()  
    {  
        // Create a credit card service credentials and add it to the behaviors.  
        CreditCardServiceCredentials serviceCredentials = new CreditCardServiceCredentials(this.creditCardFile);  
        serviceCredentials.ServiceCertificate.SetCertificate("CN=localhost", StoreLocation.LocalMachine, StoreName.My);  
        this.Description.Behaviors.Remove((typeof(ServiceCredentials)));  
        this.Description.Behaviors.Add(serviceCredentials);  

        // Register a credit card binding for the endpoint.  
        Binding creditCardBinding = BindingHelper.CreateCreditCardBinding();  
        this.AddServiceEndpoint(typeof(IEchoService), creditCardBinding, string.Empty);  

        base.InitializeRuntime();  
    }  
}  

Der Clientendpunkt wird auf ähnliche Weise wie der Dienstendpunkt konfiguriert.The client endpoint is configured in a similar manner as the service endpoint. Der Client verwendet die gleiche BindingHelper-Klasse, um eine Bindung zu erstellen.The client uses the same BindingHelper class to create a binding. Der Rest des Setups befindet sich in der Client-Klasse.The rest of the setup is located in the Client class. Der Client legt außerdem Informationen, die im CreditCardToken enthalten sein sollen, sowie Informationen zum X.509-Zertifikat des Diensts im Setupcode fest, indem eine CreditCardClientCredentials-Instanz mit den entsprechenden Daten zur Auflistung der Clientendpunktverhaltensweisen hinzugefügt wird.The client also sets information to be contained in the CreditCardToken and information about the service X.509 certificate in the setup code by adding a CreditCardClientCredentials instance with the proper data to the client endpoint behaviors collection. Im Beispiel wird das X.509-Zertifikat mit dem Antragstellernamen CN=localhost als Dienstzertifikat verwendet.The sample uses X.509 certificate with subject name set to CN=localhost as the service certificate.

Binding creditCardBinding = BindingHelper.CreateCreditCardBinding();  
EndpointAddress serviceAddress = new EndpointAddress("http://localhost/servicemodelsamples/service.svc");  

// Create a client with given client endpoint configuration  
channelFactory =   
new ChannelFactory<IEchoService>(creditCardBinding, serviceAddress);  

// configure the credit card credentials on the channel factory   
CreditCardClientCredentials credentials =   
      new CreditCardClientCredentials(  
      new CreditCardInfo(creditCardNumber, issuer, expirationTime));  
// configure the service certificate on the credentials  
credentials.ServiceCertificate.SetDefaultCertificate(  
      "CN=localhost", StoreLocation.LocalMachine, StoreName.My);  

// replace ClientCredentials with CreditCardClientCredentials  
channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));  
channelFactory.Endpoint.Behaviors.Add(credentials);  

client = channelFactory.CreateChannel();  

Console.WriteLine("Echo service returned: {0}", client.Echo());  

((IChannel)client).Close();  
channelFactory.Close();  

Implementierung des benutzerdefinierten SicherheitstokensCustom Security Token Implementation

Um ein benutzerdefiniertes Sicherheitstoken in WCF zu aktivieren, erstellen Sie eine objektdarstellung des benutzerdefinierten Sicherheitstokens.To enable a custom security token in WCF, create an object representation of the custom security token. Das Beispiel enthält diese Darstellung in der CreditCardToken-Klasse.The sample has this representation in the CreditCardToken class. Die Objektdarstellung dient zur Aufnahme aller relevanten Informationen zu Sicherheitstoken und zur Bereitstellung einer Liste der im Sicherheitstoken enthaltenen Sicherheitsschlüssel.The object representation is responsible for holding all relevant security token information and to provide a list of security keys contained in the security token. In diesem Fall enthält das Sicherheitstoken der Kreditkarte keinen Sicherheitsschlüssel.In this case, the credit card security token does not contain any security key.

Im nächsten Abschnitt wird beschrieben, was erfolgt, damit ein benutzerdefiniertes Token über die Verbindung übertragen werden können und von einem WCF-Endpunkt genutzt werden muss.The next section describes what must be done to enable a custom token to be transmitted over the wire and consumed by a WCF endpoint.

class CreditCardToken : SecurityToken  
{  
    CreditCardInfo cardInfo;  
    DateTime effectiveTime = DateTime.UtcNow;  
    string id;  
    ReadOnlyCollection<SecurityKey> securityKeys;  

    public CreditCardToken(CreditCardInfo cardInfo) : this(cardInfo, Guid.NewGuid().ToString()) { }  

    public CreditCardToken(CreditCardInfo cardInfo, string id)  
    {  
        if (cardInfo == null)  
            throw new ArgumentNullException("cardInfo");  

        if (id == null)  
            throw new ArgumentNullException("id");  

        this.cardInfo = cardInfo;  
        this.id = id;  

        // The credit card token is not capable of any cryptography.  
        this.securityKeys = new ReadOnlyCollection<SecurityKey>(new List<SecurityKey>());  
    }  

    public CreditCardInfo CardInfo { get { return this.cardInfo; } }  

    public override ReadOnlyCollection<SecurityKey> SecurityKeys { get { return this.securityKeys; } }  

    public override DateTime ValidFrom { get { return this.effectiveTime; } }  
    public override DateTime ValidTo { get { return this.cardInfo.ExpirationDate; } }  
    public override string Id { get { return this.id; } }  
}  

Abrufen des benutzerdefinierte Kreditkartentokens aus der Nachricht und Einbinden des Tokens in die NachrichtGetting the Custom Credit Card Token to and from the Message

Sicherheitstoken-Serialisierungsprogramme in WCF sind dafür erstellen eine objektdarstellung von Sicherheitstoken aus der XML-Code in der Nachricht und zum Erstellen einer XML-Formulars dieser Sicherheitstokens verantwortlich.Security token serializers in WCF are responsible for creating an object representation of security tokens from the XML in the message and creating a XML form of the security tokens. Außerdem sind sie für andere Funktionen zuständig, wie beispielsweise das Lesen und Schreiben von Schlüsselbezeichnern, die auf Sicherheitstoken verweisen. In diesem Beispiel werden jedoch nur die Funktionen behandelt, die sich auf Sicherheitstoken beziehen.They are also responsible for other functionality such as reading and writing key identifiers pointing to security tokens, but this example uses only security token-related functionality. Um ein benutzerdefiniertes Token zu aktivieren, müssen Sie ein eigenes Sicherheitstoken-Serialisierungsprogramm implementieren.To enable a custom token you must implement your own security token serializer. In diesem Beispiel wird zu diesem Zweck die CreditCardSecurityTokenSerializer-Klasse verwendet.This sample uses the CreditCardSecurityTokenSerializer class for this purpose.

Im Dienst liest das benutzerdefinierte Serialisierungsprogramm die XML-Form des benutzerdefinierten Tokens und erstellt daraus die Objektdarstellung des benutzerdefinierten Tokens.On the service, the custom serializer reads the XML form of the custom token and creates the custom token object representation from it.

Auf dem Client schreibt die CreditCardSecurityTokenSerializer-Klasse die in der Objektdarstellung des benutzerdefinierten Tokens enthaltenen Informationen in den XML-Writer.On the client, the CreditCardSecurityTokenSerializer class writes the information contained in the security token object representation into the XML writer.

public class CreditCardSecurityTokenSerializer : WSSecurityTokenSerializer  
{  
    public CreditCardSecurityTokenSerializer(SecurityTokenVersion version) : base() { }  

    protected override bool CanReadTokenCore(XmlReader reader)  
    {  
        XmlDictionaryReader localReader = XmlDictionaryReader.CreateDictionaryReader(reader);  

        if (reader == null) throw new ArgumentNullException("reader");  

        if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace))  
            return true;  

        return base.CanReadTokenCore(reader);  
    }  

    protected override SecurityToken ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)  
    {  
        if (reader == null) throw new ArgumentNullException("reader");  

        if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace))  
        {  
            string id = reader.GetAttribute(Constants.Id, Constants.WsUtilityNamespace);  

            reader.ReadStartElement();  

            // Read the credit card number.  
            string creditCardNumber = reader.ReadElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace);  

            // Read the expiration date.  
            string expirationTimeString = reader.ReadElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace);  
            DateTime expirationTime = XmlConvert.ToDateTime(expirationTimeString, XmlDateTimeSerializationMode.Utc);  

            // Read the issuer of the credit card.  
            string creditCardIssuer = reader.ReadElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace);  
            reader.ReadEndElement();  

            CreditCardInfo cardInfo = new CreditCardInfo(creditCardNumber, creditCardIssuer, expirationTime);  

            return new CreditCardToken(cardInfo, id);  
        }  
        else  
        {  
            return WSSecurityTokenSerializer.DefaultInstance.ReadToken(reader, tokenResolver);  
        }  
    }  

    protected override bool CanWriteTokenCore(SecurityToken token)  
    {  
        if (token is CreditCardToken)  
            return true;  

        else  
            return base.CanWriteTokenCore(token);  
    }  

    protected override void WriteTokenCore(XmlWriter writer, SecurityToken token)  
    {  
        if (writer == null) { throw new ArgumentNullException("writer"); }  
        if (token == null) { throw new ArgumentNullException("token"); }  

        CreditCardToken c = token as CreditCardToken;  
        if (c != null)  
        {  
            writer.WriteStartElement(Constants.CreditCardTokenPrefix, Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace);  
            writer.WriteAttributeString(Constants.WsUtilityPrefix, Constants.Id, Constants.WsUtilityNamespace, token.Id);  
            writer.WriteElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardNumber);  
            writer.WriteElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace, XmlConvert.ToString(c.CardInfo.ExpirationDate, XmlDateTimeSerializationMode.Utc));  
            writer.WriteElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardIssuer);  
            writer.WriteEndElement();  
            writer.Flush();  
        }  
        else  
        {  
            base.WriteTokenCore(writer, token);  
        }  
    }  
}  

So werden Tokenanbieter- und Tokenauthentifiziererklassen erstelltHow Token Provider and Token Authenticator Classes are Created

Client- und Dienstanmeldeinformationen sind für die Bereitstellung der Instanz des Sicherheitstoken-Managers zuständig.Client and service credentials are responsible for providing the security token manager instance. Die Instanz des Sicherheitstoken-Managers dient zum Abrufen von Tokenanbietern, Tokenauthentifizierern und Serialisierungsprogrammen für das Token.The security token manager instance is used to get token providers, token authenticators and token serializers.

Der Tokenanbieter erstellt eine Objektdarstellung des Tokens basierend auf Daten in den Client- oder Dienstanmeldeinformationen.The token provider creates an object representation of the token based on the information contained in the client or service credentials. Anschließend wird die Objektdarstellung des Tokens mithilfe des Token-Serialisierungsprogramms (im vorigen Abschnitt erörtert) in die Nachricht geschrieben.The token object representation is then written to the message using the token serializer (discussed in the previous section).

Der Tokenauthentifizierer überprüft Token, die in der Nachricht ankommen.The token authenticator validates tokens that arrive in the message. Die Objektdarstellung der eingehenden Token wird vom Token-Serialisierungsprogramm erstellt.The incoming token object representation is created by the token serializer. Diese Objektdarstellung wird dann zur Validierung an den Tokenauthentifizierer übergeben.This object representation is then passed to the token authenticator for validation. Nach der erfolgreichen Validierung des Tokens gibt der Tokenauthentifizierer eine Auflistung der IAuthorizationPolicy-Objekte zurück, die die im Token enthaltenen Informationen darstellen.After the token is successfully validated, the token authenticator returns a collection of IAuthorizationPolicy objects that represent the information contained in the token. Diese Informationen werden später während der Nachrichtenverarbeitung verwendet, um Autorisierungsentscheidungen durchzuführen und Ansprüche für die Anwendung bereitzustellen.This information is used later during the message processing to perform authorization decisions and to provide claims for the application. In diesem Beispiel verwendet der Tokenauthentifizierer für Kreditkarten CreditCardTokenAuthorizationPolicy für diesen Zweck.In this example, the credit card token authenticator uses CreditCardTokenAuthorizationPolicy for this purpose.

Das Token-Serialisierungsprogramm ist zuständig für das Abrufen der Objektdarstellung des Tokens von der Verbindung und zum Einbinden der Darstellung in die Verbindung.The token serializer is responsible for getting the object representation of the token to and from the wire. Dies wird im vorherigen Abschnitt erläutert.This is discussed in the previous section.

In diesem Beispiel wird ein Tokenanbieter nur für den Client und ein Tokenauthentifizierer nur für den Dienst verwendet, da ein Kreditkartentoken nur in der Richtung vom Client zum Dienst übertragen werden soll.In this sample, we use a token provider only on the client and a token authenticator only on the service, because we want to transmit a credit card token only in the client-to-service direction.

Die Funktionalität auf dem Client befindet sich in den Klassen CreditCardClientCrendentials, CreditCardClientCredentialsSecurityTokenManager und CreditCardTokenProvider.The functionality on the client is located in the CreditCardClientCrendentials, CreditCardClientCredentialsSecurityTokenManager and CreditCardTokenProvider classes.

Beim Dienst befindet sich die Funktionalität in den Klassen CreditCardServiceCredentials, CreditCardServiceCredentialsSecurityTokenManager, CreditCardTokenAuthenticator und CreditCardTokenAuthorizationPolicy.On the service, the functionality resides in the CreditCardServiceCredentials, CreditCardServiceCredentialsSecurityTokenManager, CreditCardTokenAuthenticator and CreditCardTokenAuthorizationPolicy classes.

    public class CreditCardClientCredentials : ClientCredentials  
    {  
        CreditCardInfo creditCardInfo;  

        public CreditCardClientCredentials(CreditCardInfo creditCardInfo)  
            : base()  
        {  
            if (creditCardInfo == null)  
                throw new ArgumentNullException("creditCardInfo");  

            this.creditCardInfo = creditCardInfo;  
        }  

        public CreditCardInfo CreditCardInfo  
        {  
            get { return this.creditCardInfo; }  
        }  

        protected override ClientCredentials CloneCore()  
        {  
            return new CreditCardClientCredentials(this.creditCardInfo);  
        }  

        public override SecurityTokenManager CreateSecurityTokenManager()  
        {  
            return new CreditCardClientCredentialsSecurityTokenManager(this);  
        }  
    }  

public class CreditCardClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager  
    {  
        CreditCardClientCredentials creditCardClientCredentials;  

        public CreditCardClientCredentialsSecurityTokenManager(CreditCardClientCredentials creditCardClientCredentials)  
            : base (creditCardClientCredentials)  
        {  
            this.creditCardClientCredentials = creditCardClientCredentials;  
        }  

        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)  
        {  
            // handle this token for Custom  
            if (tokenRequirement.TokenType == Constants.CreditCardTokenType)  
                return new CreditCardTokenProvider(this.creditCardClientCredentials.CreditCardInfo);  
            // return server cert  
            else if (tokenRequirement is InitiatorServiceModelSecurityTokenRequirement)  
            {  
                if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)  
                {  
                    return new X509SecurityTokenProvider(creditCardClientCredentials.ServiceCertificate.DefaultCertificate);  
                }  
            }  

            return base.CreateSecurityTokenProvider(tokenRequirement);  
        }  

        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)  
        {  

            return new CreditCardSecurityTokenSerializer(version);  
        }  

    }  

    class CreditCardTokenProvider : SecurityTokenProvider  
    {  
        CreditCardInfo creditCardInfo;  

        public CreditCardTokenProvider(CreditCardInfo creditCardInfo) : base()  
        {  
            if (creditCardInfo == null)  
            {  
                throw new ArgumentNullException("creditCardInfo");  
            }  
            this.creditCardInfo = creditCardInfo;  
        }  

        protected override SecurityToken GetTokenCore(TimeSpan timeout)  
        {  
            SecurityToken result = new CreditCardToken(this.creditCardInfo);  
            return result;  
        }  
    }  

public class CreditCardServiceCredentials : ServiceCredentials  
    {  
        string creditCardFile;  

        public CreditCardServiceCredentials(string creditCardFile)  
            : base()  
        {   
            if (creditCardFile == null)  
                throw new ArgumentNullException("creditCardFile");  

            this.creditCardFile = creditCardFile;  
        }  

        public string CreditCardDataFile  
        {  
            get { return this.creditCardFile; }  
        }  

        protected override ServiceCredentials CloneCore()  
        {  
            return new CreditCardServiceCredentials(this.creditCardFile);  
        }  

        public override SecurityTokenManager CreateSecurityTokenManager()  
        {  
            return new CreditCardServiceCredentialsSecurityTokenManager(this);  
        }  
    }  

public class CreditCardServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager  
{  
        CreditCardServiceCredentials creditCardServiceCredentials;  

        public CreditCardServiceCredentialsSecurityTokenManager(CreditCardServiceCredentials creditCardServiceCredentials)  
            : base(creditCardServiceCredentials)  
        {  
            this.creditCardServiceCredentials = creditCardServiceCredentials;  
        }  

        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)  
        {  
            if (tokenRequirement.TokenType == Constants.CreditCardTokenType)  
            {  
                outOfBandTokenResolver = null;  
                return new CreditCardTokenAuthenticator(creditCardServiceCredentials.CreditCardDataFile);  
            }  

            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);  
        }  

        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)  
        {  
            return new CreditCardSecurityTokenSerializer(version);  
        }  
    }  

    class CreditCardTokenAuthenticator : SecurityTokenAuthenticator  
    {  
        string creditCardsFile;  
        public CreditCardTokenAuthenticator(string creditCardsFile)  
        {  
            this.creditCardsFile = creditCardsFile;  
        }  

        protected override bool CanValidateTokenCore(SecurityToken token)  
        {  
            return (token is CreditCardToken);  
        }  

        protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)  
        {  
            CreditCardToken creditCardToken = token as CreditCardToken;  

            if (creditCardToken.CardInfo.ExpirationDate < DateTime.UtcNow)  
                throw new SecurityTokenValidationException("The credit card has expired");  
            if (!IsCardNumberAndExpirationValid(creditCardToken.CardInfo))  
                throw new SecurityTokenValidationException("Unknown or invalid credit card");  

            // the credit card token has only 1 claim - the card number. The issuer for the claim is the  
            // credit card issuer  

            DefaultClaimSet cardIssuerClaimSet = new DefaultClaimSet(new Claim(ClaimTypes.Name, creditCardToken.CardInfo.CardIssuer, Rights.PossessProperty));  
            DefaultClaimSet cardClaimSet = new DefaultClaimSet(cardIssuerClaimSet, new Claim(Constants.CreditCardNumberClaim, creditCardToken.CardInfo.CardNumber, Rights.PossessProperty));  
            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);  
            policies.Add(new CreditCardTokenAuthorizationPolicy(cardClaimSet));  
            return policies.AsReadOnly();  
        }  

        /// <summary>  
        /// Helper method to check if a given credit card entry is present in the User DB  
        /// </summary>  
        private bool IsCardNumberAndExpirationValid(CreditCardInfo cardInfo)  
        {  
            try  
            {  
                using (StreamReader myStreamReader = new StreamReader(this.creditCardsFile))  
                {  
                    string line = "";  
                    while ((line = myStreamReader.ReadLine()) != null)  
                    {  
                        string[] splitEntry = line.Split('#');  
                        if (splitEntry[0] == cardInfo.CardNumber)  
                        {  
                            string expirationDateString = splitEntry[1].Trim();  
                            DateTime expirationDateOnFile = DateTime.Parse(expirationDateString, System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.AdjustToUniversal);  
                            if (cardInfo.ExpirationDate == expirationDateOnFile)  
                            {  
                                string issuer = splitEntry[2];  
                                return issuer.Equals(cardInfo.CardIssuer, StringComparison.InvariantCultureIgnoreCase);  
                            }  
                            else  
                            {  
                                return false;  
                            }  
                        }  
                    }  
                    return false;  
                }  
            }  
            catch (Exception e)  
            {  
                throw new Exception("BookStoreService: Error while retrieving credit card information from User DB " + e.ToString());  
            }  
        }  
    }  

    public class CreditCardTokenAuthorizationPolicy : IAuthorizationPolicy  
    {  
        string id;  
        ClaimSet issuer;  
        IEnumerable<ClaimSet> issuedClaimSets;  

        public CreditCardTokenAuthorizationPolicy(ClaimSet issuedClaims)  
        {  
            if (issuedClaims == null)  
                throw new ArgumentNullException("issuedClaims");  
            this.issuer = issuedClaims.Issuer;  
            this.issuedClaimSets = new ClaimSet[] { issuedClaims };  
            this.id = Guid.NewGuid().ToString();  
        }  

        public ClaimSet Issuer { get { return this.issuer; } }  

        public string Id { get { return this.id; } }  

        public bool Evaluate(EvaluationContext context, ref object state)  
        {  
            foreach (ClaimSet issuance in this.issuedClaimSets)  
            {  
                context.AddClaimSet(this, issuance);  
            }  

            return true;  
        }  
    }  

Anzeigen der AufruferinformationenDisplaying the Callers' Information

Um die Informationen zu den Aufrufern anzuzeigen, können Sie ServiceSecurityContext.Current.AuthorizationContext.ClaimSets verwenden, wie im folgenden Beispielcode gezeigt.To display the caller's information, use the ServiceSecurityContext.Current.AuthorizationContext.ClaimSets as shown in the following sample code. ServiceSecurityContext.Current.AuthorizationContext.ClaimSets enthält dem aktuellen Aufrufer zugeordnete Autorisierungsansprüche.The ServiceSecurityContext.Current.AuthorizationContext.ClaimSets contains authorization claims associated with the current caller. Die Ansprüche werden von der CreditCardToken-Klasse in der AuthorizationPolicies-Auflistung angegeben.The claims are supplied by the CreditCardToken class in its AuthorizationPolicies collection.

bool TryGetStringClaimValue(ClaimSet claimSet, string claimType, out string claimValue)  
{  
    claimValue = null;  
    IEnumerable<Claim> matchingClaims = claimSet.FindClaims(claimType,  
        Rights.PossessProperty);  
    if (matchingClaims == null)  
        return false;  
    IEnumerator<Claim> enumerator = matchingClaims.GetEnumerator();  
    enumerator.MoveNext();  
    claimValue = (enumerator.Current.Resource == null) ? null :   
        enumerator.Current.Resource.ToString();  
    return true;  
}  

string GetCallerCreditCardNumber()  
{  
     foreach (ClaimSet claimSet in   
         ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)  
     {  
         string creditCardNumber = null;  
         if (TryGetStringClaimValue(claimSet,   
             Constants.CreditCardNumberClaim, out creditCardNumber))  
             {  
                 string issuer;  
                 if (!TryGetStringClaimValue(claimSet.Issuer,  
                        ClaimTypes.Name, out issuer))  
                 {  
                     issuer = "Unknown";  
                 }  
                 return String.Format(  
                   "Credit card '{0}' issued by '{1}'",   
                   creditCardNumber, issuer);  
        }  
    }  
    return "Credit card is not known";  
}  

Wenn Sie das Beispiel ausführen, werden die Anforderungen und Antworten für den Vorgang im Clientkonsolenfenster angezeigt.When you run the sample, the operation requests and responses are displayed in the client console window. Drücken Sie im Clientfenster die EINGABETASTE, um den Client zu schließen.Press ENTER in the client window to shut down the client.

SetupbatchdateiSetup Batch File

Mit der in diesem Beispiel enthaltenen Batchdatei Setup.bat können Sie den Server mit relevanten Zertifikaten zum Ausführen einer IIS-gehosteten Anwendung konfigurieren, die serverzertifikatbasierte Sicherheit erfordert.The Setup.bat batch file included with this sample allows you to configure the server with relevant certificates to run the IIS-hosted application that requires server certificate-based security. Diese Batchdatei muss angepasst werden, wenn sie computerübergreifend oder in einem nicht gehosteten Szenario verwendet werden soll.This batch file must be modified to work across computers or to work in a non-hosted case.

Nachfolgend erhalten Sie einen kurzen Überblick über die verschiedenen Abschnitte der Batchdateien, damit Sie sie so ändern können, dass sie in der entsprechenden Konfiguration ausgeführt werden.The following provides a brief overview of the different sections of the batch files so that they can be modified to run in the appropriate configuration.

  • Erstellen des ServerzertifikatsCreating the server certificate:

    Mit den folgenden Zeilen aus der Batchdatei Setup.bat wird das zu verwendende Serverzertifikat erstellt.The following lines from the Setup.bat batch file create the server certificate to be used. Die Variable %SERVER_NAME% gibt den Servernamen an.The %SERVER_NAME% variable specifies the server name. Ändern Sie diese Variable, und geben Sie Ihren eigenen Servernamen an.Change this variable to specify your own server name. Standardmäßig lautet die Variable in dieser Batchdatei localhost.The default in this batch file is localhost. Wenn Sie die Variable %SERVER_NAME% ändern, müssen Sie die Dateien Client.cs und Service.cs durchgehen und alle Vorkommnisse von localhost durch den Servernamen ersetzen, den Sie im Setup.bat-Skript verwenden.If you change the %SERVER_NAME% variable, you must go through the Client.cs and Service.cs files and replace all instances of localhost with the server name that you use in the Setup.bat script.

    Das Zertifikat wird im persönlichen Speicher unter dem Speicherort LocalMachine gespeichert.The certificate is stored in My (Personal) store under the LocalMachine store location. Das Zertifikat wird für die IIS-gehosteten Dienste im LocalMachine-Speicher gespeichert.The certificate is stored in the LocalMachine store for the IIS-hosted services. Für selbst gehostete Dienste sollten Sie die Batchdatei so ändern, dass das Clientzertifikat im Speicherort CurrentUser gespeichert wird. Ersetzen Sie hierzu die Zeichenfolge LocalMachine durch CurrentUser.For self-hosted services, you should modify the batch file to store the client certificate in the CurrentUser store location by replacing the string LocalMachine with CurrentUser.

    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  
    
  • Installieren des Serverzertifikats in den Clientspeicher für vertrauenswürdige Zertifikate:Installing the server certificate into client's trusted certificate store:

    Mit den folgenden Zeilen in der Batchdatei Setup.bat wird das Serverzertifikat in den Clientspeicher für vertrauenswürdige Personen kopiert.The following lines in the Setup.bat batch file copy the server certificate into the client trusted people store. Dieser Schritt ist erforderlich, da von "Makecert.exe" generierte Zertifikate nicht implizit vom Clientsystem als vertrauenswürdig eingestuft werden.This step is required because certificates generated by Makecert.exe are not implicitly trusted by the client system. Wenn Sie bereits über ein Zertifikat verfügen, dass von einem vertrauenswürdigen Clientstammzertifikat abstammt (z. B. ein von Microsoft ausgegebenes Zertifikat), ist dieser Schritt zum Auffüllen des Clientzertifikatspeichers mit dem Serverzertifikat nicht erforderlich.If you already have a certificate that is rooted in a client trusted root certificate—for example, a Microsoft issued certificate—this step of populating the client certificate store with the server certificate is not required.

    echo ************  
    echo copying server cert to client's TrustedPeople store  
    echo ************  
    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople  
    
  • Um den Zugriff vom IIS-gehosteten Dienst aus auf den privaten Schlüssel des Zertifikats zu aktivieren, müssen dem Benutzerkonto, unter dem der IIS-gehostete Prozess ausgeführt wird, entsprechende Berechtigungen für den privaten Schlüssel gewährt werden.To enable access to the certificate private key from the IIS-hosted service, the user account under which the IIS-hosted process is running must be granted appropriate permissions for the private key. Dies wird durch die letzten Schritte im Skript Setup.bat erreicht.This is accomplished by last steps in the Setup.bat script.

    echo ************  
    echo setting privileges on server certificates  
    echo ************  
    for /F "delims=" %%i in ('"%ProgramFiles%\ServiceModelSampleTools\FindPrivateKey.exe" My LocalMachine -n CN^=%SERVER_NAME% -a') do set PRIVATE_KEY_FILE=%%i  
    set WP_ACCOUNT=NT AUTHORITY\NETWORK SERVICE  
    (ver | findstr /C:"5.1") && set WP_ACCOUNT=%COMPUTERNAME%\ASPNET  
    echo Y|cacls.exe "%PRIVATE_KEY_FILE%" /E /G "%WP_ACCOUNT%":R  
    iisreset  
    

Hinweis

Die Batchdatei Setup.bat ist darauf ausgelegt, an einer Visual Studio 2012Visual Studio 2012-Eingabeaufforderung ausgeführt zu werden.The Setup.bat batch file is designed to be run from a Visual Studio 2012Visual Studio 2012 Command Prompt. Die innerhalb der Visual Studio 2012Visual Studio 2012-Eingabeaufforderung festgelegte PATH-Umgebungsvariable zeigt auf das Verzeichnis mit den ausführbaren Dateien, die für das Skript Setup.bat erforderlich sind.The PATH environment variable set within the Visual Studio 2012Visual Studio 2012 Command Prompt points to the directory that contains executables required by the Setup.bat script.

So richten Sie das Beispiel ein und erstellen esTo set up and build the sample

  1. Stellen Sie sicher, dass Sie ausgeführt haben die Setupprozedur für die Windows Communication Foundation-Beispiele zum einmaligen.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Führen Sie zum Erstellen der Projektmappe die Anweisungen im Erstellen der Windows Communication Foundation-Beispiele.To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

So führen Sie das Beispiel auf demselben Computer ausTo run the sample on the same computer

  1. Öffnen Sie eine Visual Studio 2012Visual Studio 2012-Eingabeaufforderung mit Administratorrechten, und führen Sie Setup.bat aus dem Beispielinstallationsordner aus.Open a Visual Studio 2012Visual Studio 2012 Command Prompt window with administrator privileges and run Setup.bat from the sample install folder. Hiermit werden alle Zertifikate installiert, die zum Ausführen des Beispiels erforderlich sind. Stellen Sie sicher, dass der Pfad den Ordner enthält, in dem sich Makecert.exe befindet.This installs all the certificates required for running the sample.Make sure that the path includes the folder where Makecert.exe is located.

Hinweis

Entfernen Sie nach Abschluss des Beispiels unbedingt die Zertifikate, indem Sie Cleanup.bat ausführen.Be sure to remove the certificates by running Cleanup.bat when finished with the sample. In anderen Sicherheitsbeispielen werden die gleichen Zertifikate verwendet.Other security samples use the same certificates.

  1. Starten Sie Client.exe im Verzeichnis \client\bin.Launch Client.exe from client\bin directory. In der Clientkonsolenanwendung wird Clientaktivität angezeigt.Client activity is displayed on the client console application.

  2. Wenn Client und Dienst nicht miteinander kommunizieren können, finden Sie unter Tipps zur Problembehandlung.If the client and service are not able to communicate, see Troubleshooting Tips.

So führen Sie das Beispiel computerübergreifend ausTo run the sample across computer

  1. Erstellen Sie auf dem Dienstcomputer ein Verzeichnis für die Dienstbinärdateien.Create a directory on the service computer for the service binaries.

  2. Kopieren Sie die Dienstprogrammdateien in das Dienstverzeichnis auf dem Dienstcomputer.Copy the service program files into the service directory on the service computer. Vergessen Sie nicht, die Datei CreditCardFile.txt zu kopieren. Andernfalls kann der Kreditkartenauthentifikator die vom Client gesendeten Kreditkartendaten nicht überprüfen.Do not forget to copy CreditCardFile.txt; otherwise the credit card authenticator cannot validate credit card information sent from the client. Kopieren Sie außerdem die Dateien Setup.bat und Cleanup.bat auf den Dienstcomputer.Also copy the Setup.bat and Cleanup.bat files to the service computer.

  3. Sie benötigen ein Serverzertifikat mit dem Antragstellernamen, das den vollqualifizierten Domänennamen des Computers enthält.You must have a server certificate with the subject name that contains the fully-qualified domain name of the computer. Ein entsprechendes Zertifikat können Sie mithilfe von Setup.bat erstellen, indem Sie die Variable %SERVER_NAME% auf den vollqualifizierten Namen des Computers festlegen, auf dem der Dienst gehostet wird.You can create one using the Setup.bat if you change the %SERVER_NAME% variable to fully-qualified name of the computer where the service is hosted. Beachten Sie, dass die Datei Setup.bat an einer Visual Studio-Eingabeaufforderung mit Administratorrechten ausgeführt werden muss.Note that the Setup.bat file must be run in a Visual Studio command prompt opened with administrator privileges.

  4. Kopieren Sie das Serverzertifikat in den Speicher CurrentUser-TrustedPeople auf dem Client.Copy the server certificate into the CurrentUser-TrustedPeople store on the client. Sie müssen dies nur tun, wenn das Serverzertifikat nicht von einem vertrauenswürdigen Aussteller ausgegeben wurde.You must do this only if the server certificate is not issued by a trusted issuer.

  5. Ändern Sie in der Datei EchoServiceHost.cs den Wert des Zertifikatsantragstellers, und geben Sie anstelle von localhost einen vollqualifizierten Computernamen an.In the EchoServiceHost.cs file, change the value of the certificate subject name to specify a fully-qualified computer name instead of localhost.

  6. Kopieren Sie die Clientprogrammdateien aus dem Ordner \client\bin\ (unterhalb des sprachspezifischen Ordners) auf den Clientcomputer.Copy the client program files from the \client\bin\ folder, under the language-specific folder, to the client computer.

  7. Ändern Sie in der Datei Client.cs den Adresswert des Endpunkts, sodass dieser mit der neuen Adresse Ihres Diensts übereinstimmt.In the Client.cs file, change the address value of the endpoint to match the new address of your service.

  8. Ändern Sie in der Datei Client.cs den Antragstellernamen des X.509-Dienstzertifikats, und geben Sie anstelle von localhost den vollqualifizierten Computernamen des Remotehosts an.In the Client.cs file change the subject name of the service X.509 certificate to match the fully-qualified computer name of the remote host instead of localhost.

  9. Starten Sie auf dem Clientcomputer Client.exe in einem Eingabeaufforderungsfenster.On the client computer, launch Client.exe from a command prompt window.

  10. Wenn Client und Dienst nicht miteinander kommunizieren können, finden Sie unter Tipps zur Problembehandlung.If the client and service are not able to communicate, see Troubleshooting Tips.

So stellen Sie den Zustand vor Ausführung des Beispiels wieder herTo clean up after the sample

  1. Führen Sie Cleanup.bat im Beispielordner aus, nachdem Sie das Beispiel fertig ausgeführt haben.Run Cleanup.bat in the samples folder once you have finished running the sample.

Siehe auchSee Also