WPF Command and claim/role based security

In the company I work (Reasult) we use Windows Identity Foundation (WIF) for claim based security in our software. By specifying the RoleClaimType you can indicate which claims are representing the user’s roles. With the general Thread.CurrentPrincipal.IsInRole method you can check if the current user has one of those roles. The roles are used in the WPF application to check if an user is allowed to execute a certain action. Most of the time those actions are WPF Commands.

We were looking for a nice and clean way to specify which role an user must have to execute a certain Command. Therefore we created a custom attribute which can be set on the Execute method of a Command. In this AuthorizationAttribute you can specify which role the user must have so he is allowed to execute the action.

[AttributeUsage(AttributeTargets.Method)]
public class AuthorizationAttribute : Attribute
{
    public AuthorizationAttribute()
    {

    }

    public AuthorizationAttribute(AuthorizationType authorizationType, string role)
    {
        AuthorizationType = authorizationType;
        Role = role;
    }

    public string Role { get; set; }
    public AuthorizationType AuthorizationType { get; set; }
}

The AuthorizationAttribute has two properties. A Role property for specifying the role and an AuthorizationType property (enum) which indicates if you must have the role (Allow) or the user must not have that role (Deny).

The AuthorizationAttribute can be used in the ViewModel on the Execute method of the Command. The type of command we are using is a relay/delegate command. For an explanation what a relay command is read the following article of Josh Smith WPF Apps With The Model-View-ViewModel Design Pattern

public class ViewModel
{
    public RoleBasedSecurityCommand MyCommand { get; set; }

    public ViewModel()
    {
        MyCommand = new RoleBasedSecurityCommand(Execute, CanExecute);
    }        

    [AuthorizationAttribute(AuthorizationType.Allow, "Admin")]
    private void Execute(object o)
    {

    }

    private bool CanExecute(object o)
    {
        return true;
    }
}

If the current user has the role Admin he is allowed to execute the command. The RoleBasedSecurityCommand class definition is shown here:

public class RoleBasedSecurityCommand : ICommand
{
    private readonly Action _Execute;
    private readonly Predicate _CanExecute;
    private bool _IsAuthorized;

    #region Constructors

    public RoleBasedSecurityCommand(Action execute)
        : this(execute, null)
    {
    }

    public RoleBasedSecurityCommand(Action execute, Predicate canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _Execute = execute;
        _CanExecute = canExecute;

        _IsAuthorized = IsAuthorized(_Execute.Method);
    }

    #endregion

    private bool IsAuthorized(MethodInfo methodInfo)
    {
        bool isAuthorized = true;

        var authorizationAttributes = (AuthorizationAttribute[])methodInfo.GetCustomAttributes(typeof(AuthorizationAttribute), true);

        if (authorizationAttributes.Count() == 0)
        {
            return true;
        }

        foreach (var authorizationAttribute in authorizationAttributes)
        {
            if (authorizationAttribute.AuthorizationType == AuthorizationType.Allow)
            {
                isAuthorized = Thread.CurrentPrincipal.IsInRole(authorizationAttribute.Role);
            }
            else if (authorizationAttribute.AuthorizationType == AuthorizationType.Deny)
            {
                isAuthorized = !Thread.CurrentPrincipal.IsInRole(authorizationAttribute.Role);
            }

            if (isAuthorized == false)
            {
                break;
            }
        }

        return isAuthorized;
    }

    #region ICommand Members

    public bool CanExecute(object parameter)
    {
        if (_IsAuthorized)
        {
            return _CanExecute == null ? true : _CanExecute(parameter);
        }
        else
        {
            return false;
        }
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _Execute(parameter);
    }

    #endregion
}

The RoleBasedSecurityCommand class is based on the relay command of Josh Smit but in the constructor the IsAuthorized method is executed. This method will read the AuthorizationAttribute attributes specified on the CanExecute method and check if the user has a certain role (Allow) or must not have a certain role (Deny). When the CanExecute method is called by the WPF framework and the user is not authorized it will return false. If a button is bind to this command it’s automatically disabled because we make use of the ICommand interface.

The RoleBasedSecurityCommand is just a basic implementation to work with role based security. It can be extended to support more complex role checks.

Source code can be downloaded from here. To test the application you can assign a role to the current user in the code behind of MainWindow.xaml