How to: Create a Custom Authorization Manager for a Service

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.

To create a custom authorization manager

  1. Derive a class from the ServiceAuthorizationManager class.

    Public Class MyServiceAuthorizationManager
        Inherits ServiceAuthorizationManager
    
    
    public class MyServiceAuthorizationManager : ServiceAuthorizationManager
    {
    
  2. Override the CheckAccessCore method.

    Use the OperationContext that is passed to the CheckAccessCore method to make authorization decisions.

    The following code example uses the FindClaims method to find the custom claim https://www.contoso.com/claims/allowedoperation to make an authorization decision.

    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 "https://www.contoso.com/claims/allowedoperation".
                Dim c As Claim
                For Each c In  cs.FindClaims("https://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 
    
    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 "https://www.contoso.com/claims/allowedoperation".
            foreach (Claim c in cs.FindClaims("https://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;                 
    }
    

To register a custom authorization manager using code

  1. Create an instance of the custom authorization manager and assign it to the ServiceAuthorizationManager property.

    The ServiceAuthorizationBehavior can be accessed using Authorization 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

  1. Open the configuration file for the service.

  2. Add a serviceAuthorization element to the Behaviors element.

    To the serviceAuthorization element, add a serviceAuthorizationManagerType attribute and set its value to the type that represents the custom authorization manager.

  3. 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.

  4. 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> of <serviceBehaviors> element.

    For more information about configuring a service endpoint, see How to: Create a Service Endpoint in Configuration.

    The following code example registers the custom authorization manager Samples.MyServiceAuthorizationManager.

    <configuration>
      <system.serviceModel>
        <services>
          <service 
              name="Microsoft.ServiceModel.Samples.CalculatorService"
              behaviorConfiguration="CalculatorServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="https://localhost:8000/ServiceModelSamples/service"/>
              </baseAddresses>
            </host>
            <endpoint address=""
                      binding="wsHttpBinding_Calculator"
                      contract="Microsoft.ServiceModel.Samples.ICalculator" />
          </service>
        </services>
        <bindings>
          <WSHttpBinding>
           <binding name = "wsHttpBinding_Calculator">
             <security mode="Message">
               <message clientCredentialType="Windows"/>
             </security>
            </binding>
          </WSHttpBinding>
    </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior name="CalculatorServiceBehavior">
              <serviceAuthorization serviceAuthorizationManagerType="Samples.MyServiceAuthorizationManager" />
            </behaviors>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    

Example

The following code example demonstrates a basic implementation of a ServiceAuthorizationManager class that includes overriding the CheckAccessCore method. The example code examines the AuthorizationContext for a custom claim and returns true when the resource for that custom claim matches the action value from the OperationContext. For a more complete implementation of a ServiceAuthorizationManager class, see Authorization Policy Sample.

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 "https://www.contoso.com/claims/allowedoperation".
                Dim c As Claim
                For Each c In  cs.FindClaims("https://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 
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 "https://www.contoso.com/claims/allowedoperation".
          foreach (Claim c in cs.FindClaims("https://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;                 
  }
}

See Also

Reference

ServiceAuthorizationManager

Other Resources

How To: Compare Claims
Authorization Policy Sample


© 2007 Microsoft Corporation. All rights reserved.
Build Date: 2009-08-07