Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
The identity feature of Windows Communication Foundation (WCF) enables a client to specify in advance the expected identity of the service. Whenever a server authenticates itself to the client, the identity is checked against the expected identity. (For an explanation of identity and how it works, see Service Identity and Authentication.)
If needed, the verification can be customized using a custom identity verifier. For example, you can perform additional service identity verification checks. In this example, the custom identity verifier checks additional claims in the X.509 certificate returned from the server. For a sample application, see Service Identity Sample.
Define a new class that derives from the EndpointIdentity class. This example names the extension OrgEndpointIdentity
.
Add private members along with properties that will be used by the extended IdentityVerifier class to perform the identity check against claims in the security token returned from the service. This example defines one property: the OrganizationClaim
property.
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
Define a new class that derives from IdentityVerifier. This example names the 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
Override the CheckAccess method. The method determines whether the identity check succeeded or failed.
The CheckAccess
method has two parameters. The first is an instance of the EndpointIdentity class. The second is an instance of the AuthorizationContext class.
In the method implementation, examine the collection of claims returned by the ClaimSets property of the AuthorizationContext class, and perform authentication checks as required. This example begins by finding any claim that is of type "Distinguished Name" and then compares the name to the extension of the 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
Implement the TryGetIdentity method, which determines whether an instance of the EndpointIdentity class can be returned by the client. The WCF infrastructure calls the implementation of the TryGetIdentity
method first to retrieve the service's identity from the message. Next, the infrastructure calls the CheckAccess
implementation with the returned EndpointIdentity
and AuthorizationContext.
In the TryGetIdentity
method, put the following code:
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
Create a method that returns a Binding object. This example begins creates an instance of the WSHttpBinding class and sets its security mode to Message, and its ClientCredentialType to None.
Create a BindingElementCollection using the CreateBindingElements method.
Return the SecurityBindingElement from the collection and cast it to a SymmetricSecurityBindingElement variable.
Set the IdentityVerifier property of the LocalClientSecuritySettings class to a new instance of the CustomIdentityVerifier
class created previously.
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
The custom binding that is returned is used to create an instance of the client and class. The client can then perform a custom identity verification check of the service as shown in the following code.
using (CalculatorClient client = new CalculatorClient(customSecurityBinding, serviceAddress))
{
Using client As New CalculatorClient(customSecurityBinding, serviceAddress)
The following example shows a complete implementation of the IdentityVerifier class.
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
The following example shows a complete implementation of the EndpointIdentity class.
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
Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowTraining
Module
Describe the concepts behind Microsoft Entra Verified ID - Training
Describe the core concepts behind Microsoft Entra Verified ID. Gain an understanding of decentralized identifiers and how they're used to issue and verify credentials.
Certification
Microsoft Certified: Identity and Access Administrator Associate - Certifications
Demonstrate the features of Microsoft Entra ID to modernize identity solutions, implement hybrid solutions, and implement identity governance.
Documentation
<serviceCertificate> of <clientCredentials> Element - .NET Framework
Learn more about: of Element
Learn more about:
<userNameAuthentication> - .NET Framework
Learn more about:
Learn more about: Service Identity Sample