04 December 2009

Why passing SPBasePermissions.FullMask to SPContext.Current.Web.DoesUserHavePermissions() instead of SPBasePermissions.ManageWeb when you’re trying to determine if a user is a SPWeb administrator, is a bad idea…

OK, so the title of this post could also have been “Best Practices for Determining if a User is a SPWeb Administrator”, but then the search engines wouldn’t catch the post for all those unfortunate enough to be searching for FullMask or DoesUserHavePermissions() in the future.  The Problem OK, OK, in all seriousness though.  There are a lot of content out there that recommend that people simply useSPContext.Current.Web.DoesUserHavePermissions(SPBasePermissions.FullMask) when trying to determine if the current user has Administrator rights to the current web site (SPWeb).  This is all good and well, but it assumed that you have NEVER customized your web application available permissions list i.e. your effective base permissions.  So what’s the problem, you may be wondering… The problem is in the way SharePoint behaves when you do indeed customize your permissions for the web app.  If you dive into SharePoint Central Administration under Central Administration > Application Management > Permissions for Web Application you will find all the SharePoint base permissions and the ability to turn any one of these permissions off by simply unchecking it’s checkbox and then clicking the OK button… all except for one… FullMask.  If you were to uncheck say UseClientIntegration (in order to disable desktop apps such as Office or SPD from editing content directly on the server) and then save that state, SharePoint will do two things.
  1. It will remove the UseClientIntegration bit flag from the permissions bit mask and
  2. because total full control is no longer possible for the web app, it will also remove the FullMask bit flag from the mask.
That’s all fine and dandy until you go and add the permissions back again.  If you now recheck the UseClientIntegration checkbox and clicked OK, you’d expect SharePoint to add the bit flag back to the permissions mask again and it does do that, but for the UseClientIntegration flag only.  If you’re expecting it to also reset the FullMask flag, you’ll be disappointed.   This appears, at least in my mind, to be a bug in the SharePoint core code.  Yes, yes, I know it’s most probably “working as designed” or “behaving as intended”   , but in my mind the absence of any UI way to reset the FullMask flag, as well as the sparse documentation surrounding it, this just feels like a bug and not an intended feature.  So to be clear… SharePoint does not reset the FullMask security bit once permissions on the web app was customized! Now as far as SharePoint UI and everything else an end user sees is concerned, everything is working perfectly as per usual with no ill effects.  It’s only when you drop into the world of the SharePoint developer that things can become hairy.  In case you were wondering, here’s the base permissions bit mask as returned when the FullMask bit is set:7FFFFFFFFFFFFFFF And once customized, even with all permissions enabled again, the bit mask returns rather as a union of all aggregated permissions and looks like this: 400001F07FFF1BFF If a SharePoint developer used the DoesUserHavePermissions() method and passed the FullMask flag to it in hopes of identifying an admin user, the method will always return False because the FullMask bit is never reset again.  So using SPContext.Current.Web.DoesUserHavePermissions(SPBasePermissions.FullMask)simply isn’t reliable for admin checking in code.  Fortunately, the failure occurs on the safe side i.e. it is reporting an Admin to simply not be an Admin rather than reporting a User to be an Admin so most probably your app doesn’t break, but is simply not quite working as expected. The Solution So then, you ask, what exactly would be the best practice for determining if the current user is an admin? You may be tempted to use code like this((ISecurableObject)SPContext.Current.Web).DoesUserHavePermissions((SPBasePermissions)Microsoft.SharePoint.SPPermissionGroup.WebDesigner))and then use SPPermissionGroup.Administrator as the target, but since the value of Administrator in this case is –1 and the DoesUserHavePermissions() method is looking for aulong value, it will epically fail on you, even if you were to “duck punch” it with up/down casts like (SPBasePermissions)(Object)… Rather, the proper way to check if a user has admin rights to the current SPWeb, regardless of source (web, site collection or CA policy), is as follows:((ISecurableObject)SPContext.Current.Web).DoesUserHavePermissions(SPBasePermissions.ManageWeb)By checking if the user has the ManageWeb security bit set, you will always get the proper result back.  Using FullMask is akin to trying to remove a wart with a canon.  ManageWeb is more like a scalpel. OK, I broke it.  Now what? If you’re in the boat where you’ve already “broken” the FullMask bit, don’t despair.  There is indeed hope.  Luckily some smart people like MOSS MVP Gary LaPointe, have struggled with this problem before and have created clever workarounds for this. To reset the FullMask security bit, you can use the following code courtesy of Gary:
SPWebApplication wa = SPWebApplication.Lookup(new Uri(url)); 
wa.RightsMask = wa.RightsMask | SPBasePermissions.FullMask;
wa.Update()
If you’re adventurous, you can go ahead and write an app or even your own STSADM extension for that, but if you’re like me, you’ll be happy to know that Gary already did that!  Simply go and get his MOSS or WSS extension methods for STSADM package from his Download Page.  It comes all nicely packaged in a .wsp ready for deployment into your SharePoint environment.  The STSADM operation you need is: gl-enableuserpermissionforwebapp and the proper syntax for it is as follows: stsadm -o gl-enableuserpermissionforwebapp -fullmask -url http://YourWebAppURL So there you go.  The best practice for determining if a user is an administrator for a site and a way to fix it if your code is using FullMask and broke because someone played with permissions. Enjoy…

Cheers
C

No comments:

Post a Comment

Comments are moderated only for the purpose of keeping pesky spammers at bay.

SharePoint Remote Event Receivers are DEAD!!!

 Well, the time has finally come.  It was evident when Microsoft started pushing everyone to WebHooks, but this FAQ and related announcement...