How to: Create a Custom Authorization Manager for a Service
Article
The Identity Model infrastructure in Windows Communication Foundation (WCF) supports an extensible claims-based authorization model. Claims are extracted from tokens and optionally processed by custom authorization policies and then placed into an AuthorizationContext. An authorization manager examines the claims in the AuthorizationContext to make authorization decisions.
By default, authorization decisions are made by the ServiceAuthorizationManager class; however these decisions can be overridden by creating a custom authorization manager. To create a custom authorization manager, create a class that derives from ServiceAuthorizationManager and implement CheckAccessCore method. Authorization decisions are made in the CheckAccessCore method, which returns true when access is granted and false when access is denied.
If the authorization decision depends on the contents of the message body, use the CheckAccess method.
Because of performance issues, if possible you should redesign your application so that the authorization decision does not require access to the message body.
Registration of the custom authorization manager for a service can be done in code or configuration.
The following code example uses the FindClaims(String, String) method to find the custom claim http://www.contoso.com/claims/allowedoperation to make an authorization decision.
protected override bool CheckAccessCore(OperationContext operationContext)
{
// Extract the action URI from the OperationContext. Match this against the claims
// in the AuthorizationContext.
string action = operationContext.RequestContext.RequestMessage.Headers.Action;
// Iterate through the various claim sets in the AuthorizationContext.
foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
{
// Examine only those claim sets issued by System.
if (cs.Issuer == ClaimSet.System)
{
// Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
foreach (Claim c in cs.FindClaims("http://www.contoso.com/claims/allowedoperation", Rights.PossessProperty))
{
// If the Claim resource matches the action URI then return true to allow access.
if (action == c.Resource.ToString())
return true;
}
}
}
// If this point is reached, return false to deny access.
return false;
}
Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean
' Extract the action URI from the OperationContext. Match this against the claims.
' in the AuthorizationContext.
Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action
' Iterate through the various claimsets in the AuthorizationContext.
Dim cs As ClaimSet
For Each cs In operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
' Examine only those claim sets issued by System.
If cs.Issuer Is ClaimSet.System Then
' Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
Dim c As Claim
For Each c In cs.FindClaims("http://www.contoso.com/claims/allowedoperation", _
Rights.PossessProperty)
' If the Claim resource matches the action URI then return true to allow access.
If action = c.Resource.ToString() Then
Return True
End If
Next c
End If
Next cs
' If this point is reached, return false to deny access.
Return False
End Function
To register a custom authorization manager using code
Create an instance of the custom authorization manager and assign it to the ServiceAuthorizationManager property.
The following code example registers the MyServiceAuthorizationManager custom authorization manager.
// Add a custom authorization manager to the service authorization behavior.
serviceHost.Authorization.ServiceAuthorizationManager =
new MyServiceAuthorizationManager();
' Add a custom authorization manager to the service authorization behavior.
serviceHost.Authorization.ServiceAuthorizationManager = _
New MyServiceAuthorizationManager()
To register a custom authorization manager using configuration
To the <serviceAuthorization>, add a serviceAuthorizationManagerType attribute and set its value to the type that represents the custom authorization manager.
Add a binding that secures the communication between the client and service.
The binding that is chosen for this communication determines the claims that are added to the AuthorizationContext, which the custom authorization manager uses to make authorization decisions. For more details about the system-provided bindings, see System-Provided Bindings.
Associate the behavior to a service endpoint, by adding a <service> element and set the value of the behaviorConfiguration attribute to the value of the name attribute for the <behavior> element.
Note that when you specify the serviceAuthorizationManagerType, the string must contain the fully qualified type name. a comma, and the name of the assembly in which the type is defined. If you leave out the assembly name, WCF will attempt to load the type from System.ServiceModel.dll.
public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
// Extract the action URI from the OperationContext. Match this against the claims
// in the AuthorizationContext.
string action = operationContext.RequestContext.RequestMessage.Headers.Action;
// Iterate through the various claim sets in the AuthorizationContext.
foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
{
// Examine only those claim sets issued by System.
if (cs.Issuer == ClaimSet.System)
{
// Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
foreach (Claim c in cs.FindClaims("http://www.contoso.com/claims/allowedoperation", Rights.PossessProperty))
{
// If the Claim resource matches the action URI then return true to allow access.
if (action == c.Resource.ToString())
return true;
}
}
}
// If this point is reached, return false to deny access.
return false;
}
}
Public Class MyServiceAuthorizationManager
Inherits ServiceAuthorizationManager
Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean
' Extract the action URI from the OperationContext. Match this against the claims.
' in the AuthorizationContext.
Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action
' Iterate through the various claimsets in the AuthorizationContext.
Dim cs As ClaimSet
For Each cs In operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
' Examine only those claim sets issued by System.
If cs.Issuer Is ClaimSet.System Then
' Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
Dim c As Claim
For Each c In cs.FindClaims("http://www.contoso.com/claims/allowedoperation", _
Rights.PossessProperty)
' If the Claim resource matches the action URI then return true to allow access.
If action = c.Resource.ToString() Then
Return True
End If
Next c
End If
Next cs
' If this point is reached, return false to deny access.
Return False
End Function
End Class