Custom Page Security Using SharePoint Delegate Controls

I’m a control freak, and I don’t mean that in the normal sense. What I do mean is that I love .NET controls and particularly delegate controls in SharePoint. These little gems are, on a power-to-weight ratio, perhaps the single most powerful developer tool for extending SharePoint.

However, when I start talking about delegate controls to developers, their eyes often glaze over, having either just heard about them but never used them or never heard about them at all. That’s the sad news, but the good news is that for you, this is the last day of your life when you’ll have no idea what delegate controls are…provided you read to the end of this article, of course.

In this article, I will explain how you can use delegate controls in SharePoint to implement a custom security scheme on top of the normal SharePoint security. By utilizing this method,  you may, for example, implement features such as the following:

  • Allowing access to certain pages or content only on certain dates or during certain times of the day
  • Forcing users to accept a site policy before being allowed access to your site
  • Preventing anonymous users from accessing sensitive content and application pages

These are just a few examples, however, and if you read on, I’ll show you how powerful these delegate controls are and how you can utilize them to implement custom security in SharePoint.

Oh, and you should have prior experience with SharePoint programming, but I’ll show you where to find the information you need about delegate controls if you’ve never used them before.

Delegate Control Basics

A delegate control is like a plug-in engine waiting to happen. In short, a delegate control allows you to put any piece of .NET code into a SharePoint page without touching the page itself.

What’s even cooler is that most of the out-of-the-box pages in SharePoint, even the application pages in the LAYOUTS folder, already have several of these delegate controls in place. That means you can affect virtually any page in SharePoint without modifying any out-of-the-box files.

Before we dive into the details, if you’re a regular reader of SharePoint Magazine, you’ll know that a few years ago, I posted an introduction to delegate controls. So, rather than reiterating the same instructions here, I’ll just point you to that article:

Using DelegateControls to Customize the User Experience

However, what I explained in that article is only the beginning. There’s so much more these delegate controls can do. Let’s take a look at a few additional scenarios.

Blocking Anonymous Users

For public-facing SharePoint sites, security is a major concern. Unless you pay very close attention to the details, read up on security best practices, and test your solution thoroughly, chances are your site will leak information, especially through form and application pages.

On the other hand, you can’t prevent anonymous users either, because the whole purpose of a public-facing website is to allow external users in and show them your products and services. So, is there a way you can actually have your cake and eat it too? With delegate controls, there is.

The goal of this exercise is to prevent anonymous access to application pages in a SharePoint site. This may be useful in public-facing sites that have little or no interaction from anonymous users.

Walk-through

Start by setting up a basic assembly-based delegate control feature as explained in the Using DelegateControls to Customize the User Experience article. By assembly-based, I mean a delegate control that uses ControlAssembly and ControlClass rather than ControlSrc as its control.

You can set the scope to whatever makes most sense to you because delegate control features work on any feature scope. In this example, if you want to prevent anonymous access throughout your entire SharePoint farm, you need only set the scope to Farm, and, poof, you’ll prevent any unauthorized access with a single delegate control deployed once.

We’ll also utilize the AdditionalPageHead delegate control. This particular delegate control is useful because it is present in almost every master page that ships with SharePoint. Sadly, “almost every master page” does not include the publishing master pages.

If you are using publishing pages, you may not have the AdditionalPageHead delegate control in your master pages. If you want this example to work, you can simply copy the SharePoint:DelegateControl for AdditionalPageHead from one of the out-of-the-box master pages.

This means that you’ll need to add a new feature with a feature.xml file something like this:

<Feature  Id="3c8eef25-0d4a-4267-a98c-81669498b8c7"
          Title="Anonymous Delegate Control"
          Description="Prevent access to any application page for anonymous users."
          Version="1.0.0.0"
          Hidden="FALSE"
          Scope="Web"
          DefaultResourceFile="core"
          xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>    
  </ElementManifests>
</Feature>

And you’ll need an elements.xml file that looks something like this, although with your own public key token:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control ControlAssembly="DelegateControlSecurity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63a8a734a46b73e2"
           ControlClass="DelegateControlSecurity.PreventAnonymousUsers"
           Id="AdditionalPageHead"
           Sequence="10"/>
</Elements>

These things aside, what really matters is your control class. As with all delegate controls, our control class should inherit from the System.Web.UI.Control parent class. This gives us a normal control that will run inside the delegate control.

If our case, we want the delegate control to only prevent users access to any folder in the _layouts/ folder. We also only want to prevent anonymous users from accessing the application pages, but any authenticated user should be given normal access.

Here’s an example of how the control class might look:

namespace DelegateControlSecurity
{
    public class PreventAnonymousUsers : Control
    {
        protected override void OnLoad(EventArgs e)
        {
            if (Context.Request.Url.PathAndQuery.IndexOf("_layouts/", StringComparison.InvariantCultureIgnoreCase)&gt;0)
            {
                if (SPContext.Current.Web.CurrentUser == null)
                {
                    // Anonymous user, prevent access
                    SPUtility.TransferToErrorPage("Anonymous users have no access to this page");
                }
            }
        }
    }
}

In short, you’ll check whether the page URL contains “_layouts/” and, if it does, whether the current user is NULL, meaning they are not authenticated. If so, we’ll redirect them to an error page.

Of course, these are only two of the conditions you may set for controlling access.

Other Conditions

Now that you have a basic control to handle access based on whether the user is logged in, you can easily modify the conditions to facilitate virtually anything you want. For example, if you wanted to limit after hours access to user management, you could to something like this in your control class:

protected override void OnLoad(EventArgs e)
{
    if (Context.Request.Url.PathAndQuery.IndexOf("_layouts/people.aspx", StringComparison.InvariantCultureIgnoreCase) &gt; 0)
    {
        if (DateTime.Now.Hour &gt; 16 || DateTime.Now.Hour &lt; 8)
        {
            SPUtility.TransferToErrorPage("Sorry, the user management department is now closed");
        }
    }
}

The result may resemble the screenshot shown here (and yes, I realize the timing doesn’t match the code; I just couldn’t wait several hours to test).

custom-security-in-sharepoint-using-delegate-controls-figure-1

But Wait, There’s More!

Another use for delegate controls access control is overriding default SharePoint pages. Let’s say you’ve created a customized user profile page or a new Site Settings page. Of course, you’d want your users to use only your new page, but how do you prevent users from accessing the old Site Settings page without modifying the out-of-the-box pages?

You should know the answer by now:

protected override void OnLoad(EventArgs e)
{
    if (Context.Request.Url.PathAndQuery.IndexOf("_layouts/settings.aspx", StringComparison.InvariantCultureIgnoreCase) &gt; 0)
    {
        Context.Response.Redirect("MySiteSettingsPage.aspx", true);
    }
}

You’re not limited to just page redirection, however. Delegate controls allow you to interact with the user based on any condition and perform virtually any activity, such as displaying messages, disabling links, modifying page content, adding and removing menu items, and so on. However, I’ll leave those as an exercise for you so you’ll have something to try out yourself.

Additional Considerations

Delegate controls are great, but they aren’t the perfect solution to every problem. Here are some additional considerations you need to make when deciding whether to implement delegate controls.

Control Code Execution

Keep in mind, the order in which controls run affect the control. Delegate controls are regular controls and thus follow the control execution life cycle. That means that the sooner in the life cycle you execute your code, the less likely you are to see other controls affect your control.

Another important thing to keep in mind is that when you run your control code, you can also affect other controls or even the page itself. In the USP Journal issue Advanced Content Type Development, for example, one of the methods I describe injects code into the Page object’s life cycle to update the page content.

Other Access Methods

Also keep in mind that controlling access in a web page isn’t the same as implementing complete security. Users may still access your data using other methods, such as custom pages or web services. A site administrator may even decide to turn off the delegate control, or the logic of that control may not be as water-proof as you’d like to think.

To control access through those other channels or to ensure security in case of control failure or disabling, you need other methods than delegate controls. However, that will have to wait for another article.

The End…

I hope I’ve inspired you to take a closer look at a virtually forgotten but, oh, so powerful control in SharePoint. Remember that controlling access to pages is only one use of this incredibly useful control.

If you have ideas on how to use delegate controls to improve functionality in SharePoint, why not share your ideas in the discussion forum?

Talk soon!

.b

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!

Leave a Reply

Before you post, please prove you are sentient.

What color is a typical spring leaf?