In my previous post, I was using PrincipalPermissionAttribute, the limitation of this solution is, developers have to hardcode the authorized role list into code. To improve it, we can call Demand() method explicitly.
// WCF Service
public void DeleteEmailRole(EmailRoleDto emailRoleDto)
{
// Will throw SecurityException and then WCF will convert it to SecurityAccessDeniedException
// to WCF client side, so we don't need add SecurityException to Contract, because it will not be
// caught as FaultException.
AuthorizationChecker.CheckPermissionForCurrentUserOn("DeleteEmailRole");
EmailService.Delete(emailRoleDto);
}
public class AuthorizationChecker : IAuthorizationChecker
{
private readonly IAuthRoleRepository _authRoleRepository;
public AuthorizationChecker(IAuthRoleRepository authRoleRepository)
{
_authRoleRepository = authRoleRepository;
}
/// <summary>
/// Can be used by UI to enable/disable buttons/menus.
/// </summary>
public bool IsCurrentUserAllowedTo(string serviceName)
{
try
{
CheckPermissionForCurrentUserOn(serviceName);
}
catch (SecurityException)
{
return false;
}
return true;
}
public void CheckPermissionForCurrentUserOn(string serviceName)
{
IPermission permissionSet = null;
foreach (var role in
_authRoleRepository.FetchAllRolesHavingAccessTo(serviceName))
{
var permission = new PrincipalPermission(null, role);
permissionSet = permissionSet == null ? permission : permissionSet.Union(permission);
}
// Demand will throw Security exception if user has no permission defined in authRoleRepository.
if (permissionSet != null) permissionSet.Demand();
}
}
// Client code
protected void HandleException(Exception e)
{
if (e is SecurityAccessDeniedException)
{
_messageBox.Show("Sorry you don't have permission to this method.\n" + e.Message);
throw e;
}
}