CAB – Adding Command-level security to applications

Need to enable/disable Commands depending on user identity/role/credentials? I present a practical solution that simplifies this common task.

Solution design
The implementation takes advantage of the ObjectBuilder and is based on the use of a custom attribute -the CommandAuthorization attribute- in adition to a custom ObjectBuilder strategy. This strategy will ensure that during the initialization of the work item, all the commands that the user is not authorized to use will be disabled/made unavailable.

To check authorization on a command, the custom strategy uses a user-provided service which has to implement the interface ICommandAuthorizationService. This interface contains only one method:

bool CheckAuthorization (string commandName)

that returns true if the current user is authorized to use the command, or false if it is not.

Usage

  1. Download the file CompositeUIExtensions.Security.zip and extract it to a desired folder.
  2. Open the solution named CompositeUIExtensions.Security.sln and build it. If you experience problems, check that the references to the CAB assemblies are correct.
  3. In your shell project and in any other project you want to add command-level security, add a reference to CompositeUIExtensions.Security.dll located in [folder] CompositeUIExtensions.SecuritybinDebug.
  4. In your shell application (e.g: FormShellApplication) override the AddBuilderStrategies method and insert the following code:
    protected override void AddBuilderStrategies(Microsoft.Practices.ObjectBuilder.Builder builder)
    {
    base.AddBuilderStrategies(builder)
    ;
    builder.Strategies.Add(new
    CompositeUIExtensions.Security.CommandAuthorizationStrategy
    (
    new
    CommandAuthorizationService()),
    Microsoft.Practices.ObjectBuilder.BuilderStage.Initialization)
    ;
    }

    where CommandAuthorizationService is any class that implements ICommandAuthorizationService (you can use, of course, the services I provide as examples).

  5. Decorate work items declarations with the CommandAuthorization attribute where needed (use root work item for global command-level security). This attribute can be used in two different ways: with explicit command names or without them. If no command names are explicitly defined, the user must provide a service that enumerates the commands that require authorization.Using the attribute with explicit command names
    Only the commands specified will be checked for authorization. The attribute supports the following parameters:

    • string commandName: name of the command to check authorization for.
    • bool hide: when authorization fails, if hide is set to true the invokers will be hidden, otherwise they will be disabled. The default value is false. Important: see Disabling/Hiding Invokers section below for this feature to work.

    Examples:

    • Single command, do not hide invokers if authorization fails:[CommandAuthorization(“CommandName”)]
    • Three commands, hide invokers if authorization fails:[CommandAuthorization(true, “CommandName1″, “CommandName2″,“CommandName3″)]
    • Three commands, hide invokers only for the first one:[CommandAuthorization(“CommandName1″, true)]
      [CommandAuthorization(“CommandName2″)]
      [CommandAuthorization(“CommandName3″)]

    Using the attribute without command names
    If no command names are defined, the ICommandAuthorizationService provided by user has to also implement the ICommandsProvider interface which has the following method:

    IDictionary<string, bool> GetCommands()

    where the key of the IDictionary is the command name and the value is the hide flag.

    Tip: Using the CommandAuthorization attribute in the root work item will enable authorization checking for all the commands in the application, in any module. This is a great option if you want to add command-level security to all modules in your application.

Disabling/hiding invokers
In order to disable/hide invokers (not just commands) when authorization fails, you have to override the BindCommand method of the command adapter you use. This cannot be done by the CommandAuthorizationStrategy because at the moment of building a work item, invokers are not yet added to commands.

Here I provide the method implementation for the ToolStripMenuItem adapter included in CAB. Open the CAB solution, get the file named ToolStripItemCommandAdapter.cs located in [CAB Source Folder] CompositeUI.WinForms and add the following code:

///
/// Called when the  is registered with a .
///
/// The  the adapter is being added to.
public override void
BindCommand(Command command)
{
base.BindCommand(command)
;
if
(command.Status !=
CommandStatus.Enabled)
foreach (KeyValuePair<ToolStripItem, List<string>> invoker in
Invokers)
{
invoker.Key.Enabled
= (command.Status == CommandStatus.Enabled)
;
invoker.Key.Visible = (command.Status != CommandStatus.Unavailable)
;
}
}

Finally, rebuild the project.

If you are using other control rather than ToolStripMenuItem, you should override the BindCommand method of the corresponding command adapter.

Picture 1: The sample application run by an administrator.

11
Picture 2: The same application run by an user.12

Sample Applications
Inside the download package, I included two sample applications that show the benefits of using this solution: one that implements the ICommandAuthorizationService interface with a service based on a custom authentication/authorization system and another one that implements the interface with a service that takes advantage of Authorization Manager (AzMan). The solution files are Commands QuickStart.sln and Commands QuickStart AzMan.sln respectively.

Both applications are based on the CAB Commands Quickstart. Check them out!

Note 1: For the AzMan based solution, please copy the file AzManStore.xml to C:.
Note 2: To see a detail of the AzMan solution design and implementation, please check this post.

Acknowledgments
Special thanks to Matias Woloski for his help in the solution design, and to Jonathan Halife for his advices on AzMan.

Feedback
Was this solution useful to you? Any suggestions? Feel free to post a comment on this topic.



3 Comments

  • http:// says:

    Looks very cool.

    I haven’t get a chance to look in details, but may I ask if this extention support Task base authorization, or it just do Role-Base authroization?

    Thanks,

  • Mariano says:

    Hi Mica, thanks for the comment. Actually I think I’m not getting what you mean with task based authorization.

    This solution allows you to check for authorization on commands (that may be thought as tasks or operations for instance) for logged user.

    The CommandAuthorizationService you have to provide is in charge of making the authorization check for each command. You could use here a role-based approach, a user-based approach or anything you prefer.

  • http:// says:

    Great work. I appreciate it very much. Not only because of the solution for that problem. This comment also shows, how CAB works internally.

    Thanks
    Thomas

Leave a Reply