2

I have written a custom PrincipalPermissionAttribute that uses an AuthenticationService instead of Thread.CurrentPrincipal as PrincipalPermissionAttribute does.

It works as I like, but if the user logs out and back in, or if the user's roles were to change, the attribute code is never called a second time. I suspect I've not informed the attribute it needs to recheck the permission? Breakpoint set on the CreatePermission method only ever hits once.

Is an attribute code only ever evaluated once? The attribute is currently decorating an event handler for a button click on my View's codebehind.

If I change my method back to use the PrincipalPermissionAttribute then it does work as I expect, logging out and back in as a user without the right role throws the SecurityException I expect. Have I missed overriding a property perhaps?

[Serializable]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public sealed class RolePermissionAttribute : CodeAccessSecurityAttribute
{
    private readonly PrincipalPermission _revoke = new PrincipalPermission(PermissionState.None);
    private readonly PrincipalPermission _allow = new PrincipalPermission(PermissionState.Unrestricted);
    private IList<string> _roles;

    private readonly IAuthenticationService _authorisationService;

    public RolePermissionAttribute(SecurityAction action)
        : this(action, ServiceLocator.Current.GetInstance<IAuthenticationService>())
    {
    }

    public RolePermissionAttribute(SecurityAction action, IAuthenticationService authorisationService)
        : base(action)
    {
        _authorisationService = authorisationService;
    }

    public string Roles { get; set; }

    public bool Authenticated { get; set; }

    public override IPermission CreatePermission()
    {
        _roles = (this.Roles ?? string.Empty).Split(',', ';')
                                .Select(s => s.Trim())
                                .Where(s => s.Length > 0)
                                .Distinct()
                                .ToList();

        bool result = false;

        if (_authorisationService != null)
        {
            var principal = _authorisationService.ClientSecurityPrincipal;
            if (principal == null)
            {
                throw new SecurityException("Access Denied. You are not logged in");
            }

            // If Authenticated is enforced then revoke if user is not authenticated
            if (Authenticated && !_authorisationService.IsAuthenticated)
            {
                throw new SecurityException("Access Denied. You are not authenticated");
            }

            // Allow if the principal is in any of the roles
            result = _roles.Any(principal.IsInRole);
            if (!result)
            {
                throw new SecurityException("Access Denied. You are not in an allowed Role");
            }
        }

        return result ? _allow : _revoke;
    }
}

}

Here's the method with the attribute

[RolePermission(SecurityAction.Demand, Authenticated = true, Roles = "Admin")]
private void barButtonItemConfig_ItemClick(object sender, ItemClickEventArgs e)
{
   // Do stuff
}
Stephen Price
  • 1,629
  • 1
  • 24
  • 42

1 Answers1

1

Ok I've figured out how it works. CreatePermission is actually only called once. The IPermission that is returned is the class that checks if the user is in the required role or not.

Because I was returning an unrestricted allow for user A, user B got the same access regardless of their roles.

I need to create my own class that implements IPermission and move my logic into the Demand method. Alternatively (the easier option) assign the Principal from my service to Thread.CurrentPrincipal and use the out of the box PrincipalPermissionAttribute.

Stephen Price
  • 1,629
  • 1
  • 24
  • 42
  • 4
    please if you create it, please provide us with the code because I have similar situation, but I need to create more grained level (Permission-Role-User) and I need to make PrincipalPermissionAttribute to check for Permission instead of Role, so if you have any clue that will be appreciated – Niklaus Wirth Jun 15 '14 at 07:34
  • I have the same problem could you please take a look at this ;https://stackoverflow.com/questions/45770217/my-customauthorizationpolicy-evaluate-method-never-fires – Ehsan Akbar Aug 21 '17 at 07:28