HUGE Permissions bug with Import-SPWeb -includeusersecurity

The Export-SPWeb and Import-SPWeb is a tool for moving sites around, but with all the changes that have occured with SharePoint 2010 over the past two years, it seems some of the plumbing isn't connected correctly.

One of the issues we were seeing is that after importing a site, users are able to get to the site, but not to libraries underneath the site.  You would see ULS logs like:

OriginalPermissionMask check failed. asking for 0x00020000, have 0x00000000 

Nice list of the perm masks for reference:

Exception: System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.. 

Access Denied for SITEURL. StackTrace:    at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(HttpContext context)     at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(Exception ex)     at Microsoft.SharePoint.SPWeb.GetWebPartPageContent(Uri pageUrl, Int32 pageVersion, PageView requestedView, HttpContext context, Boolean forRender, Boolean includeHidden, Boolean mainFileRequest, Boolean fetchDependencyInformation, Boolean& ghostedPage, Byte& verGhostedPage, String& siteRoot, Guid& siteId, Int64& bytes, Guid& docId, UInt32& docVersion, String& timeLastModified, Byte& level, Object& buildDependencySetData, UInt32& dependencyCount, Object& buildDependencies, SPWebPartCollectionInitialState& initialState, Object& oMultipleMeetingDoclibRootFolders, String& redirectUrl, Boolean& ObjectIsList, Guid& listId)     at Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.FetchWebPartPageInformationForInit(HttpContext context, SPWeb spweb, Boolean mainFileRequest, String path, Boolean impersonate, Boolean& fGhostedPage, Byte& verGhostedPage, Guid& docId, UInt32& docVersion, String& timeLastModified, SPFileLevel& spLevel, String& masterPageUrl, String& customMasterPageUrl, String& webUrl, String& siteUrl, Guid& siteId, Object& buildDependencySetData, SPWebPartCollectionInitialState& initialState, String& siteRoot, String& redirectUrl, Object& oMultipleMeetingDoclibRootFolders, Boolean& objectIsList, Guid& listId, Int64& bytes)     at Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.GetFileForRequest(HttpContext context, SPWeb web, Boolean exclusion, String virtualPath)     at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.InitContextWeb(HttpContext context, SPWeb web)     at Microsoft.SharePoint.WebControls.SPControl.SPWebEnsureSPControl(HttpContext context)     at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.GetContextWeb(HttpContext context)     at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.PostResolveRequestCacheHandler(Object oSender, EventArgs ea)     at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()     at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)     at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)     at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)     at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)     at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr managedHttpContext, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)     at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr managedHttpContext, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)     at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr managedHttpContext, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)     at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr managedHttpContext, IntPtr nativeRequestContext, IntPtr moduleDa…

Looking at the permissions for the library (Site Actions->Site Permissions OR Library->Library Permissions), you WOULD see what you are supposed to see as far as permissons are concerned (even the CheckPermissions tool shows what we want).  However, looks are DECEIVEING!  Also, when we try to break permissions, it would continue to show that the list was inheriting from the parent.  No errors would be thrown in the UI.  When using powershell and tracing the verbose calls in ULSViewer you would actually see some more revealing details:

05/10/2012 09:23:21.29 PowerShell.exe (0x1180) 0x0D3C SharePoint Foundation General bj8s Medium setSecurityScopeUnique: start 
05/10/2012 09:23:21.29 PowerShell.exe (0x1180) 0x0D3C SharePoint Foundation General bj8t Medium setSecurityScopeUnique: already unique 
05/10/2012 09:23:21.29 PowerShell.exe (0x1180) 0x0D3C SharePoint Foundation General bj8w Medium setSecurityScopeUnique: finished 

Notice the second line:  "Already unique"…WTF…no its not!  The UI shows it is inheriting permissions!  So what is going on here?

Turning on the handy SQL Profiler, I did the following powershell on a "working" list:

$web = get-spweb http://blah
$list = $web.lists["Project Documents"]
$list.BreakInheritance($true, $false)

What you see in profiler is a call to:

declare @p15 uniqueidentifier
set @p15='4EE7D0C0-0133-4600-A96E-53BD0D133DEF'
exec proc_SecChangeToUniqueScope @SiteId='EFAF8E96-FA9F-4816-A965-CE7A8C6ED8AC',@WebId='E504097A-2BA1-400F-BCC2-5DE6B32E8615',@OldScopeId='3FB9F8DA-A957-4B82-B4AA-FECB3B1B4551',@CopyFromScopeId='3FB9F8DA-A957-4B82-B4AA-FECB3B1B4551',@Url=N'asi/Shared Documents',@DocId='00000000-0000-0000-0000-000000000000',@bIsWeb=0,@UserId=1073741823,@CopyAnonymousMask=1,@CopyRoleAssignments=1,@ClearSubScopes=0,@bBreakBySiteOwner=0,@ReturnAuditMask=1,@MaxScopeInList=50000,@NewScopeId=@p15 output,@RequestGuid='00000000-0000-0000-0000-000000000000'
select @p15

When performing the same operation on a "broken" list (remember, from an imported web), you DO NOT see this call made.  So I decided, lets look at that stored procedure and see what it does.  The SP will actually look at the "Perms" table for a "ScopeId", then it will replicate what it needs in all the related tables to create a copy of a parent scope (actually doesn't have to be a parent, but the SharePoint team doesn't let us do this through the UIs – wouldn't that be handy!).

So what is the problem?  Well…the problem centers on that pesky "ScopeId".  What is happening is that SharePoint has TWO ways to get permissions information:

  1. Get the scopeid from the AllLists table (using urls or ids)
  2. Get the scopeid from the perms table (using urls or ids)

UPDATE:  There is also a scopeid on the AllDocs table that also gets out of whack!

In some places the object model and the "obfuscated" SPRequest COM objects are making two different calls!  One will look at the AllLists table, the other will look at the Perms table.  This is the BUG.  ALL access APIs are using the "Perms" table, all UI APIs (including the CheckPermissions tool) are using the "AllLists" table.  They should look at the same place!  What is happening is the scopeID of imported objects is being set to the parent webs scopeID!  So even though the UI shows you what you WANT to see, the internals think that the permissions are that of the web's parent web!  THAT'S NOT GOOD!

How do you fix this?  Your not going to like the answer…none of the object model calls would reset the scopeid of the lists or webs.  I had to go into the database and reset the mapping of the scopeIds.  Once I did this, BAM!  Everything started working again…

Second big bug I have found in SharePoint 2010 in the last two weeks.

SQL Queries to help you find things:

Find List Scopes:

SELECT tp_Title, tp_ScopeId

= 'GUID'

Find Doc Scopes:

SELECT WebId, DirName, LeafName, scopeid
where DirName like '%blah%'

Find Web Scopes:

SELECT ID, FullUrl, scopeid
where fullurl like '%blah%'

Find Scope Permissions:

declare @scopeid as varchar(max)
set @scopeid = 'A3A5D2C8-5624-4E2A-BE7A-7D51C26DB081'

where scopeid in (@scopeid

select *
FROM RoleAssignment ra,
Roles r
where ScopeId =
and ra.RoleId = r.RoleId


Follow me on twitter: @givenscj

Check out the previous blog post:

SharePoint 2010 Delegated Administration

Have been wanting to try this for a while now and just now got some time to do it today.  The Central Administration site is just a SharePoint site with libraries and links, so I was curious what would happen if you were added to the site as a simple reader.  Here's the results:

As a reader and contributor, you do not gain access to Central administration and you will get the access denied error message.  The real magic comes in being in a specifically names group, there are two groups in the SCA:

  • Farm Administrators
  • Delegated Administrators

Full Control, Contributor and Read permission levels have no role to play in the links on the SCA.  What does matter is what group you reside in.  Being a Farm Administrator allows you to do anything in the SCA.  Being a Delegated lets you do a subset of actions, one of the items you cannot do is to create new Web Applications, but when it comes to the majority of other things, you can do them!  The thing that I would be more insterested in how one would target the links in Quick Launch to specific people.  IE, something like the following:

  • Web Application manager
  • Service Account Manager
  • Service Application Manager (like a global service app manager role rather than manually apply to each one)
  • Backup Restore Manager
  • Content Deployment Manager

Service applications have a completed different architecture to them.  Each service application can have an "Administrator" assigned to it.  I found a great article that describes this process here:

However, this also doesn't have much in terms of granular controls.  Its all or nothing for most of them.  These need more granular controls setup for them.  Security seems to be an afterthought in SharePoint, has been, probably always will be.


SharePoint Script to Find Empty Permissions Items/Lists/Sites

A common problem around SharePoint permissions is a site owner deleting ALL the permissions for an item.  This means that ONLY a Site Collection Admin can see the item/list/site!  This script can be run against each content   database to find all the empty permission objects!  This could have been done with object model, but it's too SLOW!

select fullurl + '' + dirname + '' + leafname, p.acl from alldocs items,perms p, webs w
items.Scopeid = p.scopeid
acl like 0xF3FE0000010000000000000000000000
items.webid =