Cara: Membuat Token Kustom
Topik ini menunjukkan cara membuat token keamanan khusus menggunakan kelas SecurityToken, dan cara mengintegrasikannya dengan penyedia dan pengautentikasi token keamanan khusus. Untuk contoh kode lengkap, lihat sampel Token Kustom .
Token keamanan pada dasarnya adalah elemen XML yang digunakan oleh kerangka kerja keamanan Windows Communication Foundation (WCF) untuk mewakili klaim tentang pengirim di dalam pesan SOAP. Keamanan WCF menyediakan berbagai token untuk mode autentikasi yang disediakan sistem. Contohnya termasuk token keamanan sertifikat X.509 yang diwakili oleh kelas X509SecurityToken atau token keamanan Nama Pengguna yang diwakili oleh kelas UserNameSecurityToken.
Terkadang mode autentikasi atau kredensial tidak didukung oleh jenis yang disediakan. Dalam hal ini, token keamanan khusus harus dibuat untuk memberikan representasi XML dari kredensial khusus di dalam pesan SOAP.
Prosedur berikut menunjukkan cara membuat token keamanan kustom dan cara mengintegrasikannya dengan infrastruktur keamanan WCF. Topik ini membuat token kartu kredit yang digunakan untuk meneruskan informasi tentang kartu kredit klien ke server.
Untuk informasi selengkapnya tentang kredensial khusus dan pengelola token keamanan, lihat Petunjuk: Membuat Kredensial Klien dan Layanan Khusus.
Lihat System.IdentityModel.Tokens namespace layanan untuk lebih banyak kelas yang mewakili token keamanan.
Prosedur
Aplikasi klien harus dilengkapi dengan cara untuk menentukan informasi kartu kredit untuk infrastruktur keamanan. Informasi ini tersedia untuk aplikasi oleh kelas kredensial klien kustom. Langkah pertama adalah membuat kelas untuk mewakili informasi kartu kredit untuk kredensial klien kustom.
Untuk membuat kelas yang mewakili informasi kartu kredit di dalam kredensial klien
Tentukan kelas baru yang mewakili informasi kartu kredit untuk aplikasi. Contoh berikut menamai kelas
CreditCardInfo
.Tambahkan properti yang sesuai ke kelas untuk memungkinkan aplikasi mengatur informasi yang diperlukan untuk token kustom. Dalam contoh ini, kelas memiliki tiga properti:
CardNumber
,CardIssuer
, danExpirationDate
.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
Selanjutnya, kelas yang mewakili token keamanan kustom harus dibuat. Kelas ini digunakan oleh kelas penyedia token keamanan, pengautentikasi, dan serializer untuk meneruskan informasi tentang token keamanan ke dan dari infrastruktur keamanan WCF.
Untuk membuat kelas token keamanan kustom
Tentukan kelas baru turunan dari kelas SecurityToken. Contoh ini membuat kelas yang dinamai
CreditCardToken
.Ambil alih properti Id. Properti ini digunakan untuk mendapatkan pengidentifikasi lokal token keamanan yang digunakan untuk menunjuk ke representasi XML token keamanan dari elemen lain di dalam pesan SOAP. Dalam contoh ini, pengidentifikasi token dapat diteruskan ke dalamnya sebagai parameter konstruktor atau yang acak baru dihasilkan setiap kali instans token keamanan dibuat.
Implementasikan properti SecurityKeys. Properti ini mengembalikan kumpulan kunci keamanan yang diwakili oleh instans token keamanan. Kunci tersebut dapat digunakan oleh WCF untuk menandatangani atau mengenkripsi bagian dari pesan SOAP. Dalam contoh ini, token keamanan kartu kredit tidak boleh berisi kunci keamanan apa pun; oleh karena itu, implementasi selalu mengembalikan kumpulan kosong.
Ambil alih properti ValidFrom dan ValidTo. Properti ini digunakan oleh WCF untuk menentukan validitas instans token keamanan. Dalam contoh ini, token keamanan kartu kredit hanya memiliki tanggal kedaluwarsa, sehingga properti
ValidFrom
mengembalikan DateTime yang mewakili tanggal dan waktu pembuatan instans.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
Ketika jenis token keamanan baru dibuat, jenis token keamanan memerlukan implementasi kelas SecurityTokenParameters. Implementasinya digunakan dalam konfigurasi elemen pengikatan keamanan untuk mewakili jenis token baru. Kelas parameter token keamanan berfungsi sebagai templat yang digunakan untuk mencocokkan instans token keamanan aktual dengan saat pesan diproses. Template menyediakan properti tambahan yang dapat digunakan aplikasi untuk menentukan kriteria yang harus cocok dengan token keamanan untuk digunakan atau diautentikasi. Contoh berikut tidak menambahkan properti tambahan apa pun, jadi hanya jenis token keamanan yang cocok ketika infrastruktur WCF mencari instans token keamanan untuk digunakan atau untuk divalidasi.
Untuk membuat kelas parameter token keamanan kustom
Tentukan kelas baru turunan dari kelas SecurityTokenParameters.
Mengimplementasikan metode CloneCore. Salin semua bidang internal yang ditentukan di kelas Anda, jika ada. Contoh ini tidak menentukan bidang tambahan apa pun.
Implementasikan properti SupportsClientAuthentication baca-saja. Properti ini mengembalikan
true
jika jenis token keamanan yang diwakili oleh kelas ini dapat digunakan untuk mengautentikasi klien ke layanan. Dalam contoh ini, token keamanan kartu kredit dapat digunakan untuk mengautentikasi klien ke layanan.Implementasikan properti SupportsServerAuthentication baca-saja. Properti ini mengembalikan
true
jika jenis token keamanan yang diwakili oleh kelas ini dapat digunakan untuk mengautentikasi layanan ke klien. Dalam contoh ini, token keamanan kartu kredit tidak dapat digunakan untuk mengautentikasi layanan ke klien.Implementasikan properti SupportsClientWindowsIdentity baca-saja. Properti ini mengembalikan
true
jika jenis token keamanan yang diwakili oleh kelas ini dapat dipetakan ke akun Windows. Jika demikian, hasil autentikasi diwakili oleh instans kelas WindowsIdentity. Dalam contoh ini, token tidak dapat dipetakan ke akun Windows.Mengimplementasikan metode CreateKeyIdentifierClause(SecurityToken, SecurityTokenReferenceStyle). Metode ini disebut oleh kerangka kerja keamanan WCF ketika memerlukan referensi ke instance token keamanan yang diwakili oleh kelas parameter token keamanan ini. Baik instans token keamanan aktual dan SecurityTokenReferenceStyle yang menentukan jenis referensi yang diminta diteruskan ke metode ini sebagai argumen. Dalam contoh ini, hanya referensi internal yang didukung oleh token keamanan kartu kredit. Kelas SecurityToken ini memiliki fungsionalitas untuk membuat referensi internal; oleh karena itu, implementasi tidak memerlukan kode tambahan.
Mengimplementasikan metode InitializeSecurityTokenRequirement(SecurityTokenRequirement). Metode ini dipanggil oleh WCF untuk mengonversi instans kelas parameter token keamanan menjadi instans kelas SecurityTokenRequirement. Hasilnya digunakan oleh penyedia token keamanan untuk membuat instans token keamanan yang sesuai.
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
Token keamanan dikirimkan dalam pesan SOAP, ini memerlukan mekanisme terjemahan antara representasi token keamanan dalam memori dan representasi on-the-wire. WCF menggunakan serializer token keamanan untuk menyelesaikan tugas ini. Setiap token kustom harus disertai dengan serializer token keamanan kustom yang dapat menserialisasikan dan mendeserialisasi token keamanan kustom dari pesan SOAP.
Catatan
Kunci turunan diaktifkan secara default. Jika Anda membuat token keamanan kustom dan menggunakannya sebagai token utama, WCF mendapatkan kunci darinya. Saat melakukannya, ini memanggil serializer token keamanan kustom untuk menulis SecurityKeyIdentifierClause untuk token keamanan kustom saat menserialisasikan DerivedKeyToken
ke kawat. Di pihak penerima, saat menghapus serial token dari kabel, pembuat serial DerivedKeyToken
mengharapkan elemen SecurityTokenReference
sebagai turunan tingkat atas di bawahnya sendiri. Jika pembuat serial token keamanan khusus tidak menambahkan elemen SecurityTokenReference
saat membuat serialisasi jenis klausulnya, pengecualian akan dimunculkan.
Untuk membuat pembuat serial token keamanan khusus
Tentukan kelas baru turunan dari kelas WSSecurityTokenSerializer.
Ambil alih metode CanReadTokenCore(XmlReader), yang bergantung pada XmlReader untuk membaca aliran XML. Metode mengembalikan
true
jika implementasi serializer dapat mendeserialisasi token keamanan berdasarkan elemennya saat ini. Dalam contoh ini, metode ini memeriksa apakah elemen XML pembaca XML saat ini memiliki nama elemen dan namespace layanan yang benar. Jika tidak, metode ini memanggil implementasi kelas dasar metode ini untuk menangani elemen XML.Ambil alih metode ReadTokenCore(XmlReader, SecurityTokenResolver). Metode ini membaca konten XML dari token keamanan dan membangun representasi dalam memori yang sesuai untuknya. Jika tidak mengenali elemen XML tempat pembaca XML yang diteruskan siaga, ia memanggil implementasi kelas dasar untuk memproses jenis token yang disediakan sistem.
Ambil alih metode CanWriteTokenCore(SecurityToken). Metode ini mengembalikan
true
jika dapat mengonversi representasi token dalam memori (diteruskan sebagai argumen) ke representasi XML. Jika tidak dapat dikonversi, ini memanggil implementasi kelas dasar.Ambil alih metode WriteTokenCore(XmlWriter, SecurityToken). Metode ini mengonversi representasi token keamanan dalam memori menjadi representasi XML. Jika metode tidak dapat dikonversi, metode memanggil implementasi kelas dasar.
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
Setelah menyelesaikan empat prosedur sebelumnya, integrasikan token keamanan kustom dengan penyedia token keamanan, pengautentikasi, manajer, dan kredensial klien dan layanan.
Untuk mengintegrasikan token keamanan kustom dengan penyedia token keamanan
Penyedia token keamanan membuat, memodifikasi (jika perlu), dan mengembalikan instans token. Untuk membuat penyedia kustom untuk token keamanan kustom, buat kelas yang mewarisi dari kelas SecurityTokenProvider. Contoh berikut mengambil alih metode GetTokenCore untuk mengembalikan instans
CreditCardToken
. Untuk informasi selengkapnya tentang penyedia token keamanan kustom, lihat Cara: Membuat Penyedia Token Keamanan Kustom.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
Untuk mengintegrasikan token keamanan kustom dengan pengautentikasi token keamanan
Pengautentikasi token keamanan memvalidasi konten token keamanan saat diekstrak dari pesan. Untuk membuat pengautentikasi kustom untuk token keamanan kustom, buat kelas yang mewarisi dari kelas SecurityTokenAuthenticator. Contoh berikut mengambil alih metode ValidateTokenCore. Untuk informasi selengkapnya tentang pengautentikasi token keamanan khusus, lihat Cara: Membuat Pengautentikasi Token Keamanan Khusus.
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
Untuk mengintegrasikan token keamanan kustom dengan pengelola token keamanan
Manajer token keamanan membuat penyedia token, pengautentikasi keamanan, dan instans serializer token yang sesuai. Untuk membuat manajer token kustom, buat kelas yang mewarisi dari kelas ClientCredentialsSecurityTokenManager. Metode utama kelas menggunakan SecurityTokenRequirement untuk membuat penyedia dan kredensial klien atau layanan yang sesuai. Untuk informasi selengkapnya tentang pengelola token keamanan kustom, lihat Petunjuk: Membuat Kredensial Klien dan Layanan Khusus.
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
Untuk mengintegrasikan token keamanan kustom dengan klien kustom dan kredensial layanan
Kredensial klien dan layanan kustom harus ditambahkan untuk menyediakan API bagi aplikasi untuk memungkinkan penetapan informasi token kustom yang digunakan oleh infrastruktur token keamanan kustom yang dibuat sebelumnya untuk menyediakan dan mengautentikasi konten token keamanan kustom. Sampel berikut menunjukkan bagaimana hal ini dapat dilakukan. Untuk informasi lebih lanjut tentang klien kustom dan kredensial layanan, lihat Panduan: Membuat Kredensial Klien dan Layanan Kustom.
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
Kelas parameter token keamanan khusus yang dibuat sebelumnya digunakan untuk memberi tahu kerangka kerja keamanan WCF bahwa token keamanan khusus harus digunakan saat berkomunikasi dengan layanan. Prosedur berikut menunjukkan bagaimana hal ini dapat dilakukan.
Untuk mengintegrasikan token keamanan kustom dengan pengikatan
Kelas parameter token keamanan khusus harus ditentukan di salah satu kumpulan parameter token yang diekspos di kelas SecurityBindingElement. Contoh berikut menggunakan kumpulan yang dikembalikan oleh
SignedEncrypted
. Kode menambahkan token kustom kartu kredit ke setiap pesan yang dikirim dari klien ke layanan dengan kontennya yang ditandatangani dan dienkripsi secara otomatis.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
Topik ini menunjukkan berbagai potongan kode yang diperlukan untuk menerapkan dan menggunakan token khusus. Untuk melihat contoh lengkap tentang bagaimana semua bagian kode ini cocok bersama-sama lihat, Token Kustom.
Lihat juga
- SecurityToken
- SecurityTokenParameters
- WSSecurityTokenSerializer
- SecurityTokenProvider
- SecurityTokenAuthenticator
- IAuthorizationPolicy
- SecurityTokenRequirement
- SecurityTokenManager
- ClientCredentials
- ServiceCredentials
- SecurityBindingElement
- Panduan: Membuat Mandat Klien dan Layanan Kustom
- Cara: Membuat Pengautentikasi Token Keamanan Khusus
- Cara: Membuat Penyedia Token Keamanan Kustom