Modifying My Site Owner Security


This blog posting applies to Microsoft Office SharePoint Server 2007.

When someone creates a MySite, they are automatically given full control of that site.  More accurately: a MySite is a site collection; the creator becomes the first & only Site Collection Administrator; the creator is made a member of the Owners group. 

Some people feel that this is too much control, and they’d like to limit it in some way.  My first piece of advice in this situation is: don’t.  MySites are built with dependencies on the permissions and identity of the owner, the person who created the site.  Changing this can introduce undesirable or confusing behavior.  Then, if requirements later change, after hundreds or thousands of people have created their MySite, more code must be written to effect those changes.  But if you insist on going down this path, I found a way to meet this seemingly simple request.  The answer is most certainly not simple.

Basically, you have to follow Steve Peschka’s approach described in the blog entry customizing My Sites as the framework for doing this.  Then, add code to that scheme that knows how to change the security.  There are a few added challenges:

  • You must do two things: 1) change the creator’s group membership and 2) remove them as a Site Collection Administrator.
  • To give the creator of the MySite specific privileges, you typically want to create a custom privilege level and add the user into that group.  The benefit is that you can tweak this to allow/prevent actions at a fairly granular level, such as being able to block the ability to add subsites.
  • The creator of the MySite is the only Site Collection Administrator, so you can’t remove this person from this role until you first put someone else in there.  For best governance, this should be a user account that’s not really associated with an individual, but shared among trusted admins.  Unfortunately it must be a user account, not a group.
  • There seems to be a timer job that fixes up the title of the MySite to match the name of the site administrator… so you need some code that resets this back every time the user opens the site.

Why can’t we just change the MySite site definition (template)?  Two reasons:

  • Modifying the MySite site definition is “unsupported” by Microsoft.  If you did it, then wanted help with problems related to it, the support engineer would make a best effort, but could not guarantee a fix.  Steve’s article talks more about this.
  • Moot point!  User security is not stored in the site definition, so even if it were supported to modify it, there would be nothing to do.

Below are code samples that address the challenges listed above.  Your job would be to integrate them with Steve Peschka’s code.  Sorry I can’t give a more complete solution.  This is one task that is very difficult to accomplish in SharePoint, and the methods described are the only way we know of doing it in a supported way.

(BTW, I use lots of try…catch blocks here to get the most granular logging.  You can implement Utility.LogMessage any way you like; I use MSDN’s Trace Log Example to write to the ULS logs, and CodePlex’s Log Viewer Feature to read them.)

public void RestrictMySiteOwner()
{
    SPUserInfo originalOwnerInfo = new SPUserInfo();
    SPUserInfo newOwnerInfo = new SPUserInfo();
// Store the original owner in site properties so we can restore it later if necessary try { StoreValueInSiteProperty(_curWeb, "OriginalOwner", MakeUserInfoString(originalOwnerInfo)); Utility.LogMessage("Stored original administrator in site property."); } catch (Exception ex) { Utility.LogMessage("Error: can't store original administrator in site property. " + ex.Message); }
// Switch out the primary site administrator with a pre-defined one. try { newOwnerInfo.LoginName = "DOMAIN\MySitesAdmin"; newOwnerInfo.Email = "mysitesadmin@customer.com"; newOwnerInfo.Name = "MySites domain manager"; newOwnerInfo.Notes = "Owner of all MySites"; originalOwnerInfo = ReplacePrimarySiteAdministrator(_curWeb, newOwnerInfo); Utility.LogMessage("Switched primary administrator."); } catch (Exception ex) { Utility.LogMessage("Error: can't replace primary administrator. " + ex.Message); }
// Add the My Site creator to a group with limited permissions to control what is permissible on the site try { ChangeCurrentUserPermission(_curWeb, "Restricted Owner"); Utility.LogMessage("Changed current user permissions."); } catch (Exception ex) { Utility.LogMessage("Error: can't change current user permissions. " + ex.Message); }
// Reset the name of the site back to original owner (was changed by switching primary site admin) try { SetSiteTitle(_curWeb, originalOwnerInfo.Name); Utility.LogMessage("Reset site title."); } catch (Exception ex) { Utility.LogMessage("Error: can't reset site title. " + ex.Message); } } protected SPUserInfo ReplacePrimarySiteAdministrator(SPWeb site, SPUserInfo newAdminInfo) { SPUser originalOwner = null; SPUserInfo originalOwnerInfo = new SPUserInfo(); SPSecurity.RunWithElevatedPrivileges(delegate() { // Get the parent site collection SPSite sitecollection = site.Site;
originalOwner = sitecollection.Owner; originalOwnerInfo = Utility.GetUserInfo(originalOwner); if (newAdminInfo.LoginName != originalOwnerInfo.LoginName) { try { // Add new admin to Full Control group SPRoleDefinition admins = site.RoleDefinitions["Full Control"]; if (admins != null) { SPRoleAssignment roleAssignment =
new SPRoleAssignment(newAdminInfo.LoginName, newAdminInfo.Email,
newAdminInfo.Name, newAdminInfo.Notes); SPRoleDefinitionBindingCollection roleDefBindings =
roleAssignment.RoleDefinitionBindings; roleDefBindings.Add(admins); site.RoleAssignments.Add(roleAssignment); //site.Update(); // Don't need to do this } // Reset owner of site collection to new admin sitecollection.Owner = site.Users[newAdminInfo.LoginName]; sitecollection.Owner.Update(); //change the userprofile guid of the site sitecollection.Properties["urn:schemas-microsoft-com:sharepoint:portal:profile:userprofile_guid"] = toProfile.ID.ToString().Replace("{", string.Empty).Replace("}", string.Empty); sitecollection.Properties.Update(); } catch (SPException ex) { // We may get here if the user running this thread is the same as the
// aministrator we're trying to remove.
Utility.LogMessage("Error: can't replace primary administrator. " + ex.Message); } } }); return originalOwnerInfo; } protected void ChangeCurrentUserPermission(SPWeb site, string roleDefinitionName) { SPUser curUser = site.CurrentUser; string curUserName = curUser.LoginName; SPRoleDefinition roleDefFull = null; // Full control privilege level SPRoleDefinition roleDefContributor = null; // Contributor privilege level SPRoleDefinition roleDefLimitedOwner = null; // Our new privilege level // Create new role definition try { // Get existing role definitions roleDefFull = site.RoleDefinitions["Full Control"]; roleDefContributor = site.RoleDefinitions["Contribute"]; // Create custom role definition roleDefLimitedOwner = new SPRoleDefinition(); roleDefLimitedOwner.Name = roleDefinitionName; roleDefLimitedOwner.Description = "Permission settings for the owner of this MySite."; site.FirstUniqueRoleDefinitionWeb.RoleDefinitions.Add(roleDefLimitedOwner); site.FirstUniqueRoleDefinitionWeb.Update(); // Get the new role definition again... makes sure the Update took all the way or something. roleDefLimitedOwner = site.FirstUniqueRoleDefinitionWeb.RoleDefinitions[roleDefinitionName]; // Set permissions of new role... start from Contributor as base. roleDefLimitedOwner.BasePermissions = roleDefContributor.BasePermissions; // To ADD a permission, use Bitwise-Or assignment: permissions |= permission // To REMOVE, use Bitwise-And assignment to Complement: permissions &= ~permission roleDefLimitedOwner.BasePermissions |= SPBasePermissions.CancelCheckout; roleDefLimitedOwner.BasePermissions &= ~SPBasePermissions.AddDelPrivateWebParts; roleDefLimitedOwner.BasePermissions &= ~SPBasePermissions.UpdatePersonalWebParts; roleDefLimitedOwner.Update(); } catch (Exception ex) { Utility.LogMessage("Error: can't create new permission group \""
+ roleDefinitionName + "\". " + ex.Message); } // Add owner to new role definition try { SPRoleAssignment assignment = new SPRoleAssignment(curUser); if (roleDefLimitedOwner != null) { assignment.RoleDefinitionBindings.Add(roleDefLimitedOwner); } else { //Workaround: for now we just make owner a contributor assignment.RoleDefinitionBindings.Add(roleDefContributor); } site.RoleAssignments.Add(assignment); //site.Update(); // Don't need to do this
} catch (Exception ex) { Utility.LogMessage("Error: can't add user \"" + curUserName
+ "\" to new permission group \"" + roleDefinitionName + "\". " + ex.Message); } // Remove owner from Full Control try { SPRoleAssignment userRoleAssignment = UserRoleAssignment(site, curUser, roleDefFull); if (userRoleAssignment != null) { userRoleAssignment.RoleDefinitionBindings.Remove(roleDefFull); userRoleAssignment.Update(); } //site.Update(); // Don't need to do this } catch (Exception ex) { Utility.LogMessage("Error: can't remove user \"" + curUserName
+ "\" from default permission groups. " + ex.Message); } }


private SPRoleAssignment UserRoleAssignment(SPWeb site, SPUser curUser, SPRoleDefinition curRoleDef) { foreach (SPRoleAssignment roleAssignment in site.RoleAssignments) { if (roleAssignment.Member.ID == curUser.ID) { foreach (SPRoleDefinition roleDefinition in roleAssignment.RoleDefinitionBindings) { if (roleDefinition.Id == curRoleDef.Id) { return roleAssignment; } } } } return null; } protected void StoreValueInSiteProperty(SPWeb site, string propertyName, string propertyValue) { if (site.Properties.ContainsKey(propertyName)) site.Properties[propertyName] = propertyValue; else site.Properties.Add(propertyName, propertyValue); site.Properties.Update(); } protected void SetSiteTitle(SPWeb site, string title) { try { site.Title = title; //site.Update(); // Don't need to do this } catch (Exception ex) { Utility.LogMessage("Error: can't set site title to \"" + title + "\". " + ex.Message); } }
Comments (14)

  1. Suche FTP-Sites mit SharePoint 2007 / Search Server 2008 indizieren Tools Smart Search for SharePoint

  2. Suche FTP-Sites mit SharePoint 2007 / Search Server 2008 indizieren Tools Smart Search for SharePoint

  3. rajeshnerenki says:

    Hi Mark,

    Thanks for the good article. We have the same requirement where we are supposed to disable create rights on the MySite for all users for now. In future it should be easily CONFIGURABLE to allow certain users the ability to create lists, discussions, blogs etc.

    We have taken the same code from your article, everything seems to be working except removing the FullControl role definition binding for the owner. When we debug, we see the user has only the custom role definition, but it actually still exists once the site is created. When we go to site permissions, we see Full Control along with custom role definition. Because of this, though the user is not a site collection administrator, he still gets all create rights. What could be the problem? Is it because the the site is already provisioned when the feature is activated?

    Also with the above approach, there is a limitation that in future if some users have to be given access to creating lists, discussion forums etc. we’ll not be able to do it, unless we run a batch file to again add the user to site collection administrator or give appropriate rights. Is there a way to do this, say When the mysite is getting loaded, check an xml or external list which has the list of people who can be given create rights and based on that enable site actions, create permissions etc?

    Regards

    Rajesh

  4. Mark Arend says:

    Hmm… someone else was having this problem, I haven’t heard back from them on any progress.  How did you implement the code from the blog, did you invoke it from a master page control as Steve Peschka described in his article?  Are any of the catch blocks being executed?  Can you log what’s going on from ReplacePrimarySiteAdministrator?  

    I might try to make another test of this but have been very busy and probably can’t get to it for awhile.  The code worked successfully for me when I wrote it, but I had to pull it out of context for the blog.  Maybe I missed something from where these methods were called from.  I remember it was a little hard getting everything to work.  Logging is your friend here to see what the code is doing.

  5. rajeshnerenki says:

    Thanks for the reply. Currently we have all the code in the FeatureActivated event of the MySiteStaplee feature. We don’t get any exception, but the Full Control role definition is not being removed from the roleassignment of the user. What we’ll try is to put the code in the master page webcontrol as you suggested. There is a function "ReplacePrimarySiteAdministrator" which is not being called any where now. I guess it has to be called before we remove Full control for the current owner.

    Do you have any suggestion on how to enable create rights for certain users in future? Is it possible to enable/disable create rights for mysite through some configuration entries?

  6. bharg says:

    Hi Mark, i had sent u a mail regarding the same problem as told by Rajesh in the above posting and u had asked me what approach i am using –

    i have added this permission related code to the feature activation event (as said in Steve Peschka’s blog).

    and no exception is caught in ReplacePrimarySiteAdministrator function.

    The ReplacePrimaryAdministrator is working fine as the site collection admin is replaced.The problem is, the original owner is still retaining the Full Control permission.

  7. rajeshnerenki says:

    Thanks Mark for your help. The original code worked fine when we moved it as a part of webcontrol in the master page from the FeatureActivated event..

  8. Mark Arend says:

    Rajesh, you’re welcome… I integrated the original code that worked for you into an update of the blog and removed the comment that included that code on this commments page to avoid further confusion.

  9. bharg says:

    Thanks Mark, the permission stuff worked fine after moving it to a webcontrol.

    I have one more issue, i have a list in MySite public site collection and i want to access the list items in my personal site collection, Is it possible? I get access denied exception.

    To expain –

    The above permission related code should execute for only specific users, so i created a list in MySite Public site collection, which will have the users for whom the permission related code should not execute.

    and I do a check in my webcontrol for those users, but i get access denied when I try to access the list.

    Is there any way to achieve this? or am i doing something wrong !!!

  10. Mark Arend says:

    M. Bharg,

    If I am interpreting what you mean by "public site collection," this is the one at the root of the MySite host web application.  See http://blogs.msdn.com/markarend/archive/2008/02/22/mysite-pages-and-architecture.aspx for an explanation of how MySite site collections and the "Profile" or "Person" site collection are set up.  Your web control is probably executing with the identity of the MySite user, so you need to give all those users rights to the list.  Also, look at your code to see how you are getting to the list… do you open the site collection or even the web application?  Whatever your code is accessing, your MySite users must have the rights to.  Or, as an alternative, you could use RunWithElevatedPrivilege in your code so that it runs under a SharePoint system identity.  An example of doing this is in the code sample for this blog entry.

  11. bharg says:

    Hi Mark,

    using RunWithElevatedPrivileges, i was able to access the list, and the list items, but when i try to change the site collection admin i get access denied exception.

    I have followed ur approach and so when my MySite is created i have only read permissions. Using RunWithElevatedPrivileges can i add myself back to the site collection administrators ? Is this possible ?

  12. Mark Arend says:

    Sorry this is not working for you yet.  Logging exceptions is the key to debugging here.

    Yes, using RunWithElevatedPrivileges you should be able to add yourself back.  Note with this call, there are some restrictions on how you must do things.  For instance, if you create an SPSite object, then use RunWithElevatedPrivileges to access it, it will NOT be accessed with elevated privileges… you must create the SPSite object in the anonymous delegate.  Be sure to dispose the object if you created it anew.  Reference blogs that discuss it.  http://geekswithblogs.net/DanielC/archive/2008/01/28/sharepoint-security-runwithelevatedprivileges.aspx is good. Here’s the brief MSDN overview  http://msdn.microsoft.com/en-us/library/aa543467.aspx

  13. bharg says:

    Thanks Mark, thanks a lot.. the mistake i had done was – i was creating the SPSite object outside RunWithElevatedPrivileges delegate.

    Now it works.

Skip to main content