Procedura: creare un verificatore di identità client personalizzato
La funzionalità di identità di Windows Communication Foundation (WCF) consente a un client di specificare in anticipo l'identità prevista del servizio. Ogni volta che un server esegue l'autenticazione al client, l'identità viene confrontata con l'identità prevista. Per una spiegazione dell'identità e del relativo funzionamento, vedere Identità del servizio e autenticazione.
Se necessario, la verifica può essere personalizzata usando un verificatore di identità personalizzato. È possibile, ad esempio, eseguire ulteriori controlli di verifica dell'identità del servizio. In questo esempio il verificatore di identità personalizzato verifica le attestazioni aggiuntive nel certificato X.509 restituito dal server. Per un'applicazione di esempio, vedere Esempio di identità del servizio.
Per estendere la classe EndpointIdentity
Definire una nuova classe che deriva dalla classe EndpointIdentity. Questo esempio attribuisce un nome all'estensione
OrgEndpointIdentity
.Aggiungere membri privati insieme a proprietà che verranno usate dalla classe IdentityVerifier estesa per eseguire il controllo dell'identità rispetto alle attestazioni incluse nel token di sicurezza restituito dal servizio. Questo esempio definisce una proprietà, ovvero
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
Per estendere la classe IdentityVerifier
Definire una nuova classe che deriva dall'interfaccia IdentityVerifier. Questo esempio attribuisce un nome all'estensione
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
Eseguire l'override del metodo CheckAccess. Il metodo determina se il controllo dell'identità ha esito positivo o negativo.
Il metodo
CheckAccess
ha due parametri. Il primo è un'istanza della classe EndpointIdentity. Il secondo è un'istanza della classe AuthorizationContext.Nell'implementazione del metodo, esaminare la raccolta di attestazioni restituita dalla proprietà ClaimSets della classe AuthorizationContext ed eseguire i controlli di autenticazione necessari. Questo esempio inizia cercando qualsiasi attestazione di tipo "Nome distinto" e confronta quindi il nome all'estensione della classe 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
Per implementare il metodo TryGetIdentity
Implementare il metodo TryGetIdentity che determina se un'istanza della classe EndpointIdentity può essere restituita dal client. L'infrastruttura di WCF chiama prima l'implementazione del metodo
TryGetIdentity
per recuperare l'identità del servizio dal messaggio. L'infrastruttura chiama quindi l'implementazioneCheckAccess
con le classiEndpointIdentity
e AuthorizationContext restituite.Nel metodo
TryGetIdentity
inserire il seguente codice: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
Per implementare un'associazione personalizzata e impostare il verificatore di identità personalizzato
Creare un metodo che restituisca un oggetto Binding. Questo esempio inizia con la creazione di un'istanza della classe WSHttpBinding e imposta la propria modalità di sicurezza su Messagee la propria proprietà ClientCredentialType su None.
Creare una classe BindingElementCollection usando il metodo CreateBindingElements.
Restituire la classe SecurityBindingElement dalla raccolta ed eseguirne il cast su una variabile SymmetricSecurityBindingElement.
Imposta la proprietà IdentityVerifier della classe LocalClientSecuritySettings su una nuova istanza della classe
CustomIdentityVerifier
creata precedentemente.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
L'associazione personalizzata restituita viene usata per creare un'istanza del client e della classe. Il client può eseguire quindi un controllo di verifica dell'identità del servizio personalizzato, come illustrato nel codice seguente.
using (CalculatorClient client = new CalculatorClient(customSecurityBinding, serviceAddress)) {
Using client As New CalculatorClient(customSecurityBinding, serviceAddress)
Esempio 1
Nell'esempio seguente viene illustrata un'implementazione completa della 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
Esempio 2
Nell'esempio seguente viene illustrata un'implementazione completa della 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