+

Custom claims-based authorization in .NET using Axiomatics PEP SDK for .NET

Implementation of the custom ClaimsAuthorizationManager

The custom authorization manager should derive from ClaimsAuthorizationManager and the only method that must be implemented is CheckAccess. As a result, the simplest, minimal implementation looks like the following:

public class EvilClaimsAuthorizationManager : ClaimsAuthorizationManager
{
    public override bool CheckAccess(AuthorizationContext context)
    {
        // Let us prohibit everything at first
        return false;
    }
}

To make things interesting, we need to introduce actual authorization logic. As mentioned before, this post’s code samples will use the Axiomatics PEP SDK for .NET to send XACML authorization requests to Axiomatics PDP. The context argument of type AuthorizationContext of the CheckAccess method has three sets of claims: Resource, Action and Principal. If you are familiar with XACML (the eXtensible Access Control Markup Language), you might notice that these three sets of claims could be mapped to Resource, Action, and Subject (three types of categories in XACML) respectively. This simplifies the implementation code, as all what we need to do is a near one-to-one mapping or conversion of POCOs to XACML attributes and categories.

private static XacmlDecisionRequest BuildXacmlDecisionRequest(AuthorizationContext context)
{
    // Generic function to convert a given set of claims to a XACML attribute set
    Func<Uri, IEnumerable<Claim>, XacmlAttributes> buildCategory = (category, claims) =>
    {
        var attributes = claims.Select(
            claim => new XacmlAttribute(ToUri(claim.Type), claim.Value, ToUri(claim.ValueType)));

        return new XacmlAttributes(сcategory, attributes);
    };

    // Convert each set of claims and pack to the XACML request
    return new XacmlDecisionRequest
    {
        buildCategory(XacmlConstants.Categories.Action, context.Action),
        buildCategory(XacmlConstants.Categories.Resource, context.Resource),
        buildCategory(XacmlConstants.Categories.Subject, context.Principal.Claims)
    };
}

We now have a valid XACML request: we are ready to evaluate it against the Policy Decision Point (PDP). Let’s modify the ClaimsAuthorizationManager as follows:

public class PdpClaimsAuthorizationManager : ClaimsAuthorizationManager
{
    public override bool CheckAccess(AuthorizationContext context)
    {            
        var request = BuildXacmlDecisionRequest(context);

        // Execute on default IPolicyDecisionPointProvider (requires registration in app.config)
        var result = PolicyDecisionPoint.Evaluate(new XacmlDecisionRequestContext(request));

        // Check that all decisions are permitted
        return result.Decisions.All(x => x.Decision == XacmlDecision.Permit);
    }
}

In this example, to keep things simple, the entire configuration is hardcoded. In a real implementation, you might want to use custom configuration. This is also very simple: just override LoadCustomConfiguration. This MSDN article has good examples.

Registration and usage of the custom ClaimsAuthorizationManager

Custom implementation of the ClaimsAuthorizationManager should be registered in app.config (web.config), to make the custom authorization accessible from all parts of the application.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
       <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
    </configSections>       
    <system.identityModel>
       <identityConfiguration>
           <claimsAuthorizationManager type="ClaimsAuth.PdpClaimsAuthorizationManager, ClaimsAuth"/>
       </identityConfiguration>
    </system.identityModel>
</configuration>

Side note: The system.identityModel section does not get registered by default.

At this point, we have fully implemented and configured the ClaimsAuthorizationManager. Now is a good time to try it out. One of the uses that is interesting is when business logic classes are decorated with special permission attributes in AOP (aspect-oriented programming) style. See the following example:

public static class BankAccountManager
{
    [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Withdraw", Resource = "BankAccountFunds")]
    public static void WithdrawFunds(decimal amount)
    {
        Console.WriteLine("WithdrawFunds: " + amount);
    }
}

The ClaimsPrincipalPermissionAttribute allows declaring claims that are accessible from the CheckAccess method to enable authorization logic for the current user.

Now if you call WithdrawFunds and the CheckAccess method returns false (i.e. if the XACML request leads to a Deny decision), you will get SecurityException back:

"ID4266: Request for ClaimsPrincipalPermission failed for: Action: 'xxx', Resource: 'xxx'."

This could work as effective last barrier protection against unauthorized usage. Another possible scenario is using ClaimsPrincipalPermission directly.

public static void WithdrawFunds(decimal amount)
{
    ClaimsPrincipalPermission.CheckAccess("Withdraw", "BankAccountFunds");
    Console.WriteLine("WithdrawFunds: " + amount);
}

This example will also throw SecurityException if the operation is not authorized. However, in some cases, you might prefer to check if the operation is allowed before execution. It is quite easy: we can always call the ClaimsAuthorizationManager directly:

public static bool CanWithdrawFunds()
{
    return FederatedAuthentication.ClaimsAuthorizationModule.ClaimsAuthorizationManager
        .CheckAccess(new AuthorizationContext(ClaimsPrincipal.Current, "Withdraw", "BankAccountFunds"));
}

Troubleshooting

One of the common exceptions you might get when implementing claims-based authorizations is ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize ---> System.Configuration.ConfigurationErrorsException: Unrecognized configuration section system.identityModel. (C:\Users\...\ClaimsAuth\bin\Debug\ClaimsAuth.exe.Config line 9)

at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal) at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors)

Remember that the system.identityModel section is not registered by default. So you need to register it manually.

General Considerations

In general executing remote calls to perform authorization from ClaimsAuthorizationManager should be taken with caution. The following list highlights some considerations you should take into account:

  1. Performance: if each call to the method will issue a remote call, you may end up with thousands of authorization calls per request. So, think about scale!
  2. Debugging: you will have a remote call executed instead of a simple method call.
  3. Exceptions: there is no indication on the method signature that it will trigger a remote call, so the developer might only expect “usual” exceptions e.g. SqlException, but in fact you can get unexpected exceptions from the custom ClaimsAuthorizationManager.

Overall, decoupling authorization from business logic brings about more benefits. It reduces the code developers need to write and is easier to maintain.

One suggestion is to run authorization checks once per request. For example if you have a SOAP Service (WCF Service), you can easily enforce permissions for each operation. A similar practice could apply for ASP.NET MVC Controller Actions authorization.

Another suggestion is to use local authorization engines. For example, Axiomatics provides an Embedded PDP for .NET, so all execution is done in-process and avoids any network overhead and latency.

Conclusion

In this post, we implemented XACML authorization for .NET claims-based identity model. The Identity Model provides extension points which makes it easy to integrate with third-party authorization engines: it becomes quite easy to implement and test such integrations. Further posts will cover federated authentication, where claims for principal can be retrieved from different security token services (STS). Additional possible topics include integration with WCF and ASP.NET. So, stay tuned!

This post just covered the most basic scenarios. There are plenty of other possibilities, a few of which we hope to cover in future posts.

The Entire Code Snippet

You can download the full project below. {rsfiles path=”blogposts/Custom claims-based authorization in .NET using Axiomatics PEP SDK.zip”}

To run it, the Axiomatics PEP SDK for .NET libraries must be installed, as per explaination in the PEP SDK Documentation.

Related Articles

Meeting today’s dynamic authorization and access challenges: The Axiomatics story | Dynamically Speaking
Dynamically Speaking
For more than 15 years, Axiomatics has worked with companies worldwide to define and deliver solutions to the most complex authorization and access challenge. In...
Getting started with Zero Trust using dynamic authorization | Dynamically Speaking
Dynamically Speaking
Zero Trust. It’s everywhere. It’s a methodology that’s been around for years, and we are now seeing a significant uptick in the number of enterprises...
The case for dynamic authorization in banking and finance
Attribute Based Access Control (ABAC)
More than other organizations, banks, and financial institutions face the highest levels of scrutiny when it comes to how they protect critical assets and sensitive...