Sunday, January 27, 2008

User Permissions

After getting the current logged user, we can achieve tasks like ask for user's groups belong to, or use the declarative and imperative permission demand:
// Define the security policy in use as Windows security
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
 
try
{
    // User must belong to Administrators group
    PrincipalPermission pp = new PrincipalPermission(null, "Administrators");
    pp.Demand();
 
    // User is an administrator
    MessageBox.Show("Only administrators can see this message.");
}
catch (SecurityException)
{
    MessageBox.Show("Access denied");
}
catch(Exception ex)
{
    MessageBox.Show(ex.Message);
}
Using declarative demand:
[PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
void AdministratorsOnlyMethod()
{
    // User is an administrator
    MessageBox.Show("Only administrators can see this message.");
}
NOTE: The PrincipalPermission only exposes three properties: Authenticated, Name and Role.

WindowsIdentity and WindowsPrincipal classes

The WindowsIdentity class has several methods for getting identities and their properties: GetAnonymous, GetCurrent, Impersonate.

Properties: AuthenticationType, IsAnonymous, IsAuthenticated, IsGuest, IsSystem, Name ("DOMAIN\Username"), Token.

The WindowsPrincipal provides information about groups the user is belong to.

// Getting the current identity and principal representation
WindowsIdentity wi = WindowsIdentity.GetCurrent();
WindowsPrincipal wp = new WindowsPrincipal(wi);
 
// Showing some properties
MessageBox.Show(wi.AuthenticationType);
 
MessageBox.Show(wp.IsInRole(WindowsBuiltInRole.Administrator).ToString());
MessageBox.Show(wp.IsInRole(WindowsBuiltInRole.Guest).ToString());
MessageBox.Show(wp.IsInRole("Administrators").ToString());
If we need authenticate users agaings a custom database, we must implement our custom identity and principal classes from IIdentity and IPrincipal interfaces. Also, we can extend properties and funcionality from classes like WindowsIdentity, WindowsPrincipal, GenericIdentity and GenericPrincipal.

public class myIdentity : IIdentity
{
    private string _name, _password;
 
    // Custom constructor
    public myIdentity(string name, string password)
    {
        _name = name;
        _password = password;
    }
 
    #region IIdentity Members
 
    public string AuthenticationType
    {
        get { return "custom"; }
    }
 
    public bool IsAuthenticated
    {
        get 
        { 
            // Our custom validation, like getting passwords
            // from a local database could be here
            return (_password == _name + "123");
        }
    }
 
    public string Name
    {
        get { return _name; }
    }
 
    #endregion
}
public class myPrincipal: IPrincipal
{
    private myIdentity _identity;
    private string[] _roles;
 
    public myPrincipal(myIdentity identity, string[] roles)
    {
        _identity = identity;
        _roles = roles;
    }
 
    #region IPrincipal Members
 
    public IIdentity Identity
    {
        get { return _identity; }
    }
 
    public bool IsInRole(string role)
    {
        // Here, we can search for identity's roles
        // in our custom database
        foreach (string s in _roles)
        {
            if (s.ToLower() == role.ToLower())
                return true;
        }
   
        return false;
    }
 
    #endregion
}
Using our custom identity and principal:

// validate our user
myIdentity mi = new myIdentity("john", "john123");
if (!mi.IsAuthenticated)
{
    MessageBox.Show("Invalid username/password");
    return;
}
 
// Set some roles
myPrincipal mp = new myPrincipal(mi, new string[] {"users", "accounting"});
 
// Assign to the thread's current principal
Thread.CurrentPrincipal = mp;
 
try
{
    PrincipalPermission pp = new PrincipalPermission("john", "accounting");
    pp.Demand();
 
    MessageBox.Show("performing some accounting code");
}
catch(Exception ex)
{
    MessageBox.Show(ex.Message);
}

0 comments:


View My Stats