Sample: SecurityManager (Windows Forms)

Omar and I were on the phone late tonight discussing the design of a Windows Forms application he’ll be working on (what else is there to do at 11:30 PM? :) ) . The discussion came around to the topic of security, namely how visual components and bits of code could be displayed or treated differently according to the permissions of users. As we were talking I came up with an interesting solution, using data binding, which I thought I’d repost here.

First, I started out by defining a singleton class, called “SecurityManager“, that will maintain a whole load of settings/constraints about the application. Depending on the size of the application you’re working on you’d probably split this up, but for my purposes it is pretty simple.

public class SecurityManager {
    private static readonly SecurityManager _current = new SecurityManager();

    public static SecurityManager Current {
        get { return _current; }
    }

    public bool IsAdministrator {
        get {
            // Change this code to a role that does/doesn't exist
            return Thread.CurrentPrincipal.IsInRole("Administrators");
        }
    }
}

When the application launches, I can then set the current Windows user like so:

Thread.CurrentPrincipal =
    new WindowsPrincipal(WindowsIdentity.GetCurrent());

Now everywhere in the application where I need to do a security check, I can could write basic, stone-age code like this:

if (!SecurityManager.Current.IsAdministrator) {
    // Don't reveal world domination plan
}

That’s all pretty standard. However, let’s say I want to decide whether or not to show a Panel based on permissions. I might do something like this:

adminPanel.Visible = SecurityManager.Current.IsAdministrator;

However, this type of code is going to appear all over the application, and is simply going to bloat the Code Behind of the form. Instead, I’ll use Data Binding to do the work for me :)

I started by creating a custom BindingSource, called SecurityManagerBindingSource, which would automatically set the SecurityManager.Current instance as its DataSource (now hopefully you can see why I used a singleton above - I need an instance of the object to bind to):

public class SecurityManagerBindingSource : BindingSource {
    public SecurityManagerBindingSource() {
        this.DataSource = SecurityManager.Current;
    }
}

Now I can make use of the designer. First, I drag an instance of the SecurityManagerBindingSource onto my Form:

Then I can simply bind the Visible and Enabled properties of any of my controls to the IsAdministrator property on the SecurityManager:

Now when the application runs, the panel won’t appear unless the current user is in the Administrators role.

This approach has numerous advantages:

  1. Most Windows Forms developers will appreciate the design-time aspect. If you just want to hide something based on group membership, you don’t need to write a single bit of code.
  2. Of course, Data Binding isn’t mandatory - you can achieve all of the same functionality in code if you wish
  3. You get a lot of cool data binding functionality for free. For example, if the user disconnected from an application database, or impersonated another user, your SecurityManager just has to implement INotifyPropertyChanged and raise an event to say that the roles/permissions for the user have changed. All UI controls will automatically show/hide themselves to match.

This fits very nicely into the Binding Oriented Programming idea I discussed a while back. If you use a solution like this, you’re recognizing that every instance of the application has a set of permissions associated with it, and that the visibility/enabled aspects of your UI must be bound to and synchronized with that permission set.

I think this is a great example of applying data binding to a scenario which doesn’t have anything to do with the plain old creating, updating or deleting of business data.

4 Responses to “Sample: SecurityManager (Windows Forms)”

  1. […] Yesterday I posted about a class called SecurityManager, which had the job of checking role-based security settings and exposing properties that could be data bound to. In that example, I created a custom BindingSource in Windows Forms so that I could bind the Visible and Enabled properties of controls to the class, all through the designer. […]

  2. Love the idea and will probably use it for an application I’m currently working on.

    Thanks!

  3. I enjoy many of your posts and your insights are very helpful.

    When it comes to security, Microsoft falls flat on its face: IMO. An application should not have hard-coded roles. Attributes placed in code (hard-coded) that demand IsInRole(”XYZ”) makes no sense for software that’s a hardware solution.

    A role is a collection of permissions. An application must support permission options. Permissions can becomes much more complex when data is expected to be filtered based on permissions and when certain users have different rules for validation.

    A basic (poor) application hard-codes these options as roles. A robust application allows for end-user configuration of roles.

    Permission options (obviously) must be hard-coded (not the role); thus, the code should be something like:

    // a simple implementation
    public bool HasPermission(IRole role, IPermission permission) {
    // return result
    }

    The class needs to know if the a permission is granted, but should never know what specific roles exist - only that “a” role exists.

    Further, why do so many apps send unauthorized data to a client and then use the client-side to filter/block-out the data?

    Since .NET 2.0 and nullable types no client should ever receive unauthorized data (hidden or not).

  4. This example has a flaw: it serializes the Datasource in the designer.cs. So the actual properties like IsAdministrator are stored in the designer :(
    This code solves the problem of the datasource being serialized:

    using System.ComponentModel;
    public class SecurityManagerBindingSource : System.Windows.Forms.BindingSource
    {
    public SecurityManagerBindingSource()
    {
    this.DataSource = SecurityManager.Current;
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new object DataSource {
    get {
    return base.DataSource;
    }
    set {
    base.DataSource = value;
    }
    }
    }

Leave a Reply