Saturday, August 22, 2009

Securing sharepoint pages / views

Scenario:
Sharepoint has a great security model build but client always need something different. i.e. X user should be able to acess the following Url etc etc.

Solution:
This is the starting point for a good solution which can be scaled to any level. Look at the possible enhancement section.

I have created a very simple HTTPModule which will act as gate keeper for blocking/allowing users.

Steps:
1. Create a list name 'Blocked' of type 'Generic List'

2. Add columns for Url ( Text ) , BlockedFor ( People and Group, Allow multiple and display AccountName as field value ), Message ( Multi-line , with no rick text support )

3. Add a test entry for a user as shown here
blocked entry

4. Now login to the site using new user account details and try navigating to the Url you have blocked for this user. Here's what you get.
blocked error

HTTPModule Code:

using System;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;

namespace SPSecureHttpModule
{
public class SPSecureHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += ContextPostAuthenticateRequest;
}

static void ContextPostAuthenticateRequest(object sender, EventArgs e)
{
var app = sender as HttpApplication;
if (app != null)
{
string requesturl = app.Request.Url.ToString();
string message = CheckBlockage(requesturl, app.Request.LogonUserIdentity.Name);
if (message.Length >0 )
{
SPUtility.TransferToErrorPage(message);
//SPUtility.SendAccessDeniedHeader(new Exception("You dont have access"));
}
}
}
public static string CheckBlockage(string url, string userName)
{
const string rootSite = "http://localhost";
const string listName = "Blocked";
string message = string.Empty ;

SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (var site = new SPSite(rootSite))
{
using (SPWeb web = site.RootWeb)
{
SPList list = web.Lists[listName];

SPQuery query = new SPQuery()
{
ViewFields = "<FieldRef Name='Message'/>",
RowLimit = 100,
Query = string.Format(@"<Where>" +
"<And>" +
"<Eq>"+
"<FieldRef Name='Url' />"+
"<Value Type='Text'>{0}</Value>"+
"</Eq>"+
"<Eq>"+
"<FieldRef Name='BlockedFor' />"+
"<Value Type='UserMulti'>{1}</Value>"+
"</Eq>"+
"</And>"+
"</Where>",url,userName)

};

SPListItemCollection listItemCollection = list.GetItems(query);
if (listItemCollection.Count > 0)
message = listItemCollection[0]["Message"].ToString();
}
}
});

return message;
}

public void Dispose() { }
}
}
Web Config entry:
    <httpModules>
<clear />

.... other entries ( remove for readability ) .....

<add name="SPSecureHttpModule" type="SPSecureHttpModule.SPSecureHttpModule, SPSecureHttpModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=898712a2c58c5c10" />

</httpModules>
Enhancements possible:
1. To make it more generic for Groups / Multiple Users
2. Wildcard support for Url

Thoughts ??

0 comments: