Welcome to MSDN Blogs Sign in | Join | Help

Jeff Nuckolls {Application Platform and Development Tools}

Here you'll find a little of everything as it relates to the Microsoft Application Platform (Biztalk, Visual Studio Developer tools, SQL Server, Windows, .NET development/architecture, etc...). I may even touch on WSS/MOSS from time-to-time. While my blogs are widely applicable to all verticals, I'm dedicated to the Education vertical (K-12 and Higher Education).
Changing Item-level permissions in a Sharepoint List (WSS 3.0) with Elevated Privileges

Most blogs, books, articles, etc... provide some nice sample code, but they all assume that the user is logged on to Sharepoint as a Site Admin or someone with "Full Control" privileges. :-) 

What if you need to do something to the currently logged on user (which is NOT a Site Admin with Full Control) that requires elevated permissions... such as changing the user's item-level permission on a document they just added to the List.

Your knee jerk reaction is to steal a commonly published workaround for running code with elevated permissions by using...

SPSecurity.RunWithEleveatedPrivilege(delegate(){....//add your elevated privileged code here... });

The problem is that you have just changed the user context to Sharepoint\System, but you need it to be the actual logged on Domain\UserName, so you can change/lookup/remove/add/etc... that particular user's Group/Role Assignment affiliations and/or permissions.

So here is some sample code (that does NOT assume the logged on user has "Full Control" permissions already, although its ok if they do), that overrides the ItemAdded event handler and does some work requiring elevated permissions, but with the actual user context instead of Sharepoint\System.  It first checks if the user is in a particular Group, then based on that will remove their Group affiliations, and ultimately change their permissions ONLY on the file that they just added to the Document Library (this same code example applies to any Sharepoint List).  Note that I added a LogEvent method for basic debugging, but as a best practice I would use the Sharepoint Tracing log.


public override void ItemAdded(SPItemEventProperties properties)
{
    this.DisableEventFiring();
    base.ItemAdded(properties);

    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        using (SPSite _site = new SPSite(properties.WebUrl))
        {
            using (SPWeb _web = _site.OpenWeb(properties.RelativeWebUrl))
            {

                SPUserToken userToken = _web.AllUsers[properties.UserLoginName].UserToken;
                if (bIsInGroup(properties.WebUrl, properties.RelativeWebUrl, userToken, "Nuckolls University Professors") == false)
                {
                    LogEvent("================Changing Permissions==============");
                    SPListItem _item = _web.Lists[properties.ListId].GetItemById(properties.ListItemId);

                    _item.BreakRoleInheritance(true);

                    SPRoleAssignmentCollection sr = _item.RoleAssignments;
                    for (int i = sr.Count - 1; i > -1; i--)
                    {
                        sr.Remove(i);
                    }
                    LogEvent("=================Removed All Roles=================");
                    SPUserCollection users = _web.SiteUsers;
                    SPUser student = users[properties.UserLoginName];

                    SPRoleDefinition readerRoleDefinition = _web.RoleDefinitions.GetByType(SPRoleType.Reader);
                    SPRoleAssignment studentRoleAssignment = new SPRoleAssignment(student as SPPrincipal);
                    studentRoleAssignment.RoleDefinitionBindings.Add(readerRoleDefinition);
                    _item.RoleAssignments.Add(studentRoleAssignment);
                    LogEvent("================Permissions Changes================");
                }
                else
                {
                    LogEvent("This user is in the 'Nuckolls University Professors' group");
                }
                    _web.Dispose();
                }
                _site.Dispose();
            }
        });
    this.EnableEventFiring();
}

private bool bIsInGroup(string siteCollURL, string siteRelativeURL, SPUserToken userToken, string strGroupName)
{
    try
    {
        LogEvent("executed bIsInGroup");
            //Since we need to get site information in context of the "User" (ie. Domain\Steve")
            //instead of the user with elevated previledges (ie. Sharepoint\System), we are
            //creating a new Site object with the "UserToken" and evaluating the "User" with
            //a particular Sharepoint group.
            using (SPSite contextSiteColl = new SPSite(siteCollURL, userToken))
            {
                using (SPWeb contextSite = contextSiteColl.OpenWeb(siteRelativeURL))
                {
                    SPGroup userGroup = contextSite.Groups[strGroupName];
                    if (userGroup != null)
                    {
                        LogEvent(String.Format("Is user in group = {0}", userGroup.ContainsCurrentUser.ToString()));
                        if (!userGroup.ContainsCurrentUser)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    LogEvent("userGroup = null");
                    return false;
                }
            }
    }
    catch (Exception exception)
    {
        LogEvent("Error checking if user is in a particular group: " + exception.Message.ToString());
    }
    return false;
}


private void ChangeItemLevelPermissions(string user)
{
    LogEvent("We should change this user's permission because they are NOT a professor: " + user);
}

private void LogEvent(string debugMsg)
{
    StreamWriter sw = File.AppendText(@"C:\HomeworkListLog.txt");
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("[{0}] {1}", DateTime.Now.ToString(), debugMsg);
    sw.WriteLine(sb.ToString());
    sw.Close();
}

 

I hope this will save you time!  And if you've struggling with this for a while, as many others have, then I suggest you should bookmark this blog and get some sleep.  :-)

Posted: Wednesday, April 30, 2008 3:03 PM by jeffnuck
Filed under:

Comments

DT said:

Tell how and where to use this?

# March 24, 2009 6:57 AM

jeffnuck said:

Since I posted this, I've noticed additional references to it in Sharepoint 2007 Development books, so they may have other examples of use for this; however I envisioned it being used as a "drop box" for student's homework.  Another scenario would be a drop-box for resumes.  To finish these examples I would add the capability for a site admin (or teacher) to be able to reset these permissions at any time and/or add a Feature to provision additional drop-boxes for other assignments.  Some other examples would include a voting or feedback scenario... pretty much anywhere you want a write-once/read-only your data option.

# March 24, 2009 9:19 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker