Instrukcje: Tworzenie tokenu niestandardowego
W tym temacie pokazano, jak utworzyć niestandardowy token zabezpieczający przy użyciu SecurityToken klasy oraz jak zintegrować go z niestandardowym dostawcą tokenów zabezpieczających i wystawcą uwierzytelniania. Pełny przykład kodu można znaleźć w przykładzie niestandardowego tokenu.
Token zabezpieczający jest zasadniczo elementem XML używanym przez platformę zabezpieczeń windows Communication Foundation (WCF) do reprezentowania oświadczeń o nadawcy wewnątrz komunikatu PROTOKOŁU SOAP. Zabezpieczenia WCF zapewniają różne tokeny dla trybów uwierzytelniania dostarczanych przez system. Przykłady obejmują token zabezpieczający certyfikatu X.509 reprezentowany przez X509SecurityToken klasę lub token zabezpieczający nazwy użytkownika reprezentowany przez klasę UserNameSecurityToken .
Czasami tryb uwierzytelniania lub poświadczenia nie są obsługiwane przez podane typy. W takim przypadku należy utworzyć niestandardowy token zabezpieczający, aby zapewnić reprezentację XML niestandardowego poświadczenia wewnątrz komunikatu PROTOKOŁU SOAP.
Poniższe procedury pokazują, jak utworzyć niestandardowy token zabezpieczający i jak zintegrować go z infrastrukturą zabezpieczeń WCF. W tym temacie tworzony jest token karty kredytowej używany do przekazywania informacji o karcie kredytowej klienta do serwera.
Aby uzyskać więcej informacji na temat niestandardowych poświadczeń i menedżera tokenów zabezpieczających, zobacz Przewodnik: tworzenie niestandardowych poświadczeń klienta i usługi.
Zobacz przestrzeń nazw, System.IdentityModel.Tokens aby uzyskać więcej klas reprezentujących tokeny zabezpieczające.
z konkretnym obiektem
Aplikacja kliencka musi być dostarczana w celu określenia informacji o karcie kredytowej dla infrastruktury zabezpieczeń. Te informacje są udostępniane aplikacji przez niestandardową klasę poświadczeń klienta. Pierwszym krokiem jest utworzenie klasy reprezentującej informacje o karcie kredytowej dla niestandardowych poświadczeń klienta.
Aby utworzyć klasę reprezentującą informacje o karcie kredytowej wewnątrz poświadczeń klienta
Zdefiniuj nową klasę reprezentującą informacje o karcie kredytowej dla aplikacji. Poniższy przykład nazywa klasę
CreditCardInfo
.Dodaj odpowiednie właściwości do klasy, aby umożliwić aplikacji ustawienie niezbędnych informacji wymaganych dla tokenu niestandardowego. W tym przykładzie klasa ma trzy właściwości:
CardNumber
,CardIssuer
iExpirationDate
.public class CreditCardInfo { string cardNumber; string cardIssuer; DateTime expirationDate; public CreditCardInfo(string cardNumber, string cardIssuer, DateTime expirationDate) { this.cardNumber = cardNumber; this.cardIssuer = cardIssuer; this.expirationDate = expirationDate; } public string CardNumber { get { return this.cardNumber; } } public string CardIssuer { get { return this.cardIssuer; } } public DateTime ExpirationDate { get { return this.expirationDate; } } }
Public Class CreditCardInfo Private _cardNumber As String Private _cardIssuer As String Private _expirationDate As DateTime Public Sub New(ByVal cardNumber As String, ByVal cardIssuer As String, _ ByVal expirationDate As DateTime) Me._cardNumber = cardNumber Me._cardIssuer = cardIssuer Me._expirationDate = expirationDate End Sub Public ReadOnly Property CardNumber() As String Get Return Me._cardNumber End Get End Property Public ReadOnly Property CardIssuer() As String Get Return Me._cardIssuer End Get End Property Public ReadOnly Property ExpirationDate() As DateTime Get Return Me._expirationDate End Get End Property End Class
Następnie należy utworzyć klasę reprezentującą niestandardowy token zabezpieczający. Ta klasa jest używana przez dostawcę tokenów zabezpieczających, wystawcę uwierzytelniającego i serializatora do przekazywania informacji o tokenie zabezpieczającym do i z infrastruktury zabezpieczeń programu WCF.
Aby utworzyć niestandardową klasę tokenu zabezpieczającego
Zdefiniuj nową klasę pochodzącą SecurityToken z klasy . W tym przykładzie zostanie utworzona klasa o nazwie
CreditCardToken
.Zastąpij Id właściwość . Ta właściwość służy do pobierania identyfikatora lokalnego tokenu zabezpieczającego używanego do wskazywania reprezentacji XML tokenu zabezpieczającego z innych elementów wewnątrz komunikatu PROTOKOŁU SOAP. W tym przykładzie identyfikator tokenu można przekazać do niego jako parametr konstruktora lub jest generowany nowy losowy przy każdym utworzeniu wystąpienia tokenu zabezpieczającego.
Zaimplementuj SecurityKeys właściwość . Ta właściwość zwraca kolekcję kluczy zabezpieczeń reprezentowanych przez wystąpienie tokenu zabezpieczającego. Takie klucze mogą być używane przez usługę WCF do podpisywania lub szyfrowania części komunikatu PROTOKOŁU SOAP. W tym przykładzie token zabezpieczający karty kredytowej nie może zawierać żadnych kluczy zabezpieczeń; dlatego implementacja zawsze zwraca pustą kolekcję.
Zastąpij ValidFrom właściwości i ValidTo . Te właściwości są używane przez usługę WCF do określenia ważności wystąpienia tokenu zabezpieczającego. W tym przykładzie token zabezpieczający karty kredytowej ma tylko datę wygaśnięcia, więc
ValidFrom
właściwość zwraca wartość reprezentującą DateTime datę i godzinę utworzenia wystąpienia.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; } } }
Friend Class CreditCardToken Inherits SecurityToken Private _cardInfo As CreditCardInfo Private _effectiveTime As DateTime = DateTime.UtcNow Private _id As String Private _securityKeys As ReadOnlyCollection(Of SecurityKey) Public Sub New(ByVal cardInfo As CreditCardInfo) Me.New(cardInfo, Guid.NewGuid().ToString()) End Sub Public Sub New(ByVal cardInfo As CreditCardInfo, _ ByVal id As String) If cardInfo Is Nothing Then Throw New ArgumentNullException("cardInfo") End If If id Is Nothing Then Throw New ArgumentNullException("id") End If Me._cardInfo = cardInfo Me._id = id ' The credit card token is not capable of any cryptography. Me._securityKeys = New ReadOnlyCollection(Of SecurityKey)(New List(Of SecurityKey)()) End Sub Public ReadOnly Property CardInfo() As CreditCardInfo Get Return Me._cardInfo End Get End Property Public Overrides ReadOnly Property SecurityKeys() As ReadOnlyCollection(Of SecurityKey) Get Return Me._securityKeys End Get End Property Public Overrides ReadOnly Property ValidFrom() As DateTime Get Return Me._effectiveTime End Get End Property Public Overrides ReadOnly Property ValidTo() As DateTime Get Return Me._cardInfo.ExpirationDate End Get End Property Public Overrides ReadOnly Property Id() As String Get Return Me._id End Get End Property End Class
Po utworzeniu nowego typu tokenu zabezpieczającego wymaga implementacji SecurityTokenParameters klasy. Implementacja jest używana w konfiguracji elementu powiązania zabezpieczeń do reprezentowania nowego typu tokenu. Klasa parametrów tokenu zabezpieczającego służy jako szablon, który jest używany do dopasowania rzeczywistego wystąpienia tokenu zabezpieczającego do momentu przetworzenia komunikatu. Szablon zawiera dodatkowe właściwości, których aplikacja może używać do określania kryteriów, które token zabezpieczający musi być zgodny z używanym lub uwierzytelnianym. Poniższy przykład nie dodaje żadnych dodatkowych właściwości, dlatego tylko typ tokenu zabezpieczającego jest zgodny, gdy infrastruktura WCF wyszukuje wystąpienie tokenu zabezpieczającego do użycia lub weryfikacji.
Aby utworzyć niestandardową klasę parametrów tokenu zabezpieczającego
Zdefiniuj nową klasę pochodzącą SecurityTokenParameters z klasy .
Zaimplementuj metodę CloneCore . Skopiuj wszystkie pola wewnętrzne zdefiniowane w klasie, jeśli istnieją. W tym przykładzie nie zdefiniowano żadnych dodatkowych pól.
Zaimplementuj SupportsClientAuthentication właściwość tylko do odczytu. Ta właściwość zwraca
true
wartość, jeśli typ tokenu zabezpieczającego reprezentowany przez tę klasę może służyć do uwierzytelniania klienta w usłudze. W tym przykładzie token zabezpieczający karty kredytowej może służyć do uwierzytelniania klienta w usłudze.Zaimplementuj SupportsServerAuthentication właściwość tylko do odczytu. Ta właściwość zwraca
true
wartość, jeśli typ tokenu zabezpieczającego reprezentowany przez tę klasę może służyć do uwierzytelniania usługi na kliencie. W tym przykładzie token zabezpieczający karty kredytowej nie może być używany do uwierzytelniania usługi na kliencie.Zaimplementuj SupportsClientWindowsIdentity właściwość tylko do odczytu. Ta właściwość zwraca
true
wartość, jeśli typ tokenu zabezpieczającego reprezentowany przez tę klasę może zostać zamapowany na konto systemu Windows. Jeśli tak, wynik uwierzytelniania jest reprezentowany przez WindowsIdentity wystąpienie klasy. W tym przykładzie nie można zamapować tokenu na konto systemu Windows.Zaimplementuj metodę CreateKeyIdentifierClause(SecurityToken, SecurityTokenReferenceStyle) . Ta metoda jest wywoływana przez platformę zabezpieczeń WCF, gdy wymaga odwołania do wystąpienia tokenu zabezpieczającego reprezentowanego przez tę klasę parametrów tokenu zabezpieczającego. Zarówno rzeczywiste wystąpienie tokenu zabezpieczającego, jak i SecurityTokenReferenceStyle określające typ żądanego odwołania są przekazywane do tej metody jako argumenty. W tym przykładzie tylko odwołania wewnętrzne są obsługiwane przez token zabezpieczający karty kredytowej. Klasa SecurityToken ma funkcje tworzenia odwołań wewnętrznych, dlatego implementacja nie wymaga dodatkowego kodu.
Zaimplementuj metodę InitializeSecurityTokenRequirement(SecurityTokenRequirement) . Ta metoda jest wywoływana przez usługę WCF w celu przekonwertowania wystąpienia klasy parametrów tokenu zabezpieczającego SecurityTokenRequirement na wystąpienie klasy. Wynik jest używany przez dostawców tokenów zabezpieczających do utworzenia odpowiedniego wystąpienia tokenu zabezpieczającego.
public class CreditCardTokenParameters : SecurityTokenParameters { public CreditCardTokenParameters() { } protected CreditCardTokenParameters(CreditCardTokenParameters other) : base(other) { } protected override SecurityTokenParameters CloneCore() { return new CreditCardTokenParameters(this); } protected override void InitializeSecurityTokenRequirement(SecurityTokenRequirement requirement) { requirement.TokenType = Constants.CreditCardTokenType; return; } // A credit card token has no cryptography, no windows identity, and supports only client authentication. protected override bool HasAsymmetricKey { get { return false; } } protected override bool SupportsClientAuthentication { get { return true; } } protected override bool SupportsClientWindowsIdentity { get { return false; } } protected override bool SupportsServerAuthentication { get { return false; } } protected override SecurityKeyIdentifierClause CreateKeyIdentifierClause(SecurityToken token, SecurityTokenReferenceStyle referenceStyle) { if (referenceStyle == SecurityTokenReferenceStyle.Internal) { return token.CreateKeyIdentifierClause<LocalIdKeyIdentifierClause>(); } else { throw new NotSupportedException("External references are not supported for credit card tokens"); } } }
Public Class CreditCardTokenParameters Inherits SecurityTokenParameters Public Sub New() End Sub Protected Sub New(ByVal other As CreditCardTokenParameters) MyBase.New(other) End Sub Protected Overrides Function CloneCore() As SecurityTokenParameters Return New CreditCardTokenParameters(Me) End Function Protected Overrides Sub InitializeSecurityTokenRequirement(ByVal requirement As SecurityTokenRequirement) requirement.TokenType = Constants.CreditCardTokenType Return End Sub ' A credit card token has no cryptography, no windows identity, and supports only client authentication. Protected Overrides ReadOnly Property HasAsymmetricKey() As Boolean Get Return False End Get End Property Protected Overrides ReadOnly Property SupportsClientAuthentication() As Boolean Get Return True End Get End Property Protected Overrides ReadOnly Property SupportsClientWindowsIdentity() As Boolean Get Return False End Get End Property Protected Overrides ReadOnly Property SupportsServerAuthentication() As Boolean Get Return False End Get End Property Protected Overrides Function CreateKeyIdentifierClause(ByVal token As SecurityToken, _ ByVal referenceStyle As SecurityTokenReferenceStyle) As SecurityKeyIdentifierClause If referenceStyle = SecurityTokenReferenceStyle.Internal Then Return token.CreateKeyIdentifierClause(Of LocalIdKeyIdentifierClause)() Else Throw New NotSupportedException("External references are not supported for credit card tokens") End If End Function End Class
Tokeny zabezpieczające są przesyłane wewnątrz komunikatów PROTOKOŁU SOAP, co wymaga mechanizmu tłumaczenia między reprezentacją tokenu zabezpieczającego w pamięci a reprezentacją on-the-wire. Program WCF używa serializatora tokenu zabezpieczającego do wykonania tego zadania. Do każdego tokenu niestandardowego musi towarzyszyć niestandardowy serializator tokenu zabezpieczającego, który może serializować i deserializować niestandardowy token zabezpieczający z komunikatu PROTOKOŁU SOAP.
Uwaga
Klucze pochodne są domyślnie włączone. Jeśli utworzysz niestandardowy token zabezpieczający i użyjesz go jako tokenu podstawowego, program WCF będzie uzyskiwać z niego klucz. W ten sposób wywołuje niestandardowy serializator tokenu zabezpieczającego w celu zapisania SecurityKeyIdentifierClause niestandardowego tokenu zabezpieczającego podczas serializacji DerivedKeyToken
do przewodu. Na końcu odbierania, podczas deserializacji tokenu z przewodu, DerivedKeyToken
serializator oczekuje SecurityTokenReference
elementu jako elementu podrzędnego najwyższego poziomu w sobie. Jeśli niestandardowy serializator tokenu zabezpieczającego SecurityTokenReference
nie dodał elementu podczas serializacji jego typu klauzuli, zgłaszany jest wyjątek.
Aby utworzyć niestandardowy serializator tokenu zabezpieczającego
Zdefiniuj nową klasę pochodzącą WSSecurityTokenSerializer z klasy .
Zastąpi metodę CanReadTokenCore(XmlReader) , która opiera się na XmlReader metodzie odczytu strumienia XML. Metoda zwraca
true
, jeśli implementacja serializatora może deserializować token zabezpieczający na podstawie jego bieżącego elementu. W tym przykładzie ta metoda sprawdza, czy bieżący element XML czytnika XML ma poprawną nazwę elementu i przestrzeń nazw. Jeśli tak nie jest, wywołuje implementację klasy bazowej tej metody w celu obsługi elementu XML.Zastąpij metodę ReadTokenCore(XmlReader, SecurityTokenResolver) . Ta metoda odczytuje zawartość XML tokenu zabezpieczającego i tworzy odpowiednią reprezentację w pamięci. Jeśli nie rozpoznaje elementu XML, na którym stoi przekazany czytnik XML, wywołuje implementację klasy bazowej w celu przetworzenia typów tokenów dostarczonych przez system.
Zastąpij metodę CanWriteTokenCore(SecurityToken) . Ta metoda zwraca
true
, jeśli może przekonwertować reprezentację tokenu w pamięci (przekazaną jako argument) do reprezentacji XML. Jeśli nie można go przekonwertować, wywołuje implementację klasy bazowej.Zastąpij metodę WriteTokenCore(XmlWriter, SecurityToken) . Ta metoda konwertuje reprezentację tokenu zabezpieczającego w pamięci na reprezentację XML. Jeśli metoda nie może dokonać konwersji, wywołuje implementację klasy bazowej.
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); } } }
Public Class CreditCardSecurityTokenSerializer Inherits WSSecurityTokenSerializer Public Sub New(ByVal version As SecurityTokenVersion) MyBase.New() End Sub Protected Overrides Function CanReadTokenCore(ByVal reader As XmlReader) As Boolean Dim localReader = XmlDictionaryReader.CreateDictionaryReader(reader) If reader Is Nothing Then Throw New ArgumentNullException("reader") End If If reader.IsStartElement(Constants.CreditCardTokenName, _ Constants.CreditCardTokenNamespace) Then Return True End If Return MyBase.CanReadTokenCore(reader) End Function Protected Overrides Function ReadTokenCore(ByVal reader As XmlReader, _ ByVal tokenResolver As SecurityTokenResolver) As SecurityToken If reader Is Nothing Then Throw New ArgumentNullException("reader") End If If reader.IsStartElement(Constants.CreditCardTokenName, _ Constants.CreditCardTokenNamespace) Then Dim id = reader.GetAttribute(Constants.Id, _ Constants.WsUtilityNamespace) reader.ReadStartElement() ' Read the credit card number. Dim creditCardNumber = reader.ReadElementString(Constants.CreditCardNumberElementName, _ Constants.CreditCardTokenNamespace) ' Read the expiration date. Dim expirationTimeString = reader.ReadElementString(Constants.CreditCardExpirationElementName, _ Constants.CreditCardTokenNamespace) Dim expirationTime As DateTime = XmlConvert.ToDateTime(expirationTimeString, _ XmlDateTimeSerializationMode.Utc) ' Read the issuer of the credit card. Dim creditCardIssuer = reader.ReadElementString(Constants.CreditCardIssuerElementName, _ Constants.CreditCardTokenNamespace) reader.ReadEndElement() Dim cardInfo As New CreditCardInfo(creditCardNumber, _ creditCardIssuer, _ expirationTime) Return New CreditCardToken(cardInfo, id) Else Return WSSecurityTokenSerializer.DefaultInstance.ReadToken(reader, _ tokenResolver) End If End Function Protected Overrides Function CanWriteTokenCore(ByVal token As SecurityToken) As Boolean If TypeOf token Is CreditCardToken Then Return True Else Return MyBase.CanWriteTokenCore(token) End If End Function Protected Overrides Sub WriteTokenCore(ByVal writer As XmlWriter, _ ByVal token As SecurityToken) If writer Is Nothing Then Throw New ArgumentNullException("writer") End If If token Is Nothing Then Throw New ArgumentNullException("token") End If Dim c = TryCast(token, CreditCardToken) If c IsNot Nothing Then With writer .WriteStartElement(Constants.CreditCardTokenPrefix, _ Constants.CreditCardTokenName, _ Constants.CreditCardTokenNamespace) .WriteAttributeString(Constants.WsUtilityPrefix, _ Constants.Id, _ Constants.WsUtilityNamespace, _ token.Id) .WriteElementString(Constants.CreditCardNumberElementName, _ Constants.CreditCardTokenNamespace, _ c.CardInfo.CardNumber) .WriteElementString(Constants.CreditCardExpirationElementName, _ Constants.CreditCardTokenNamespace, _ XmlConvert.ToString(c.CardInfo.ExpirationDate, _ XmlDateTimeSerializationMode.Utc)) .WriteElementString(Constants.CreditCardIssuerElementName, _ Constants.CreditCardTokenNamespace, _ c.CardInfo.CardIssuer) .WriteEndElement() .Flush() End With Else MyBase.WriteTokenCore(writer, token) End If End Sub End Class
Po wykonaniu czterech poprzednich procedur zintegruj niestandardowy token zabezpieczający z dostawcą tokenów zabezpieczających, wystawcą uwierzytelnień, menedżerem oraz poświadczeniami klienta i usługi.
Aby zintegrować niestandardowy token zabezpieczający z dostawcą tokenów zabezpieczających
Dostawca tokenu zabezpieczającego tworzy, modyfikuje (w razie potrzeby) i zwraca wystąpienie tokenu. Aby utworzyć niestandardowego dostawcę dla niestandardowego tokenu zabezpieczającego, utwórz klasę dziedziczą z SecurityTokenProvider klasy. Poniższy przykład zastępuje metodę GetTokenCore , aby zwrócić wystąpienie
CreditCardToken
klasy . Aby uzyskać więcej informacji na temat niestandardowych dostawców tokenów zabezpieczających, zobacz How to: Create a Custom Security Token Provider (Instrukcje: tworzenie niestandardowego dostawcy tokenów zabezpieczających).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; } }
Friend Class CreditCardTokenProvider Inherits SecurityTokenProvider Private creditCardInfo As CreditCardInfo Public Sub New(ByVal creditCardInfo As CreditCardInfo) MyBase.New() If creditCardInfo Is Nothing Then Throw New ArgumentNullException("creditCardInfo") End If Me.creditCardInfo = creditCardInfo End Sub Protected Overrides Function GetTokenCore(ByVal timeout As TimeSpan) As SecurityToken Return TryCast(New CreditCardToken(Me.creditCardInfo), SecurityToken) End Function End Class
Aby zintegrować niestandardowy token zabezpieczający z wystawcą uwierzytelniającego tokenu zabezpieczającego
Wystawca uwierzytelnienia tokenu zabezpieczającego weryfikuje zawartość tokenu zabezpieczającego po wyodrębnieniu go z komunikatu. Aby utworzyć niestandardowy wystawcę uwierzytelnień dla niestandardowego tokenu zabezpieczającego, utwórz klasę dziedziczą z SecurityTokenAuthenticator klasy. Poniższy przykład zastępuje metodę ValidateTokenCore . Aby uzyskać więcej informacji na temat niestandardowych wystawców uwierzytelnień tokenów zabezpieczających, zobacz How to: Create a Custom Security Token Authenticator (Instrukcje: tworzenie niestandardowego wystawcy uwierzytelniania tokenu zabezpieczającego).
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(); } // This helper method checks whether a given credit card entry is present in the user database. 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()); } } }
Friend Class CreditCardTokenAuthenticator Inherits SecurityTokenAuthenticator Private creditCardsFile As String Public Sub New(ByVal creditCardsFile As String) Me.creditCardsFile = creditCardsFile End Sub Protected Overrides Function CanValidateTokenCore(ByVal token As SecurityToken) As Boolean Return (TypeOf token Is CreditCardToken) End Function Protected Overrides Function ValidateTokenCore(ByVal token As SecurityToken) As ReadOnlyCollection(Of IAuthorizationPolicy) Dim creditCardToken = TryCast(token, CreditCardToken) If creditCardToken.CardInfo.ExpirationDate < DateTime.UtcNow Then Throw New SecurityTokenValidationException("The credit card has expired") End If If Not IsCardNumberAndExpirationValid(creditCardToken.CardInfo) Then Throw New SecurityTokenValidationException("Unknown or invalid credit card") End If ' The credit card token has only 1 claim: the card number. The issuer for the claim is the ' credit card issuer. Dim cardIssuerClaimSet As New DefaultClaimSet(New Claim(ClaimTypes.Name, _ creditCardToken.CardInfo.CardIssuer, _ Rights.PossessProperty)) Dim cardClaimSet As New DefaultClaimSet(cardIssuerClaimSet, _ New Claim(Constants.CreditCardNumberClaim, _ creditCardToken.CardInfo.CardNumber, _ Rights.PossessProperty)) Dim policies As New List(Of IAuthorizationPolicy)(1) policies.Add(New CreditCardTokenAuthorizationPolicy(cardClaimSet)) Return policies.AsReadOnly() End Function ' This helper method checks whether a given credit card entry is present in the user database. Private Function IsCardNumberAndExpirationValid(ByVal cardInfo As CreditCardInfo) As Boolean Try Using myStreamReader As New StreamReader(Me.creditCardsFile) Dim line = String.Empty line = myStreamReader.ReadLine() Do While line IsNot Nothing Dim splitEntry() = line.Split("#"c) If splitEntry(0) = cardInfo.CardNumber Then Dim expirationDateString = splitEntry(1).Trim() Dim expirationDateOnFile As DateTime = DateTime.Parse(expirationDateString, _ System.Globalization.DateTimeFormatInfo.InvariantInfo, _ System.Globalization.DateTimeStyles.AdjustToUniversal) If cardInfo.ExpirationDate = expirationDateOnFile Then Dim issuer = splitEntry(2) Return issuer.Equals(cardInfo.CardIssuer, _ StringComparison.InvariantCultureIgnoreCase) Else Return False End If End If line = myStreamReader.ReadLine() Loop Return False End Using Catch e As Exception Throw New Exception("BookStoreService: Error while retrieving credit card information from User DB " & e.ToString()) End Try End Function End Class
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; } }
Public Class CreditCardTokenAuthorizationPolicy Implements IAuthorizationPolicy Private _id As String Private _issuer As ClaimSet Private _issuedClaimSets As IEnumerable(Of ClaimSet) Public Sub New(ByVal issuedClaims As ClaimSet) If issuedClaims Is Nothing Then Throw New ArgumentNullException("issuedClaims") End If Me._issuer = issuedClaims.Issuer Me._issuedClaimSets = New ClaimSet() {issuedClaims} Me._id = Guid.NewGuid().ToString() End Sub Public ReadOnly Property Issuer() As ClaimSet Implements IAuthorizationPolicy.Issuer Get Return Me._issuer End Get End Property Public ReadOnly Property Id() As String Implements System.IdentityModel.Policy.IAuthorizationComponent.Id Get Return Me._id End Get End Property Public Function Evaluate(ByVal context As EvaluationContext, _ ByRef state As Object) As Boolean Implements IAuthorizationPolicy.Evaluate For Each issuance In Me._issuedClaimSets context.AddClaimSet(Me, issuance) Next issuance Return True End Function End Class
Aby zintegrować niestandardowy token zabezpieczający z menedżerem tokenów zabezpieczających
Menedżer tokenów zabezpieczających tworzy odpowiedniego dostawcę tokenów, wystawcę uwierzytelniania zabezpieczeń i wystąpienia serializacji tokenów. Aby utworzyć niestandardowy menedżer tokenów, utwórz klasę dziedziczą po ClientCredentialsSecurityTokenManager klasie. Podstawowe metody klasy używają klasy , SecurityTokenRequirement aby utworzyć odpowiedniego dostawcę i poświadczenia klienta lub usługi. Aby uzyskać więcej informacji na temat niestandardowych menedżerów tokenów zabezpieczających, zobacz Przewodnik: tworzenie niestandardowych poświadczeń klienta i usługi.
public class CreditCardClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager { CreditCardClientCredentials creditCardClientCredentials; public CreditCardClientCredentialsSecurityTokenManager(CreditCardClientCredentials creditCardClientCredentials) : base(creditCardClientCredentials) { this.creditCardClientCredentials = creditCardClientCredentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { if (tokenRequirement.TokenType == Constants.CreditCardTokenType) { // Handle this token for Custom. return new CreditCardTokenProvider(this.creditCardClientCredentials.CreditCardInfo); } else if (tokenRequirement is InitiatorServiceModelSecurityTokenRequirement) { // Return server certificate. 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); } }
Public Class CreditCardClientCredentialsSecurityTokenManager Inherits ClientCredentialsSecurityTokenManager Private creditCardClientCredentials As CreditCardClientCredentials Public Sub New(ByVal creditCardClientCredentials As CreditCardClientCredentials) MyBase.New(creditCardClientCredentials) Me.creditCardClientCredentials = creditCardClientCredentials End Sub Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider If tokenRequirement.TokenType = Constants.CreditCardTokenType Then ' Handle this token for Custom. Return New CreditCardTokenProvider(Me.creditCardClientCredentials.CreditCardInfo) ElseIf TypeOf tokenRequirement Is InitiatorServiceModelSecurityTokenRequirement Then ' Return server certificate. If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then Return New X509SecurityTokenProvider(creditCardClientCredentials.ServiceCertificate.DefaultCertificate) End If End If Return MyBase.CreateSecurityTokenProvider(tokenRequirement) End Function Public Overloads Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) As SecurityTokenSerializer Return New CreditCardSecurityTokenSerializer(version) End Function End Class
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); } }
Public Class CreditCardServiceCredentialsSecurityTokenManager Inherits ServiceCredentialsSecurityTokenManager Private creditCardServiceCredentials As CreditCardServiceCredentials Public Sub New(ByVal creditCardServiceCredentials As CreditCardServiceCredentials) MyBase.New(creditCardServiceCredentials) Me.creditCardServiceCredentials = creditCardServiceCredentials End Sub Public Overrides Function CreateSecurityTokenAuthenticator(ByVal tokenRequirement As SecurityTokenRequirement, _ <System.Runtime.InteropServices.Out()> ByRef outOfBandTokenResolver As SecurityTokenResolver) As SecurityTokenAuthenticator If tokenRequirement.TokenType = Constants.CreditCardTokenType Then outOfBandTokenResolver = Nothing Return New CreditCardTokenAuthenticator(creditCardServiceCredentials.CreditCardDataFile) End If Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver) End Function Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) As SecurityTokenSerializer Return New CreditCardSecurityTokenSerializer(version) End Function End Class
Aby zintegrować niestandardowy token zabezpieczający z niestandardowymi poświadczeniami klienta i usługi
Niestandardowe poświadczenia klienta i usługi należy dodać, aby udostępnić interfejs API dla aplikacji, aby umożliwić określenie niestandardowych informacji o tokenach używanych przez niestandardową infrastrukturę tokenów zabezpieczających utworzoną wcześniej w celu udostępnienia i uwierzytelnienia niestandardowej zawartości tokenu zabezpieczającego. W poniższych przykładach pokazano, jak można to zrobić. Aby uzyskać więcej informacji na temat niestandardowych poświadczeń klienta i usługi, zobacz Przewodnik: tworzenie niestandardowych poświadczeń klienta i usługi.
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 CreditCardClientCredentials Inherits ClientCredentials Private _creditCardInfo As CreditCardInfo Public Sub New(ByVal creditCardInfo As CreditCardInfo) MyBase.New() If creditCardInfo Is Nothing Then Throw New ArgumentNullException("creditCardInfo") End If Me._creditCardInfo = creditCardInfo End Sub Public ReadOnly Property CreditCardInfo() As CreditCardInfo Get Return Me._creditCardInfo End Get End Property Protected Overrides Function CloneCore() As ClientCredentials Return New CreditCardClientCredentials(Me._creditCardInfo) End Function Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New CreditCardClientCredentialsSecurityTokenManager(Me) End Function End Class
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 CreditCardServiceCredentials Inherits ServiceCredentials Private creditCardFile As String Public Sub New(ByVal creditCardFile As String) MyBase.New() If creditCardFile Is Nothing Then Throw New ArgumentNullException("creditCardFile") End If Me.creditCardFile = creditCardFile End Sub Public ReadOnly Property CreditCardDataFile() As String Get Return Me.creditCardFile End Get End Property Protected Overrides Function CloneCore() As ServiceCredentials Return New CreditCardServiceCredentials(Me.creditCardFile) End Function Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New CreditCardServiceCredentialsSecurityTokenManager(Me) End Function End Class
Utworzona wcześniej niestandardowa klasa parametrów tokenu zabezpieczającego służy do informowania platformy zabezpieczeń WCF, że podczas komunikacji z usługą należy używać niestandardowego tokenu zabezpieczającego. Poniższa procedura pokazuje, jak można to zrobić.
Aby zintegrować niestandardowy token zabezpieczający z powiązaniem
Niestandardowa klasa parametrów tokenu zabezpieczającego musi być określona w jednej z kolekcji parametrów tokenu uwidocznionych w SecurityBindingElement klasie. W poniższym przykładzie użyto kolekcji zwróconej przez
SignedEncrypted
element . Kod dodaje niestandardowy token karty kredytowej do każdego komunikatu wysyłanego od klienta do usługi z zawartością automatycznie podpisaną i zaszyfrowaną.public static class BindingHelper { public static Binding CreateCreditCardBinding() { HttpTransportBindingElement httpTransport = new HttpTransportBindingElement(); // The message security binding element is configured to require a credit card // 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); } }
Public NotInheritable Class BindingHelper Private Sub New() End Sub Public Shared Function CreateCreditCardBinding() As Binding Dim httpTransport As New HttpTransportBindingElement() ' The message security binding element is configured to require a credit card ' token that is encrypted with the service's certificate. Dim messageSecurity As New SymmetricSecurityBindingElement() messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(New CreditCardTokenParameters()) Dim x509ProtectionParameters As New X509SecurityTokenParameters() x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never messageSecurity.ProtectionTokenParameters = x509ProtectionParameters Return New CustomBinding(messageSecurity, httpTransport) End Function End Class
W tym temacie przedstawiono różne fragmenty kodu niezbędne do zaimplementowania i użycia tokenu niestandardowego. Aby zobaczyć pełny przykład sposobu dopasowania wszystkich tych fragmentów kodu do siebie, zobacz Custom Token (Token niestandardowy).
Zobacz też
- SecurityToken
- SecurityTokenParameters
- WSSecurityTokenSerializer
- SecurityTokenProvider
- SecurityTokenAuthenticator
- IAuthorizationPolicy
- SecurityTokenRequirement
- SecurityTokenManager
- ClientCredentials
- ServiceCredentials
- SecurityBindingElement
- Przewodnik: tworzenie niestandardowego klienta i poświadczeń usługi
- Instrukcje: tworzenie niestandardowego wystawcy uwierzytelniania tokenu zabezpieczeń
- Instrukcje: tworzenie niestandardowego dostawcy tokenów zabezpieczeń