Creating Item Level Security for an Event Receiver based upon metadata (Part 2)

clock June 3, 2009 03:20 by author steveboldt

After completing the process of creating a MOSS configuration list and the SetConfiguration method in the event receiver (Creating Item Level Security for an Event Receiver based upon metadata (Part 1)), it’s now time to create the methods for actually implementing the security for the individual documents.

SetSecurityForItem:

This method will set the applicable security for the document. For my purposes, I added a boolean field in the document library called ChangeSecurity that can be checked if different security needs to be applied.  Once this is done,  we need to call the method BreakRoleInheritance(false) so that it will not copy down the permissions from the library.  I did find when you call the ItemUpdated method, that you need to remove all inherited roles to be able to apply the correct assignment (See line 23). Therefore, one of the parameters passed into the SetSecuritForItem method requires the type of method being called (“ItemAdded”, “ItemUpdated”, etc…) At this point, we need to set the SPRoleDefinitionCollection (I chose to utilize caching in this instance again).  To obtain the role definitons, the SPWeb parameter is called. Following this, a new array of type SPRoleDefinition is created passing in the roleType from the custom list. Last portioin of this method is to iterate through the SPFieldUserValue to apply the permission to the document.

   1: #region SetSecurityForItem
   2:        // This function sets the Item Level Security for the document
   3:        private void SetSecurityForItem(SPItemEventProperties properties, SPWeb spWebSet, string methodType)
   4:        {
   5:            SPFieldUserValueCollection sharePointGroups;
   6:            SPList spList = properties.ListItem.ParentList;
   7:            SPListItem docItem = properties.ListItem;
   8:  
   9:            bool isChangeSecurity = (bool)docItem["ChangeSecurity"];
  10:  
  11:            if (isChangeSecurity)
  12:            {
  13:                sharePointGroups = group2;
  14:            }
  15:            else
  16:            {
  17:                sharePointGroups = group1;
  18:            }
  19:            //Break the Inheritance to assign new role definition to the group
  20:            docItem.BreakRoleInheritance(false);
  21:  
  22:            //Remove the previous RoleAssignment if this is an update
  23:            if (methodType == "ItemUpdated")
  24:            {
  25:                //remove all the inherited roles  
  26:                for (int i = docItem.RoleAssignments.Count - 1; i >= 0; --i)
  27:                {
  28:                    docItem.RoleAssignments.Remove(i);
  29:                }
  30:            }
  31:            // Get Role Definitions
  32:            SPRoleDefinitionCollection roleDefinitions = HttpRuntime.Cache.Get("WebRoleDefinitions") as SPRoleDefinitionCollection;
  33:            if (roleDefinitions == null)
  34:            {
  35:                roleDefinitions = spWebSet.RoleDefinitions;
  36:                HttpRuntime.Cache.Insert("WebRoleDefinitions", roleDefinitions);
  37:            }
  38:  
  39:            SPRoleDefinition[] rolesToApply = new SPRoleDefinition[1] { roleDefinitions[roleType] };
  40:  
  41:            foreach (SPFieldUserValue fuv in sharePointGroups)
  42:            {
  43:                addPermissionToListItem(properties.ListItem.Web, properties.ListItem, fuv, rolesToApply);
  44:            }
  45:  
  46:        }
  47:        #endregion

addPermissionToListItem is called in SetSecurityForItem which I will go into detail below:

addPermissiontoListItem:

With this method, it allows you to programmatically add security to a list item by the means of iterating through the values of a SharePoint User or Group column, including support for passing in a list of SPRoleDefinition items to grant to the security item. SPPrincipal represents either a user or group that will be assigned permissions.  Once we distinguish the type of SPPrincipal, a new SPRoleAssignment is created and the binding information is then iterated through and added to the role assignment. Finally, the group’s (or user’s) role assignment is then added to the list item. One thing to note about this method is that if the field user value is a User, a lookup is performed to obtain the SPPrincipal value (line 21)

   1: #region addPermissionToListItem
   2:        private void addPermissionToListItem(SPWeb SharePointWeb, SPListItem ListItemToAddTo, SPFieldUserValue UserOrGroupToAdd, params SPRoleDefinition[] RolesToGrant)
   3:        {
   4:            if (SharePointWeb != null && ListItemToAddTo != null && UserOrGroupToAdd != null && RolesToGrant != null && RolesToGrant.Length > 0)
   5:            {
   6:                SPPrincipal newItemToAdd = null;
   7:  
   8:                bool isUser = false;
   9:                try
  10:                {
  11:                    if (UserOrGroupToAdd.User != null)
  12:                    {
  13:                        isUser = true;
  14:                        newItemToAdd = UserOrGroupToAdd.User as SPPrincipal;
  15:                    }
  16:                }
  17:                catch { }
  18:  
  19:                if (!isUser)
  20:                {
  21:                    newItemToAdd = SharePointWeb.SiteGroups.GetByID(UserOrGroupToAdd.LookupId) as SPPrincipal;
  22:                }
  23:  
  24:                if (newItemToAdd != null)
  25:                {
  26:                    //Create a new assignment for the new group
  27:                    SPRoleAssignment newRoleAssignmentToAdd = new SPRoleAssignment(newItemToAdd);
  28:  
  29:                    //Get the role definitions binding collection for the new assignment
  30:                    foreach (SPRoleDefinition roleDefinition in RolesToGrant)
  31:                    {
  32:                        newRoleAssignmentToAdd.RoleDefinitionBindings.Add(roleDefinition);
  33:                    }
  34:  
  35:                    // Add Group
  36:                    ListItemToAddTo.RoleAssignments.Add(newRoleAssignmentToAdd);
  37:                }
  38:            }
  39:        }
  40:        #endregion

Final Step:

Create your overload methods for ItemAdded and ItemUpdated inheriting from the SPItemEventProperties. Make sure to call the methods above and also set the SPWeb value.

   1: #region ItemAdded
   2:        public override void ItemAdded(SPItemEventProperties properties)
   3:        {
   4:            base.ItemAdded(properties);
   5:  
   6:            if (properties.ListItem != null)
   7:            {
   8:                SPWeb spWeb = properties.ListItem.Web;
   9:  
  10:                SetConfiguration(spWeb, properties.ListTitle);
  11:  
  12:                if (applySecurity)
  13:                {
  14:                    SetSecurityForItem(properties, spWeb, "ItemAdded");
  15:                }
  16:            }
  17:        }
  18:        #endregion

Finally, build your project and deploy as a feature. That’s a brief overview of how to apply item level security based upon a metadata value.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Creating a SharePoint Custom Event Handler - Basics

clock June 1, 2009 14:06 by author steveboldt

I’ll review the basic steps on creating a SharePoint custom event handler.

You begin by opening up Microsoft Visual Studio 2005 and create a new class project. Reference the Microsoft.SharePoint assembly and then rename the default.cs class to the name that you want to give to your event handler. Also, remember to add your using statement for Microsoft.SharePoint.

Depending on which type of event handler you are wanting to write, will determine the proper SharePoint class to derive from. A breakdown of the available SharePoint classes to derive from are as follows:

  • List Items – SPItemEventReceiver
  • List Columns – SPListEventReceiver
  • Site – SPWebEventReceiver
  • Email - SPEmailEventReceiver

At this point, you need to make a decision on whether you want to use Asynchronous or Synchronous events in your event handler. In order to determine which one you want, first decide if you want the event to fire before or after the event.

Asynchronous calls occur after the event, and do not block any code being executed in SharePoint. On the flipside, synchronous calls occur before the event, will block code being executed in SharePoint until your custom event handler is completed.

For a list of the available methods for each class, refer to Microsoft’s site:

SPItemEventReceiver Methods
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spitemeventreceiver_methods.aspx

SPListEventReceiver Methods
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splisteventreceiver_methods.aspx

SPWebEventReceiver Methods
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spwebeventreceiver_methods.aspx

SPEmailEventReceiver Methods
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spemaileventreceiver_methods.aspx

Once you make your decision on what type of event receiver and also what type of method call you will be using, write out the override method . I will discuss further on manipulating particular methods.

Creating a Strong Name Key
After completing your method, you will need to sign the assembly. You can do this by going into solution explorer and right clicking your project and selecting properties. Then, click the Signing tab, then select Sign the Assembly, then select Choose a strong name key file and click “<New…>”. Type a name into the Key file name box (usually the name of your project). It needs to be in the format of xxxxxx.snk. You can set a password if you want, and click OK.

Creating Event Receiver to be installed as a Feature
Right click on your event handler project and select Add / New Folder. Name the folder as the same name as the project or similar. Add to blank XML files under the folder. Name the XML files as elements.xml and the other feature.xml.

In the feature.xml file, it should follow the following format:

<Feature Scope="Web"
    Title="My Event Handler"
    Description ="Description goes here."
    Id="F141E5EA-796E-4807-AB86-43F5DC560371"
    xmlns="http://schemas.microsoft.com/sharepoint/">
    <ElementManifests>
        <ElementManifest Location="elements.xml"/>
    </ElementManifests>
</Feature>

For further explanation, refer to the Microsoft site for all the available nodes.
http://msdn.microsoft.com/en-us/library/ms436075.aspx

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Receivers ListTemplateId="101">
        <Receiver>
            <Name>MyEventHandler</Name>
            <Type>ItemAdded</Type>
            <SequenceNumber>10000</SequenceNumber>
            <Assembly>MyEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1cd942f82aed8c82</Assembly>
            <Class>MyEventHandler.EventHandler</Class>
            <Data></Data>
            <Filter></Filter>
        </Receiver>
    </Receivers>
</Elements>

In the elements.xml, the ListTemplateId refers to which list to associate the event handler. 101 = document library. For a description of the available id, see here: http://msdn.microsoft.com/en-us/library/ms462947.aspx

The <Type> node refers to the method that will be raised when the action takes place. For multiple methods, you will need multiple <Receiver> nodes. <SequenceNumber>node refers to the order of execution.

Add a text file to the root of the project and rename it to cab.ddf and input the following:

;** MyEventHandler.wsp **
.OPTION EXPLICIT
.Set CabinetNameTemplate= MyEventHandler.wsp
.Set DiskDirectoryTemplate=CDROM
.Set CompressionType=MSZIP
.Set UniqueFiles="ON"
.Set Cabinet=on
.Set DiskDirectory1=Package
;**************************************************
manifest.xml manifest.xml
MyEventHandler\elements.xml MyEventHandler \elements.xml
MyEventHandler \feature.xml MyEventHandler \feature.xml
bin\debug\ MyEventHandler.dll MyEventHandler.dll

Then add another text file and rename that one to installer.bat. The following should be inputted:

makecab /f cab.ddf

 

Add a new xml file to the root of the project and rename it to manifest.xml and input the following:

<?xml version="1.0" encoding="utf-8" ?>
<Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="BF2A762B-A158-456c-BCA5-38120E87D982">
    <FeatureManifests>
        <FeatureManifest Location="MyEventHandler\feature.xml"/>
    </FeatureManifests>
    <Assemblies>
        <Assembly DeploymentTarget="GlobalAssemblyCache"  Location="MyEventHandler.dll">
        </Assembly>
    </Assemblies>
</Solution>

Save all your work and build your project.

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5