Mad, Beautiful Ideas
SharePoint 2007 Web Part Security

Microsoft’s SharePoint is a team-oriented Portal System that Microsoft has been pushing heavily due to it’s integration with the Microsoft Office Suite of products. To this end, Microsoft offers a lot of built-in web parts to facilitate this: discussion lists, blogs, simple forums, and quite a bit more. However, occasionally, users will require something more out of SharePoint than is provided by the core functionality.

To fill this void, a Developer can utilize Web Parts, which are small web applications that fit inside of larger applications and are either completely self-contained, or can communicate with other web parts on the same page. Even better, you can write a web part using the .NET 2.0 Web Parts Framework, allowing your common Web Part to function on non-SharePoint .NET Portals. This is useful for web-parts that are largely meant for the consumption of public-data, say a Flickr Web Part, or a weather web part. Sometimes you’re going to want to use a Web Part for other purposes, for instance as a front-end to a database. For that, you need more control, you need to be able to limit user’s access. You need to tie more tightly into SharePoint. Luckily, this can be done easily, with virtually no code changes.

Oddly enough, you don’t even have to inherit from SharePoint’s native Web Part class (Microsoft.SharePoint.WebPartPages.WebPart) in order to get access to the SharePoint Context object (Microsoft.SharePoint.SPContext). In my opinion, it is generally safer to inherit from Microsoft.SharePoint.WebPartPages.WebPart if you use anything in the Microsoft.SharePoint Namespace, as your Web Part will already only work in SharePoint, so you might as well. Unfortunately, this won’t prevent a SharePoint Web Part from loading into a non-SharePoint portal, as Microsoft.SharePoint.WebPartPages.WebPart inherits from System.Web.UI.WebControls.WebParts.WebPart, meaning that if you want your Web Part to always fail gracefully, you’ll require something like this:

Protected Overrides Sub Render(ByVal Output As System.Web.UI.HtmlTextWriter)
                        If Microsoft.SharePoint.SPContext == Nothing 
                                        ' Output fancy error Message and return.
                        End If
        End Sub

Of course, you have to be careful about anything that might use the SPContext object earlier in the Web Part execution cycle (CreateChildControls is a common culprit), but this allows you to fail gracefully, which is particularly important if you intend to distribute your Web Part at all.

Okay, you’ve got a web part that you want to control user access to in a fine-grained method. As made clear, you do this by checking the current SPContext object, which is static, so you shouldn’t instantiate it. One of the biggest problems that I ran into with SharePoint was determining if the Access Denied page that my users were experiencing were related to code or actually access controls within SharePoint. Due to this difficulty, you’re going to want to make sure you have the MSDN handy, or you’re likely to spend a lot of time butting your head against the wall.

One potentially easy mistake is accessing the wrong objects to determine permissions. I had begun working under the assumption that to determine a user’s permissions, we’d want to check the permissions that user has on the Site (or sub-Site) that they’re on. Unfortunately, there is a method, CheckForPermissions, on the SPSite object for that. The following code certainly seems like it should work.

        SPContext.Current.Web.Site.CheckForPermissions(SPContext.Current.Web.ReusableAcl, permissionsMask)
        

This only appears to work for users who have Full Control of the site in question. And Microsoft’s API documentation doesn’t appear to offer any commentary on why that might be. If you know, please, leave a comment. Let me know. This is another unfortunate case of a Microsoft API having, or appearing to have, several methods to accomplish a given task, and I really hope that the documentation improves.

It turned out that I’d been over thinking the problem. The SPWeb object give you the exact method you need, though it’s name, while descriptive, wasn’t quite as discoverable. It turns out that the proper way to check a user’s permissions is this:

        SPContext.Current.Web.DoesUserHavePermissions(permissionsMask)
        

It’s just that easy. The nice part, is that you can now check the permissions against the set permissions in the SPBasePermissions Enum. This enumerated type doesn’t have any permissions specific to Web Parts, but I found that, for my purposes at least, using the ✱ListItem set of permissions was the best means to control the access, as for our purposes users that couldn’t modify the lists also weren’t going to be allowed to modify the data in the Web Part. If this won’t work for you, you may need to create a sub-site, which luckily isn’t very hard, otherwise, I don’t know how to create Custom Permissions. I’m not entirely sure it’s possible.

Maybe the reason that I couldn’t find a reference to this on my Google searches is because other people simply weren’t having this problem, but I was, and I do hope this will help someone else. Why the SPSite.CheckForPermissions method exists, if it won’t work when a non-owner is on the page, then it isn’t terrible useful for limiting permissions. Just remember, to use the correct object, and everything will be fine.