Pages

Friday, April 8, 2011

How to programmatically copy Web Level, List level and List Item Level Security Information for SharePoint Sites

 

[Note : This post is part of  my main blog “Moving Large MOSS 2007 Sites” and “SharePoint 2010 Migration”]

Some Background

[See my other blog on Drawbacks of current List Export and Import MOSS 2007 Content Migration APIs]

How to fix this gap?

Well, there are SharePoint APIs you can use to copy all the necessary missing security information. But there needs to be an order to perform the process most efficiently. Follow below order of steps:

  • First you will be creating a new site collection, or you may already have your target importing site collection existing.
  • In any case before you perform your Import, you want to first copy over the Custom Permission Level.
  • Next you want to perform your usual Import with All security Included. (settings.IncludeSecurity = SPIncludeSecurity.All)
  • Above Import process will ensure to import all the Users and SharePoint Groups and any OOTB Permission Levels as applicable.
  • Now you want to Copy all the Web level Permission Assignments. Having all ready  copied the custom permission levels, this step will ensure all the permission assignments are appropriately copied over.
  • Next you can attend for each of the lists and libraries you have imported, copy the Permission Assignments.
  • Next you can attend for each Items in your lists and libraries you have imported, copy the Item Level Permission Assignments.

 

Below are the methods for each of these above tasks:

Your call order:

1. PrepareNewSiteCollection();//Here either create the new site collection in preparation for Import, or simply establish your site collection SPSite object.

2. CopyWebRoleAssignments(); //Here copy the web level permission levels.

3. PerformListExportImporting(); //Here perform your List Export and Import.

4. CopyWebRoleAssignments();//Here perform your Web level Permission Assignments copy.
5. CopyListRoleAssignments(); //Here finally copy your List and List item level permissions.

 

Common Methods:

        public static void CopyWebRoles(SPWeb sourceWeb, SPWeb destinationWeb)
{

//First copy Source Web Role Definitions to the Destination Web
foreach (SPRoleDefinition roleDef in sourceWeb.RoleDefinitions)
{
//Skip WSS base permission levels
if (roleDef.Type != SPRoleType.Administrator
&& roleDef.Type != SPRoleType.Contributor
&& roleDef.Type != SPRoleType.Guest
&& roleDef.Type != SPRoleType.Reader
&& roleDef.Type != SPRoleType.WebDesigner
)
{
//handle additon of existing permission level error
try { destinationWeb.RoleDefinitions.Add(roleDef); }
catch (SPException) { }
}
}


}


public static void CopyWebRoleAssignments(SPWeb sourceWeb, SPWeb destinationWeb)
{

//Copy Role Assignments from source to destination web.
foreach (SPRoleAssignment sourceRoleAsg in sourceWeb.RoleAssignments)
{
SPRoleAssignment destinationRoleAsg = null;

//Get the source member object
SPPrincipal member = sourceRoleAsg.Member;

//Check if the member is a user
try
{
SPUser sourceUser = (SPUser)member;
SPUser destinationUser = destinationWeb.AllUsers[sourceUser.LoginName];
if (destinationUser != null)
{
destinationRoleAsg = new SPRoleAssignment(destinationUser);
}
}
catch
{ }

if (destinationRoleAsg == null)
{
//Check if the member is a group
try
{
SPGroup sourceGroup = (SPGroup)member;
SPGroup destinationGroup = destinationWeb.SiteGroups[sourceGroup.Name];
destinationRoleAsg = new SPRoleAssignment(destinationGroup);
}
catch
{ }
}

//At this state we should have the role assignment established either by user or group
if (destinationRoleAsg != null)
{

foreach (SPRoleDefinition sourceRoleDefinition in sourceRoleAsg.RoleDefinitionBindings)
{
try { destinationRoleAsg.RoleDefinitionBindings.Add(destinationWeb.RoleDefinitions[sourceRoleDefinition.Name]); }
catch { }
}

if (destinationRoleAsg.RoleDefinitionBindings.Count > 0)
{
//handle additon of an existing permission assignment error
try { destinationWeb.RoleAssignments.Add(destinationRoleAsg); }
catch (ArgumentException) { }
}

}

}

//Finally update the destination web
destinationWeb.Update();

}


public static void CopyListRoleAssignments(SPList sourceList, SPList destinationList)
{
//First check if the Source List has Unique permissions
if (sourceList.HasUniqueRoleAssignments)
{

//Break List permission inheritance first
destinationList.BreakRoleInheritance(true);

//Remove current role assignemnts
while (destinationList.RoleAssignments.Count > 0)
{
destinationList.RoleAssignments.Remove(0);
}


//Copy Role Assignments from source to destination list.
foreach (SPRoleAssignment sourceRoleAsg in sourceList.RoleAssignments)
{
SPRoleAssignment destinationRoleAsg = null;

//Get the source member object
SPPrincipal member = sourceRoleAsg.Member;

//Check if the member is a user
try
{
SPUser sourceUser = (SPUser)member;
SPUser destinationUser = destinationList.ParentWeb.Users.GetByEmail(sourceUser.Email);
destinationRoleAsg = new SPRoleAssignment(destinationUser);
}
catch
{ }

if (destinationRoleAsg == null)
{
//Check if the member is a group
try
{
SPGroup sourceGroup = (SPGroup)member;
SPGroup destinationGroup = destinationList.ParentWeb.SiteGroups[sourceGroup.Name];
destinationRoleAsg = new SPRoleAssignment(destinationGroup);
}
catch
{ }
}

//At this state we should have the role assignment established either by user or group
if (destinationRoleAsg != null)
{

foreach (SPRoleDefinition sourceRoleDefinition in sourceRoleAsg.RoleDefinitionBindings)
{
try { destinationRoleAsg.RoleDefinitionBindings.Add(destinationList.ParentWeb.RoleDefinitions[sourceRoleDefinition.Name]); }
catch { }
}

if (destinationRoleAsg.RoleDefinitionBindings.Count > 0)
{
//handle additon of an existing permission assignment error
try { destinationList.RoleAssignments.Add(destinationRoleAsg); }
catch (ArgumentException) { }
}

}

}

//Does not require list update
//destinationList.Update();
}
else
//No need to assign permissions
return;



}

public static void CopyListItemsRoleAssignments(SPList sourceList, SPList destinationList)
{
foreach (SPListItem sourceListitem in sourceList.Items)
{
CopyListItemRoleAssignments(sourceListitem, destinationList.GetItemById(sourceListitem.ID));
}

}
public static void CopyListItemRoleAssignments(SPListItem sourceListItem, SPListItem destinationListItem)
{
//First check if the Source List has Unique permissions
if (sourceListItem.HasUniqueRoleAssignments)
{

//Break List permission inheritance first
destinationListItem.BreakRoleInheritance(true);
destinationListItem.Update();

//Remove current role assignemnts
while (destinationListItem.RoleAssignments.Count > 0)
{
destinationListItem.RoleAssignments.Remove(0);
}
destinationListItem.Update();

//Copy Role Assignments from source to destination list.
foreach (SPRoleAssignment sourceRoleAsg in sourceListItem.RoleAssignments)
{
SPRoleAssignment destinationRoleAsg = null;

//Get the source member object
SPPrincipal member = sourceRoleAsg.Member;

//Check if the member is a user
try
{
SPUser sourceUser = (SPUser)member;
SPUser destinationUser = destinationListItem.ParentList.ParentWeb.AllUsers[sourceUser.LoginName];
if (destinationUser != null)
{
destinationRoleAsg = new SPRoleAssignment(destinationUser);
}
}
catch
{ }

//Not a user, try check if the member is a Group
if (destinationRoleAsg == null)
{
//Check if the member is a group
try
{
SPGroup sourceGroup = (SPGroup)member;
SPGroup destinationGroup = destinationListItem.ParentList.ParentWeb.SiteGroups[sourceGroup.Name];
if (destinationGroup != null)
{
destinationRoleAsg = new SPRoleAssignment(destinationGroup);
}
}
catch
{ }
}

//At this state we should have the role assignment established either by user or group
if (destinationRoleAsg != null)
{

foreach (SPRoleDefinition sourceRoleDefinition in sourceRoleAsg.RoleDefinitionBindings)
{
try { destinationRoleAsg.RoleDefinitionBindings.Add(destinationListItem.ParentList.ParentWeb.RoleDefinitions[sourceRoleDefinition.Name]); }
catch { }
}

if (destinationRoleAsg.RoleDefinitionBindings.Count > 0)
{
//handle additon of an existing permission assignment error
try { destinationListItem.RoleAssignments.Add(destinationRoleAsg); }
catch (ArgumentException) { }
}

}

}

//Ensure item update metadata is not affected.
destinationListItem.SystemUpdate(false);
}
else
//No need to assign permissions
return;



}



 





Technorati Tags:

16 comments:

Anonymous said...

HI

ABOVE CODE HELPED ME A LOT. THANX FOR THAT BUT UNABLE TO ADD LIMITED ACCESS LEVEL.
HELP ME OUT. THANKS IN ADVANCE.

Rajesh Agadi said...

Hello Anonymous,

Limitted Access Permission is not available for us to assign to users.

In SharePoint content hierarchy when the Permission inheritence is broken at any level and a specific permissions are assigned at say an Item Level, that user gets added to the root site as Limitted Access.

So in terms of rights it gets nothing to that specific user at the root site level.

Hope this answers your questions. Otherwise describe your scenario for why you need to assign a Limitted Access?

Cheers!
-Rajesh

Anonymous said...

Thank You
Great Work
Saved me a lot of time

Casey said...

Thanks so much for the method to copy permissions from one web to another. You saved me a days worth of work! I posted it as an answer here... http://stackoverflow.com/questions/19256037/sharepoint-2013-server-object-model-copy-permissions-from-one-site-to-another-d

Casey

Casey said...

I'm using CopyWebRoleAssignments() to copy permissions from one web to another web. Both site collections have the groups I am copying. There are Active Directory groups in the sharepoint group. The AD groups do not copy. Do you know why?

Rajesh Agadi said...

Casey,

There are two situations when the Active Directory Users/Groups do not get copied over:

1. When the source AD User/Group are not valid/active or disabled/deleted from the AD.

2. When the target is not in the same domain and/or do not have AD trust.

I assume this may not be your case. Other than above, I guess you may have some other run time error.

-Rajesh

Casey said...

I figured out the issue. I updated it here... http://stackoverflow.com/a/19256944/1711994

The issue was, I am copying permissions across site collections. The users/groups I was copying had never accessed the destination collection. I had to add SPWeb.EnsureUser() to your user check. That way if the user does not exist in the destination, it is added.

Hes said...

Can I use this solution to copy permissions from a sp 2003 site to sp 2013 site?

Rajesh Agadi said...

Hes,

Short answer is may be. Remember, the API reference for copying the source security data from SPS 2003 should have SP 2003 assemblies.

While to copy in to the SP 2010 you will need reference to SP 2010 API assemblies.

So the source objects you instantiate to read from SP 2003 will be unique will work against only the SP 2003. For SP 2010 you will have to instantiate SP 2010 Objects.

Having said that, what it really means is you insatiate your SP 2003 objects, read the security data, then instaliate your SP 2010 Objects and perform property assignments from Sp 2003 objects to SP 2010, then update your Sp 2010 Objects.

Hope this helps.

-Rajesh

Hes said...

Hi Rajesh, I'm not sure if you did read my question correctly - I want to copy/migrate to SP 2013, not 2010.

Hes said...

Another question - is it possible to migrate users rights from SP2003 to SP2013?

Rajesh Agadi said...

Hes,

The same rules apply to copy from SP 2003 to SP 2013.

In your code base, you have to reference SP 2003 and SP 2013. All the above said equally applied here as well.

Hope this helps.
-Rajesh

Hes said...

Thanks for your help Rajesh!

Unknown said...

Hi Rajesh,

I need to migrate sites from one site collection to another.
For that I need to clone permission groups (including custom one ) from old root sitecollection to another site collection in a same web application. May you please helpme out here .
Thanks
Kunal

Rajesh Agadi said...

Hi Kunal,

The code base here should help you address copy the custom permission level and custom SharePoint groups as well.

What is your specific challenge?

-Rajesh

Unknown said...

Hi Rajesh,

This is very useful code to copy contents from one subsite to another within same site collections. I have done in dev env as well as in PreProd env, till that time it was working. Once i moved to production for go live, this tool is throwing errors "item does not exist,it may be deleted by some other users". My tool runs copy site groups, copy lists and copy libraries same time simultaneously.

Please suggest.

Rajesh Kumar