« Multiple Event Receiver and The Single-Responsibility Principle (SRP) | Main
Wednesday
Oct152008

Securing SharePoint Application Pages

Why inherit from LayoutsPageBase to write a custom application page?  It’s actually to take advantage of the security elements LayoutsPageBase adds on top of UnsecuredLayoutsPageBase. If only if we wanted to have an application page we would have just inherited UnsecuredLayoutsPageBase, and boom, we’ll have a custom ASP.NET page under the context of SharePoint.

The very reason we call inheritance, white box reuse, is because we assume that we understand how the base class (the white box) works and then we take advantage by reusing its inherit functionalities. So, I tried to understand how security is implemented in LayoutsPageBase so I can efficiently customize it.

Microsoft.SharePoint.WebControls.LayoutsPageBase

namespace Microsoft.SharePoint.WebControls
{
    public class LayoutsPageBase : UnsecuredLayoutsPageBase
    {
        public static readonly SPBasePermissions DefaultLayoutsRights;
        protected virtual bool RequireDefaultLayoutsRights { get; }
        protected virtual bool RequireSiteAdministrator { get; }
        protected LayoutsPageBase.RightsCheckModes RightsCheckMode { get; set; }
        protected virtual SPBasePermissions RightsRequired { get; }
        protected void CheckRights();
        protected override void OnLoad(EventArgs e);
        protected override void OnLoadComplete(EventArgs e);
        protected override void OnPreInit(EventArgs e);
 
        [Flags]
        protected enum RightsCheckModes
        {
            None = 0,
            OnPreInit = 1,
            OnLoadComplete = 2,
        }
    }
}

You have two options as to when to check users’ permission to access your application page: OnLoadComplete and on OnPreInit. By default, permissions are checked on OnLoadComplete, and the default permissions checked are EmptyMask, ViewPages,  Open and ViewFormPages site permissions, which I find to be the minimum permission set you need to access a SharePoint application page. If you don’t want the default permissions to be checked you just need to override RequireDefaultLayoutsRights and return false. Of course, checking the default permissions will not do you too much good, you might also want to check if user has enough rights to manage alerts, create groups or check any of the SharePoint permissions to accomplish a specific business use case. That is where overriding RightsRequired property comes in. Simply by overriding it and returning all the permissions you need to check, SharePoint will take care the rest for you by checking the permissions you listed including the default layouts permissions and authorize the user to access the custom application page and if checking fails SharePoint redirects the user to an access denied page and let the user login with a different account.

 

It sounds almost perfect now. But, what if you wanted to check if a user belongs to a certain security group in Active Directory or check if user belongs to a SharePoint Group before granting access? Well, there is no SharePoint permission (SPBasePermission) that directly corresponds to that, so there is no use in just using RightsRequired property. But then I could have overridden CheckRights and put my custom user access check logic in there if it was a virtual method, unfortunately it is not.

 

What about RequireSiteAdministrator? I assumed if supposedly it was returning true, then you would be required to be a site administrator to access the page. This was not actually the case. Whether or not you are a site administrator, it will not let you access it if it was returning true. So, what does that leave me with? I could perhaps put logic in there and return true every time my user does not pass through my custom permission check logic, right? But it still kind of bothered me that it my might be a little confusing to do so. So I kind of looked back and asked myself why don’t I just put my dumb custom logic on OnLoad (and redirect user to access denied page when they do not meet my custom permissions), and change RightsCheckMode to OnPreInit so that SharePoint permissions are checked before my custom checks are run (Didn’t know it was that simple), and this is what you should get:

 

public class AppPage : LayoutsPageBase
{     
    protected override SPBasePermissions RightsRequired
    {
        get
        {
            SPBasePermissions permissions = base.RightsRequired 
                | SPBasePermissions.BrowseUserInfo 
                | SPBasePermissions.CreateGroups
                | SPBasePermissions.ManageLists;
            return permissions;
        }
    }
 
    public AppPage()
    {
        this.RightsCheckMode = RightsCheckModes.OnPreInit;
    }
 
    protected virtual void CheckCustomRights()
    {
        bool userCheckedForCustomLogic = false;
        //write here a custom logic to check if user has enough rights to access application page
        //if yes, set userCheckedForCustomLogic to true;
 
        if (!userCheckedForCustomLogic)
        {
            SPUtility.HandleAccessDenied(new UnauthorizedAccessException());
        }
    }
 
    protected override void OnLoad(EventArgs e)
    {
        this.CheckCustomRights();   
    }
}

 

I admit that, I kind of exaggerated the process to getting to the solution. But, I wanted to make an important point that if you ask yourself why you are inheriting anything, at all times, then you will be able to efficiently reuse code (and you should get a tattoo just saying that).

 

using(NaT)

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>