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
}