Procédure : créer un vérificateur d’identité du client personnalisé
La fonctionnalité d’identité de Windows Communication Foundation (WCF) active un client pour spécifier à l’avance l’identité attendue du service. Lorsqu'un serveur s'authentifie auprès du client, l'identité est vérifiée par rapport à l'identité attendue. (Pour obtenir une explication de l’identité et de son fonctionnement, consultez Identité du service et authentification.)
Si nécessaire, la vérification peut être personnalisée à l'aide d'un vérificateur d'identité personnalisé. Par exemple, vous pouvez effectuer des contrôles supplémentaires de vérification de l'identité du service. Dans cet exemple, le vérificateur d'identité personnalisé vérifie des revendications supplémentaires dans le certificat X.509 retourné par le serveur. Pour obtenir un exemple d’application, consultez l’exemple d’identité de service.
Pour étendre la classe EndpointIdentity
Définissez une nouvelle classe dérivée de la classe EndpointIdentity. Cet exemple nomme l'extension
OrgEndpointIdentity
.Ajoutez les membres privés avec les propriétés qui seront utilisées par la classe IdentityVerifier étendue pour exécuter le contrôle d'identité par rapport aux revendications dans le jeton de sécurité retourné par le service. Cet exemple définit une propriété : la propriété
OrganizationClaim
.public class OrgEndpointIdentity : EndpointIdentity { private string orgClaim; public OrgEndpointIdentity(string orgName) { orgClaim = orgName; } public string OrganizationClaim { get { return orgClaim; } set { orgClaim = value; } } }
Public Class OrgEndpointIdentity Inherits EndpointIdentity Private orgClaim As String Public Sub New(ByVal orgName As String) orgClaim = orgName End Sub Public Property OrganizationClaim() As String Get Return orgClaim End Get Set(ByVal value As String) orgClaim = value End Set End Property End Class
Pour étendre la classe IdentityVerifier
Définissez une nouvelle classe dérivée de IdentityVerifier. Cet exemple nomme l'extension
CustomIdentityVerifier
.public class CustomIdentityVerifier : IdentityVerifier { // Code to be added. public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext) { throw new Exception("The method or operation is not implemented."); } public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity) { throw new Exception("The method or operation is not implemented."); } }
Public Class CustomIdentityVerifier Inherits IdentityVerifier ' Code to be added. Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _ ByVal authContext As AuthorizationContext) As Boolean Throw New Exception("The method or operation is not implemented.") End Function Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _ <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean Throw New Exception("The method or operation is not implemented.") End Function End Class
Remplacez la méthode CheckAccess . La méthode détermine si le contrôle d'identité a réussi ou a échoué.
La méthode
CheckAccess
possède deux paramètres. Le premier est une instance de la classe EndpointIdentity. Le second est une instance de la classe AuthorizationContext.Dans l'implémentation de méthode, examinez la collection de revendications retournée par la propriété ClaimSets de la classe AuthorizationContext et exécutez des contrôles d'authentification selon les besoins. Cet exemple commence par rechercher les revendications de type « Distinguished Name » puis compare le nom à l’extension du EndpointIdentity (
OrgEndpointIdentity
).public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext) { bool returnvalue = false; foreach (ClaimSet claimset in authContext.ClaimSets) { foreach (Claim claim in claimset) { if (claim.ClaimType == "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname") { X500DistinguishedName name = (X500DistinguishedName)claim.Resource; if (name.Name.Contains(((OrgEndpointIdentity)identity).OrganizationClaim)) { Console.WriteLine("Claim Type: {0}", claim.ClaimType); Console.WriteLine("Right: {0}", claim.Right); Console.WriteLine("Resource: {0}", claim.Resource); Console.WriteLine(); returnvalue = true; } } } } return returnvalue; }
Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _ ByVal authContext As AuthorizationContext) As Boolean Dim returnvalue = False For Each claimset In authContext.ClaimSets For Each claim In claimset If claim.ClaimType = "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname" Then Dim name = CType(claim.Resource, X500DistinguishedName) If name.Name.Contains((CType(identity, OrgEndpointIdentity)).OrganizationClaim) Then Console.WriteLine("Claim Type: {0}", claim.ClaimType) Console.WriteLine("Right: {0}", claim.Right) Console.WriteLine("Resource: {0}", claim.Resource) Console.WriteLine() returnvalue = True End If End If Next claim Next claimset Return returnvalue End Function
Pour implémenter la méthode TryGetIdentity
Implémentez la méthode TryGetIdentity qui détermine si une instance de la classe EndpointIdentity peut être retournée par le client. L’infrastructure WCF appelle d’abord l’implémentation de la méthode
TryGetIdentity
pour récupérer l’identité du service à partir du message. Ensuite, l'infrastructure appelle l'implémentationCheckAccess
avec lesEndpointIdentity
et AuthorizationContext retournés.Dans la méthode
TryGetIdentity
, insérez le code suivant :public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity) { return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity); }
Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _ <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean Return IdentityVerifier.CreateDefault().TryGetIdentity(reference, identity) End Function
Pour implémenter une liaison personnalisée et définir l'IdentityVerifier personnalisé
Créez une méthode qui retourne un objet Binding. Cet exemple commence par créer une instance de la classe WSHttpBinding et affecte à son mode de sécurité la valeur Message, et à son ClientCredentialType la valeur None.
Créez un BindingElementCollection à l'aide de la méthode CreateBindingElements.
Retournez le SecurityBindingElement de la collection et effectuez un cast en une variable SymmetricSecurityBindingElement.
Affectez à la propriété IdentityVerifier de la classe LocalClientSecuritySettings une nouvelle instance de la classe
CustomIdentityVerifier
créée précédemment.public static Binding CreateCustomSecurityBinding() { WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message); //Clients are anonymous to the service. binding.Security.Message.ClientCredentialType = MessageCredentialType.None; //Secure conversation is turned off for simplification. If secure conversation is turned on, then //you also need to set the IdentityVerifier on the secureconversation bootstrap binding. binding.Security.Message.EstablishSecurityContext = false; // Get the SecurityBindingElement and cast to a SymmetricSecurityBindingElement to set the IdentityVerifier. BindingElementCollection outputBec = binding.CreateBindingElements(); SymmetricSecurityBindingElement ssbe = (SymmetricSecurityBindingElement)outputBec.Find<SecurityBindingElement>(); //Set the Custom IdentityVerifier. ssbe.LocalClientSettings.IdentityVerifier = new CustomIdentityVerifier(); return new CustomBinding(outputBec); }
Public Shared Function CreateCustomSecurityBinding() As Binding Dim binding As New WSHttpBinding(SecurityMode.Message) With binding.Security.Message 'Clients are anonymous to the service. .ClientCredentialType = MessageCredentialType.None 'Secure conversation is turned off for simplification. If secure conversation is turned on, then 'you also need to set the IdentityVerifier on the secureconversation bootstrap binding. .EstablishSecurityContext = False End With ' Get the SecurityBindingElement and cast to a SymmetricSecurityBindingElement to set the IdentityVerifier. Dim outputBec = binding.CreateBindingElements() Dim ssbe = CType(outputBec.Find(Of SecurityBindingElement)(), SymmetricSecurityBindingElement) 'Set the Custom IdentityVerifier. ssbe.LocalClientSettings.IdentityVerifier = New CustomIdentityVerifier() Return New CustomBinding(outputBec) End Function
La liaison personnalisée retournée est utilisée pour créer une instance du client et de la classe. Le client peut effectuer ensuite une vérification personnalisée de l'identité du service comme indiqué dans le code suivant.
using (CalculatorClient client = new CalculatorClient(customSecurityBinding, serviceAddress)) {
Using client As New CalculatorClient(customSecurityBinding, serviceAddress)
Exemple 1
L'exemple suivant illustre une implémentation complète de la classe IdentityVerifier.
class CustomIdentityVerifier : IdentityVerifier
{
public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
{
bool returnvalue = false;
foreach (ClaimSet claimset in authContext.ClaimSets)
{
foreach (Claim claim in claimset)
{
if (claim.ClaimType == "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname")
{
X500DistinguishedName name = (X500DistinguishedName)claim.Resource;
if (name.Name.Contains(((OrgEndpointIdentity)identity).OrganizationClaim))
{
Console.WriteLine("Claim Type: {0}", claim.ClaimType);
Console.WriteLine("Right: {0}", claim.Right);
Console.WriteLine("Resource: {0}", claim.Resource);
Console.WriteLine();
returnvalue = true;
}
}
}
}
return returnvalue;
}
public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
{
return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity);
}
}
Friend Class CustomIdentityVerifier
Inherits IdentityVerifier
Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _
ByVal authContext As AuthorizationContext) As Boolean
Dim returnvalue = False
For Each claimset In authContext.ClaimSets
For Each claim In claimset
If claim.ClaimType = "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname" Then
Dim name = CType(claim.Resource, X500DistinguishedName)
If name.Name.Contains((CType(identity, OrgEndpointIdentity)).OrganizationClaim) Then
Console.WriteLine("Claim Type: {0}", claim.ClaimType)
Console.WriteLine("Right: {0}", claim.Right)
Console.WriteLine("Resource: {0}", claim.Resource)
Console.WriteLine()
returnvalue = True
End If
End If
Next claim
Next claimset
Return returnvalue
End Function
Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _
<System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean
Return IdentityVerifier.CreateDefault().TryGetIdentity(reference, identity)
End Function
End Class
Exemple 2
L'exemple suivant illustre une implémentation complète de la classe EndpointIdentity.
public class OrgEndpointIdentity : EndpointIdentity
{
private string orgClaim;
public OrgEndpointIdentity(string orgName)
{
orgClaim = orgName;
}
public string OrganizationClaim
{
get { return orgClaim; }
set { orgClaim = value; }
}
}
Public Class OrgEndpointIdentity
Inherits EndpointIdentity
Private orgClaim As String
Public Sub New(ByVal orgName As String)
orgClaim = orgName
End Sub
Public Property OrganizationClaim() As String
Get
Return orgClaim
End Get
Set(ByVal value As String)
orgClaim = value
End Set
End Property
End Class