Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Our old software architecture used role based validation. We now want to use claims based authorization. As a matter of fact, I think we always used something modelling claims, even if we used role base technology.

The lowest level are Privileges. A privilege may be "invoke the user service adding a user" or short "UserService.Add". Privileges can be assigned to groups. Users can be members of groups. In the end, through group membership, a user can have a list of privileges.

The old system used a combination of UserNamePasswordValidator, IAuthorizationPolicy and CodeAccessSecurityAttribute to have attributes that were written above the service method and on call of the service method, the validity would be checked. If the user didn't have the required privilege, access would be denied. Worked great.

[CompanyRoleRequired(SecurityAction.Demand, Role = "Common.Connect")]
[CompanyRoleRequired(SecurityAction.Demand, Role = "SomeServiceName.Save")]
public void Save(IEnumerable<Data> data)
{
  // code
}

Now I'd like to use claims based authorization. Keeping the model above, I would create either a claim for each former privilege, or maybe a claim for each service with valid values of it's operations. For example, instead of "UserService.Add" I could add a claim "UserService" and people with the former privilege would get the claim with the value "Add". I would like to offer the service developers the same ease of access checking, so I'd like the required claims to be annotated above the service method. Microsoft already provides a ClaimsPrincipalPermissionAttribute for this.

Instead of implementing IAuthorizationPolicy, I implemented ClaimsAuthorizationManager.

Question 1) The authorization manager gets called twice. Once with the soap url and once with my attribute. I've googled a lot and it seems to be by design. I don't have a problem differentiating between the calls and checking only my calls, but maybe I didn't see something. Is there an option or an easy way to not get called on soap calls with the urls and only getting called for the attributes?

Question 2) The access check offers the ability to check if the pricipal has a claim. Obviously, a claim has a type/name and a value. I would have expected the attribute to offer such an interface. However, the attribute wants to know about the resource and operation. The access check function I need to overwrite also needs to check resources and operations. Why is that? Do I need to map resource/operation to claims in my AuthorizationManager? And if I don't see any need for it, would it be ok to just put the expected type and value of the claim in the attribute as resource and operation and map them 1:1 in the authorization manager? Or do I miss out on some important security feature if I do this?

share|improve this question
1  
BTW why you are using old Microsoft.IdentityModel namespace instead of new 4.5 System.Security.Claims? msdn.microsoft.com/en-us/library/… have a sample for CheckAcess method with policy in config file – Danila Polevshikov Mar 8 at 11:39
Sorry, my link was wrong. I'm using the exact class you posted, it even features the resource/action model I'm talking about in the middle of the page. I edited the links in my question. – nvoigt Mar 8 at 11:49

2 Answers

up vote 4 down vote accepted
+50

Q1) That's unfortunately the case - and since both the "automatic" calls and the attribute/.CheckAccess use the same claim types you cannot easily distinguish between the two. I wrote about that here: http://leastprivilege.com/2011/04/30/what-i-dont-like-about-wifs-claims-based-authorization/

Q2) You are missing the concept here. The idea is to NOT check for specific claims - but to rather annotate the code with "what you are doing". The person that writes the business code typically does not know exactly who is allowed to call it (or which claims are exactly needed). You only tell the authZ poliy that you are about to add a customer (as an example). The authorization manager's job is to figure out if the principal is authorized to do that (by whatever means). Separation of concerns. See here: http://leastprivilege.com/2011/04/30/what-i-like-about-wifs-claims-based-authorization/

share|improve this answer
Thanks a lot, your blog is really helpful. – nvoigt Mar 14 at 9:59

Not sure if this is going to be helpful to you but ClaimsAuthorizationManager has method that can be overridden (LoadCustomConfiguration) that you can use to load your policy from XML file. That policy might be designed in a way to allow mapping between resources and actions and roles. I've built in-code access control list instead that looks like this:

public interface IAccessControlList
{
   List<CustomAccessRule> Rules { get; }
}

public class CustomAccessRule
{
    public string Operation { get; set; }
    public List<string> Roles { get; set; }

    public CustomAccessRule(string operation, params string[] roles)
    {
        Operation = operation;
        Roles = roles.ToList();
    }
}

My claims authorization manager looks like this:

public class CustomClaimsAuthorizationManager : ClaimsAuthorizationManager
{
    private IAccessControlList _accessControlList;

    public CustomClaimsAuthorizationManager(IAccessControlList accessControlList)
    {
        _accessControlList = accessControlList;
    }

    public override bool CheckAccess(AuthorizationContext context)
    {
        string operation = context.Action.First().Value.Split('/').Last();
        CustomAccessRule rule = _accessControlList.Rules.FirstOrDefault(x => x.Operation == operation);
        if (rule == null) return true;
        if (context.Principal.Identities.First().IsInRoles(rule.Roles)) return true;
        throw new MessageSecurityException(string.Format("Username {0} does not have access to operation {1}.", context.Principal.Identities.First().Name, operation));
    }

}

And here is an example of one access control list implementation for one service:

public class SampleServiceACL : IAccessControlList
{
    public List<CustomAccessRule> Rules { get; private set; }

    public SampleServiceACL()
    {
        Rules = new List<CustomAccessRule>();
        Rules.Add(new CustomAccessRule("OpenAccount", "Manager", "Owner"));
        Rules.Add(new CustomAccessRule("CloseAccount", "Manager", "Owner"));
        Rules.Add(new CustomAccessRule("SendEmail", "User", "Manager", "Owner"));
    }
}

And I'm applying this at service host base level by using:

    protected override void OnOpening()
    {
        base.OnOpening();

        IdentityConfiguration identityConfiguration = new IdentityConfiguration();
        identityConfiguration.SecurityTokenHandlers.Clear();
        identityConfiguration.ClaimsAuthorizationManager = new CustomClaimsAuthorizationManager(new SampleServiceACL());
        this.Credentials.IdentityConfiguration = identityConfiguration;

        ...
    }

As a result, I'm not using attributes at all, all authorization logic is centralized in claims authorization manager over ACL.

Now if you don't like this approach, and you're still in pursuit of attribute that will check for specific claims, you can then derive from CodeAccessSecurityAttribute and actually implement that logic. What is given by MS out of the box is good, but it does not mean you should stick to it by any means. Also logic for checking the claims can be implemented as an extension to identity, i.e.:

public static class IdentityExtensions
{
    public static bool IsInRoles(this ClaimsIdentity id, List<string> roles)
    {
        foreach (string role in roles)
            if (id.HasClaim(ClaimTypes.Role, role)) return true;
        return false;
    }
}

So you might build extensions, custom attribute, and then use extensions in the attribute to perform your validation logic.

Again, this is just something that I've already done. Might not be what you're looking for but it's one type of custom solution.

share|improve this answer
Thanks for your answer, I wish I could select more than one answer or bounty. – nvoigt Mar 14 at 10:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.