User Impersonation with the User Token


Two primary ways exist to create the SPSite as a security context. One way is to use the current Windows or Forms identity, which is the default method whether you are accessing the site from the WSS Web application or an administrative console. This is also the method used with the SPSecurity.RunWithElevatedPrivileges delegate-the current principal that happens to be SHAREPOINT\system is used to create the site security context.

The other way to create the SPSite is by using an SPUserToken object. The SPUserToken is the token created upon authentication. It references the principal of the user from either Active Directory or the identity store with its groups and roles. In the case of a Windows identity, this token is used to query Active Directory for the TokenGroups property. These tokens time out after 24 hours, making them a good candidate for system code that needs to impersonate users in the case of workflow actions or post-processing of list data that happens slightly after the original action (not days later). This token timeout value can be set by using the STSADM console. Using the user token in the constructor of the SPSite enables code to make changes to the WSS object model just as if the actual user were making the changes. Using impersonation is a security-sensitive operation that requires the SharePointPermission with the Impersonate property set to true.

You can request the token for any user in the system by using the UserToken property of the SPUser class (provided that your code has the SharePointPermission with the Impersonate rights). If the current user is not the user requested, WSS builds the token on the fly from the user’s Security ID and group membership. You can then pass this token to the SPSite’s contructor to create a new impersonated security context.

For example, let’s revisit the list event receiver from Chapter 6, “Lists and Content Types.” On creation of a Litware Company record in either the Vendor or Customer list, we will create an announcement with the credentials of the user who created the item. When this code runs, it is in the context of the SHAREPOINT\system account, and we don’t have access to the actual credentials of the user who created the item. To create the item under the impersonated security context, simply obtain a user token from the SPUser profile that created the object and pass that into the SPSite constructor. When the item is inserted into the announcements list, it will be as if the impersonated user created the item even though the event receiver is running under the identity of SHAREPOINT\system.

 public override void ItemAdded(SPItemEventProperties properties) {   DisableEventFiring();   string CompanyName = properties.ListItem["Company"].ToString();   properties.ListItem["Company"] = FormatStringValue(CompanyName);   properties.ListItem.Update();   SPUserToken token =     properties.OpenWeb().AllUsers[properties.UserLoginName].UserToken;   using( SPSite site = new SPSite(properties.SiteId, token) )   {       using(SPWeb web = site.OpenWeb(properties.WebUrl))       {         SPListItem announcement = web.Lists["Announcements"].Items.Add();         announcement["Title"] = properties.ListItem["Company"].ToString();         announcement["Body"] = "A new company was added!";       }   }

Within this code sample, we are using the AllUsers property of the site. Users are available through a reference to the site (the SPWeb class). Three user collections are available within the site, and choosing which one to use may be confusing. The AllUsers property lists all users, including members of the site as well as members of domain groups that are members of the site. The SiteUsers property contains the users who are members of the site collection, and the Users property is the smallest group, containing only users who are explicitly members of the site.

Securing Objects with WSS

Objects in WSS are secured with the ISecurableObject interface, which is applied to the SPWeb, SPList, and SPListItem classes. Because of this, most objects of significance in WSS are secured with this interface, which is shown in Listing 10-5.

Listing 10-5: The ISecurableObject interface

image from book
  Microsoft.SharePoint.ISecurableObject [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true), SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel = true)] public interface ISecurableObject {   // Methods   void BreakRoleInheritance(bool CopyRoleAssignments);   void CheckPermissions(SPBasePermissions permissionMask);   bool DoesUserHavePermissions(SPBasePermissions permissionMask);   void ResetRoleInheritance();   // Properties   SPRoleDefinitionBindingCollection AllRolesForCurrentUser { get; }   SPBasePermissions EffectiveBasePermissions { get; }   ISecurableObject FirstUniqueAncestor { get; }   bool HasUniqueRoleAssignments { get; }   SPReusableAcl ReusableAcl { get; }   SPRoleAssignmentCollection RoleAssignments { get; } } 
image from book

ISecurableObject provides a method for checking whether permissions exist as well as a method for demanding that the permissions exist. The first method, DoesUserHave-Permissions, is used to query for permissions, whereas the second method, CheckPermissions, throws a security exception if the permission does not exist. Because this interface is common throughout the object model, it is easy to learn how to use it throughout your code. For example, to check whether the current user has permissions to view list items, you can call the DoesUserHavePermissions method of the SPWeb class passing in the ViewListItems permission flag as follows:

 SPWeb web = SPContext.Current.Web ; if (web.DoesUserHavePermissions(SPBasePermissions.ViewListItems){     // Enumerate lists }

The SPList is also an ISecurableObject, which means that you can apply the same principles to check permissions on lists. To check the user’s permission to view list items within a specific list, call the list’s DoesUserHavePermissions method as follows:

 foreach(SPList list in  web.lists){   if (list.DoesUserHavePermissions(SPBasePermissions.ViewListItems))     // Process the list   } }

Likewise, the same method is available in other objects, such as the SPListItem class, which can be used to ensure that the user has permissions to the item or document.

 foreach(SPListItem item in list.Items){   if (item.DoesUserHavePermissions(SPBasePermissions.ViewListItems)) {     // Process the list item   } }

To examine the ISecurableObject interface, we will examine code from the Litware OPML generator. The Litware OPML generator builds a list of feeds for the site collection by recursively walking the sites and lists. OPML is an XML format used for lists of XML feeds and is most often used for lists of RSS feeds. OPML feeds can be used with RSS aggregator software, such as NewsGator Enterprise Server or FeedDemon, to subscribe to a list of feeds. Alternatively, it can be used to build AJAX interfaces with XSLT and JavaScript as demonstrated in Chapter 5, “AJAX Web Parts.” To build OPML for the current site scope, we will enumerate the current site and child sites while checking for permissions and writing nodes for items to which the user has read access. The full source code for the OPML generator is included in Chapter 5.

Within the code, we also want to track whether the current user is anonymous or authenticated. For anonymous users, we want to display only items that are available to the anonymous user. To check whether the anonymous user can access either the site or the list, use the AnonymousPermMask64 property. This permission mask contains the permissions available to the anonymous user. The following code enumerates child sites and calls the WriteSiteFeeds method when the user has permissions to view list items. First, we will check anonymous permissions if the user is anonymous. Secondly, if the user is authenticated, we will check the user’s permissions against the ISecurableObject interface.

 foreach (SPWeb childSite in site.Webs) {   if (HttpContext.Current.User.Identity.IsAuthenticated == false) {     if ((childSite.AnonymousPermMask64 & SPBasePermissions.ViewListItems)           == SPBasePermissions.ViewListItems) {       this.WriteWebFeeds(childSite, xw);     }  } else  if  childSite.DoesUserHavePermissions(         SPBasePermissions.ViewListItems))     this.WriteWebFeeds(childSite, xw);   } }

The same code can be used against the SPList list object, as the following code demonstrates.

 foreach (SPList list in site.Lists) {   if (HttpContext.Current.User.Identity.IsAuthenticated == false) {     if ((list.AnonymousPermMask64 & SPBasePermissions.ViewListItems) ==         SPBasePermissions.ViewListItems)       WriteListReference(xw, list);   } else {     if (list.DoesUserHavePermissions(SPBasePermissions.ViewListItems))       WriteListReference(xw, list);   } }

Because we are using the DoesUserHavePermissions method, the code does not throw a security exception if the user does not have read permissions. Within the WriteListReference method, we could perform an additional security check to ensure that the user has permissions using the CheckPermissions method of ISecurableInterface, as in the following example. If this check fails, a SecurityException is thrown.

 list.CheckPermissions(SPBasePermissions.ViewListItems);

Rights and Permission Levels

Rights within WSS are defined by permissions within the SPBasePermissions enumeration. This enumeration is a flags-based enumeration in which multiple permissions can be combined to create a permission set. SPBasePermissions are aggregated into more granular roles with the SPRoleDefinitions within the site context, in which permissions are role based. You will most likely assign a role when assigning permissions to a security principal; when validating rights for an action on a particular object, you will check the permission itself. To assign roles to a security principal, use the SPRoleDefinition class. By default, each site creates the following role definitions, exposing them through the Web’s RoleDefinition property: Full Control, Design, Contribute, Read, and Limited Access. These roles, along with their aggregated permissions, are listed in Table 10-2.

Table 10-2: Default WSS Site Roles
Open table as spreadsheet

Site Role

SPBasePermissions

Full Control

FullMask

Design

ViewListItems, AddListItems, EditListItems, DeleteListItems, ApproveItems, OpenItems, ViewVersions, DeleteVersions, CancelCheckout, ManagePersonalViews, ManageLists, ViewFormPages, Open, ViewPages, AddAndCustomizePages, ApplyThemeAndBorder, ApplyStyleSheets, CreateSSCSite, BrowseDirectories, BrowseUserInfo, AddDelPrivateWebParts, UpdatePersonalWebParts, UseClientIntegration, UseRemoteAPIs, CreateAlerts, EditMyUserInfo

Contribute

ViewListItems, AddListItems, EditListItems, DeleteListItems, OpenItems, ViewVersions, DeleteVersions, ManagePersonalViews, ViewFormPages, Open, ViewPages, CreateSSCSite, BrowseDirectories, BrowseUserInfo, AddDelPrivateWebParts, UpdatePersonalWebParts, UseClientIntegration, UseRemoteAPIs, CreateAlerts, EditMyUserInfo

Read

ViewListItems, OpenItems, ViewVersions, ViewFormPages, Open, ViewPages, CreateSSCSite, BrowseUserInfo, UseClientIntegration, UseRemoteAPIs, CreateAlerts

Limited Access

ViewFormPages, Open, BrowseUserInfo, UseClientIntegration, UseRemoteAPIs

Permissions are stored in the ACL for each ISecurableObject. These permissions are cached in the binary ReusableAcl property and define permissions for all users in the site collection on each object. These permissions are always accessed from the object (you will remember that object references always are accessed through the user and always contain permission information). The following code checks for permissions on the list object and, based on the AddListItems permission, decides whether to let the user add items.

 if (list.DoesUserHavePermissions(SPBasePermissions.AddListItems)){     // Let the user add an item }

The full SPBasePermission is included in Listing 10-6 for your quick reference. You will see that there are both basic and advanced permissions that you can grant, not all of which are available as options in the user interface.

Listing 10-6: The SPBasePermission enumeration

image from book
  SPBasePermission Enumeration [Flags] public enum SPBasePermissions { // Has no permissions on the Web site. EmptyMask = 0, // View items in lists and documents in document libraries. ViewListItems = 1, // Add items to lists, add documents to document libraries. AddListItems = 2, // Edit items in lists, edit documents in document libraries. EditListItems = 4, // Delete items from a list or documents from a document library. DeleteListItems = 8, // Approve a minor version of a list item or document. ApproveItems = 16, // View the source of documents with server-side file handlers. OpenItems = 32, // View past versions of a list item or document. ViewVersions = 64, // Delete past versions of a list item or document. DeleteVersions = 128, // Discard or check in a document which is checked out to another user. CancelCheckout = 256, // Create, change, and delete personal views of lists. ManagePersonalViews = 512, // Create and delete lists, add or remove columns or public views in a list. ManageLists = 2048, // View forms, views, and application pages. Enumerate lists. ViewFormPages = 4096, // Allows users to open a Web site, list, or folder. Open = 65536, // View pages in a Web site. ViewPages = 131072, // Add, change, or delete HTML pages or Web Part Pages. AddAndCustomizePages = 262144, // Apply a theme or borders to the entire Web site. ApplyThemeAndBorder = 524288, // Apply a style sheet (.CSS file) to the Web site. ApplyStyleSheets = 1048576, // View reports on Web site usage. ViewUsageData = 2097152, // Create a Web site using Self-Service Site Creation. CreateSSCSite = 4194304, // Create subsites such as team sites. ManageSubwebs = 8388608, // Create a group of users that can be used anywhere within the site collection. CreateGroups = 16777216, // Create and change permission levels on the Web site and users and groups. ManagePermissions = 33554432, // Enumerate files and folders in a Web site using Microsoft SharePoint Designer // and Web DAV interfaces. BrowseDirectories = 67108864, // View information about users of the Web site. BrowseUserInfo = 134217728, // Add or remove personal Web Parts on a Web Part Page. AddDelPrivateWebParts = 268435456, // Update Web Parts to display personalized information. UpdatePersonalWebParts = 536870912, // Grants the ability to perform all administration tasks for the Web site as // well as manage content. ManageWeb = 1073741824, UseClientIntegration = 68719476736, // Use SOAP, Web DAV, or Microsoft SharePoint Designer interfaces. UseRemoteAPIs = 137438953472, // Manage alerts for all users of the Web site. ManageAlerts = 274877906944, // Create e-mail alerts. CreateAlerts = 549755813888, // Allows a user to change his or her own user information, such as adding a picture. EditMyUserInfo = 1099511627776, // Enumerate permissions on the Web site, list, folder, document, or list item. EnumeratePermissions = 4611686018427387904, // Has all permissions on the Web site. FullMask = 9223372036854775807, } 
image from book

Handling Authorization Failures with SPUtility

You will generally secure objects, including sites and lists, by using the ISecurableObject interface. If you need a simple check for permissions, you could also check properties of the current user, such as IsSiteAdmin, to ensure that the user is the site administrator. By default, the CheckPermissions method of the ISecurableObject throws a security exception and sends an access denied message to the user; however, you may wish to handle authorization failures yourself. The SPUtility class has several methods that are useful for handling authorization failures, including the SPUtility.Redirect method. The SPUtility.Redirect method can be used to send users to the access denied page by using the following syntax:

 SPUtility.Redirect(SPUtility.AccessDeniedPage,    SPRedirectFlags.RelativeToLayoutsPage,    Context);

SPUtility also has a method that handles access denied exceptions and redirects the user to the access denied page. The SPUtility.HandleAccessDenied method takes an exception as a parameter and is used to handle SecurityExceptions.

 try {     // authorization code } catch (SecurityException securityException) {    SPUtility.HandleAccessDenied(securityException); }

To check whether the user is a site administrator, you can use the EnsureSiteAdminAccess method of the SPUtility. If the user is not a site admin, WSS prompts for a site admin credential. If the site admin credential is not supplied, the user is transferred to the access denied page. Alternatively, you can also check the current user’s IsSiteAdmin property and redirect elsewhere.

Finally, SPUtility has a simple method to send an HTTP 401 (Access Denied) header to the user. To send a 401 to the user, enabling the user to either supply new credentials or end up at the access denied page, use the SendAccessDeniedHeader method, as in the following code.

 try {    // authorization code } catch (SecurityException securityException) {    SPUtility.SendAccessDeniedHeader(securityException); }




Inside Microsoft Windows Sharepoint Services Version 3
Inside Microsoft Windows Sharepoint Services Version 3
ISBN: 735623201
EAN: N/A
Year: 2007
Pages: 92

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net