Walkthrough: Using a Custom Security Trimmer for SharePoint Server Search Results
Applies to: SharePoint Server 2010
In this article
Prerequisites
Step 1: Create the Custom Security Trimmer
Step 2: Register the Custom Security Trimmer
Step 3 (Optional): Specify a Configurable Limit on the Number of Crawl URLs That Are Checked
Microsoft SharePoint Server 2010 search performs query-time security trimming of search results. However, there may be scenarios in which you want to perform custom security trimming. SharePoint Server search provides support for these scenarios through the ISecurityTrimmer2 interface in the Microsoft.Office.Server.Search.Query namespace.
By implementing this interface, you can create a component to perform custom security trimming of search results before they are returned to the user. The security trimmer registration process enables you to specify configuration properties for the custom security trimmer.
This walkthrough guides you through the steps to implement—create, deploy, and register—a basic custom security trimmer for SharePoint Server search by using Microsoft Visual Studio 2010. It also includes an optional step that shows you how to implement a configurable limit on the number of content items that are checked by the trimmer.
Prerequisites
Step 1: Create the Custom Security Trimmer
Step 2: Register the Custom Security Trimmer
Step 3 (Optional): Specify a Configurable Limit on the Number of Crawl URLs That Are Checked
Prerequisites
To complete this walkthrough, you must have the following installed in your development environment:
Microsoft SharePoint Server 2010
Microsoft Visual Studio 2010 or a similar Microsoft .NET Framework-compatible development tool
Step 1: Create the Custom Security Trimmer
Creating the custom security trimmer includes the following tasks:
Setting Up the Custom Security Trimmer Project
Writing the Custom Security Trimmer Code
Deploying the Custom Security Trimmer Project
Example
Setting Up the Custom Security Trimmer Project
In this step, you'll create the custom security trimmer project, and then add the required references and the custom security trimmer class file to the project.
To create the project for the custom security trimmer
In Visual Studio, on the File menu, point to New, and then click Project.
In Project types, under C#, select SharePoint.
Under Templates, select Empty SharePoint Project. In the Name field, type CustomSecurityTrimmerSample, and then click OK.
In the SharePoint Customization Wizard, choose Deploy as a farm solution, and then click Finish.
To add references to the custom security trimmer project
On the Project menu, click Add Reference.
On the .NET tab, select the references with the following component names, and then click OK:
Microsoft Search component
You should see two entries on the .NET tab with the component name Microsoft Search component. Select the entry where the Path column is \ISAPI\Microsoft.Office.Server.Search.dll. If this entry is missing from the .NET tab of the Add References dialog box, you must add the reference from the Browse tab by using the path to the Microsoft.Office.Server.Search.dll.
Microsoft.IdentityModel
If Microsoft.IdentityModel is not listed on the .NET tab, you must add the reference to the Microsoft.IdentityModel.dll from the Browse tab, by using the path:
%ProgramFiles%\Reference Assemblies\Microsoft\Windows Identity Foundation\v3.5.
To create the class file for the security trimmer
On the Project menu, click Add New Item.
Under Visual C# Items in Installed Templates, click Code, and then click Class..
Type CustomSecurityTrimmer.cs, and then click Add
Writing the Custom Security Trimmer Code
Your custom security trimmer must implement the ISecurityTrimmer2 interface. The code example in this section is a basic implementation of this interface.
To modify the default code in CustomSecurityTrimmer
Add the following using directives at the beginning of the class:
using System; using System.Collections.Generic; using Microsoft.Office.Server.Search.Query; using Microsoft.Office.Server.Search.Administration; using System.Collections; using System.Collections.Specialized; using System.Security.Principal;
Specify that the CustomSecurityTrimmer class implements the ISecurityTrimmer2 interface in the class declaration, as follows.
public class CustomSecurityTrimmer : ISecurityTrimmer2
You are now ready to write the code to implement the ISecurityTrimmer2 interface methods.
To implement the ISecurityTrimmer2 interface methods
Add the following code for the Initialize() method declaration.
public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication) { }
The basic version of this sample does not include any code in the Initialize method. The Initialize method in the Step 3 (Optional): Specify a Configurable Limit on the Number of Crawl URLs That Are Checked contains an example implementation.
For more information about implementing the Initialize method, see Writing a Custom Security Trimmer for SharePoint Server Search.
Add the following code for the CheckAccess() method declaration.
public BitArray CheckAccess(IList<String> documentCrawlUrls, IDictionary<String, Object> sessionProperties, IIdentity passedUserIdentity) { //CheckAccess method implementation, see steps 3-5. }
For the first part of the CheckAccess method implementation, declare and initialize a BitArray variable to store the results of the access check for each URL in the crawlURLs collection, and retrieve the user who submitted the query, as follows.
BitArray retArray = new BitArray(documentCrawlUrls.Count); //Use passedUserIdentity to get the identity of the user who issued the query. //IClaimsIdentity claimsIdentity = (IClaimsIdentity)passedUserIdentity; //IClaimsIdentity is defined in Microsoft.IdentityModel.Claims;
Loop through each crawl URL in the collection, and perform the access check to determine if the user who submitted the query can access the crawl URL's associated content item.
If the user has access to the content item, set the value of the BitArray item at that index, retArray[x], to true; otherwise, set it to false, as follows.
for (int x = 0; x < documentCrawlUrls.Count; x++) { /* To fully implement the security trimmer, add code to perform the security check and determine if the user can access documentCrawlUrls[x]. If the user can access documentCrawlUrls[x], then: */ retArray[x] = true; //If not: retArray[x] = false; }
Set the return value of the CheckAccess method to retArray, as follows.
return retArray;
Deploying the Custom Security Trimmer Project
The deployment process does the following:
Builds the CustomSecurityTrimmerSample.dll and deploys it to the global assembly cache
Recycles Internet Information Services (IIS)
To deploy the custom security trimmer project
On the Build menu, click Deploy Solution.
If you make changes to the project, select Deploy Solution again to automatically retract the previous version of the solution and replace it with the newest version.
Example
Following is the complete sample code for the CustomSecurityTrimmerSample class, described in this step.
using System;
using System.Collections.Generic;
using Microsoft.IdentityModel;
using Microsoft.IdentityModel.Claims;
using Microsoft.Office.Server.Search.Query;
using Microsoft.Office.Server.Search.Administration;
using System.Collections;
using System.Collections.Specialized;
using System.Security.Principal;
namespace CustomSecurityTrimmerSample
{
class CustomSecurityTrimmer : ISecurityTrimmer2
{
public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication)
{
}
public BitArray CheckAccess(IList<String> documentCrawlUrls, IDictionary<String, Object> sessionProperties, IIdentity passedUserIdentity)
{
BitArray retArray = new BitArray(documentCrawlUrls.Count);
//Use passedUserIdentity to get the identity of the user who issued the query.
//IClaimsIdentity claimsIdentity = (IClaimsIdentity)passedUserIdentity;
//IClaimsIdentity is defined in Microsoft.IdentityModel.Claims;
for (int x = 0; x < documentCrawlUrls.Count; x++)
{
/*
To fully implement the security trimmer,
add code to perform the security check
and determine if userIdentity can access documentCrawlUrls[x].
If userIdentity can access documentCrawlUrls[x], then:
*/
retArray[x] = true;
//If not:
retArray[x] = false;
}
return retArray;
}
}
}
Step 2: Register the Custom Security Trimmer
Step 2 describes how to configure the custom security trimmer, and includes the following tasks:
Creating the crawl rule for the custom security trimmer
Registering the custom security trimmer for the Search service application and re-crawling the content source
Creating a Crawl Rule for the Custom Security Trimmer
Before you register the custom security trimmer, you must create the crawl rule for the content that the custom security trimmer applies to.
To create the crawl rule
Open SharePoint 2010 Central Administration, and then navigate to the Application Management page.
In the Service Applications section of the Application Management page, click Manage service applications.
Click Search Service Application.
To open the Manage Crawl Rules page, click Crawl rules in the Crawling section.
Click New Crawl Rule, and then for Path, type file://FileServer1/*, replacing FileServer1 with the path to the content to crawl.
For Crawl Configuration, select Include all items in this path, and then click OK to create the crawl rule.
Registering the Custom Security Trimmer and Re-crawl the Content Source
You use the SharePoint 2010 Management Shell to register a custom security trimmer. The following procedure shows how to register a custom security trimmer, with the ID set to 1 for the Search service application, applied to content located on file shares for a server named FileServer1.
To register the custom security trimmer
In Windows Explorer, locate CustomSecurityTrimmerSample.dll in the path <Local_Drive>:\WINDOWS\assembly.
Right-click the file, and then click Properties.
On the General tab in the Properties dialog box, select the token and copy it.
Open the SharePoint 2010 Management Shell. For information about using this tool, see Administering Service Applications Using the SharePoint 2010 Management Shell.
At the command prompt, type the following command.
New-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application" -typeName "CustomSecurityTrimmerSample.CustomSecurityTrimmer, CustomSecurityTrimmerSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=token" -RulePath file://FileServer1/* -id 1
In the command, replace token with the Public Key Token for the CustomSecurityTrimmerSample.dll file, and replace FileServer1 with file share server name.
Important
If you have multiple Web front-end (WFE) servers, you must deploy your security trimmer to the global assembly cache on all the WFE servers in the farm.
Initiate a full crawl of the content source, as described in the following procedure.
To initiate a full crawl of the content source
Open SharePoint 2010 Central Administration, and then navigate to the Application Management page.
In the Service Applications section of the Application Management page, click Manage service applications.
Click Search Service Application.
To open the Manage Content Sources page, click Content Sources in the Crawling section.
For the content source that represents the content affected by the crawl rule for the security trimmer, click the arrow next to the Edit menu. From the menu, select Start Full Crawl. If the content source is not listed on the Manage Content Sources page, you must create it.
To create the content source
Click New Content Source, and then for Name, type the content source name.
For Content Source Type, click File Shares.
For Start Addresses, type file://FileServer1/*.
Check Start full crawl of this content source, and then click OK to add the content source.
Step 3 (Optional): Specify a Configurable Limit on the Number of Crawl URLs That Are Checked
When you register a custom security trimmer by using the SharePoint Management Shell, you can specify optional configuration properties with the New-SPEnterpriseSearchSecurityTrimmer cmdlet. This cmdlet supports creating a custom security trimmer with configurable settings.
For example, you could create a custom security trimmer with a configurable limit on the number of items checked by the security trimmer. Although this is optional, we recommend that you include some type of limit in your custom security trimmer implementation. For more information, see Writing a Custom Security Trimmer for SharePoint Server Search.
Step 3 describes how to create and register a custom security trimmer with a configurable limit on the number of documents checked, and includes the following tasks:
Coding the Custom Security Trimmer
Registering the Custom Security Trimmer
Example
The custom security trimmer described in this sample is similar to the one described in Step 1: Create the Custom Security Trimmer and Step 2: Register the Custom Security Trimmer. In this custom security trimmer, however, we include additional steps to set a limit in the implementation, and change the command you use to register the custom security trimmer.
Coding the Custom Security Trimmer
Before starting the task described here, create the custom security trimmer project and modify the CustomSecurityTrimmer class, as described in Step 1: Create the Custom Security Trimmer.
To code the custom security trimmer
After you modify the class declaration to implement the ISecurityTrimmer2 interface, declare a variable for the limit value, as follows.
class CustomSecurityTrimmer : ISecurityTrimmer2 { /* Sets a default limit of 200. You can change this to a value that meets your specific requirements. */ private int intCheckLimit = 200;
Create a method to compare the number of items checked to the configured limit, add the following code.
private bool CheckLimit(IDictionary<String, Object> sessionProperties, int numChecks) { Object currentCount; sessionProperties.TryGetValue("currentCheckCount", out currentCount); if (currentCount == null) { sessionProperties["currentCheckCount"] = numChecks; return (true); } int currentCountInt = Convert.ToInt32(currentCount); currentCountInt += numChecks; sessionProperties["currentCheckCount"] = currentCountInt; if (currentCountInt <= intCheckLimit) { return true; } else { return false; } }
To complete the code for the custom security trimmer sample, you must modify the Initialize() and CheckAccess() method implementations described in Step 1: Create the Custom Security Trimmer.
To modify ISecurityTrimmer2 interface method implementations
Add the following code to the Initialize() method.
if (staticProperties["CheckLimitProperty"] != null) { intCheckLimit = Convert.ToInt32(staticProperties["CheckLimitProperty"]); }
This code sets the limit for the maximum number of documents that the security trimmer will check to the value of a configuration property named CheckLimitProperty.
Note
You can specify configuration properties when you register the security trimmer.
Add the following code to the CheckAccess() method, immediately after the method declaration.
if (!this.CheckLimit(sessionProperties, documentCrawlUrls.Count)) { throw (new PluggableAccessCheckException("<Display Message>")); }
This code calls the CheckLimit method. If the limit has been reached, this method returns false. When this occurs, a PluggableAccessCheckException exception is thrown, however the user will not see the message specified in the constructor. After the exception is thrown by the security trimmer, the trimmerID that caused the exception will be filtered out and that result will be excluded from the search results. Other security trimmed results, if available, will be returned and displayed in the search results user interface.
Note
This section does not repeat steps already specified in Step 1 and 2; it only describes the tasks that are different. For information from the previous steps, see Step 1: Create the Custom Security Trimmer and Step 2: Register the Custom Security Trimmer.
Registering the Custom Security Trimmer
Before you start this step, you must deploy CustomSecurityTrimmerSample.dll to the global assembly cache, as described in Step 2: Register the Custom Security Trimmer. Then, you can register the custom security trimmer by using the SharePoint 2010 Management Shell.
The following procedure shows how to register a custom security trimmer with the ID set to 1 for the Search service application, which is applied to content located on file shares for a server named FileServer1. It also sets the value of the CheckLimitProperty configuration setting to 300.
To register the custom security trimmer with the CheckLimitProperty configuration setting
Open the SharePoint 2010 Management Shell. For information about using this tool, see Administering Service Applications Using the SharePoint 2010 Management Shell.
At the command prompt, type the following command.
New-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application" -typeName "CustomSecurityTrimmerSample.CustomSecurityTrimmer, CustomSecurityTrimmerSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=token" -RulePath file:// FileServer1/* -id 1 -properties CheckLimitProperty~300
In the command, replace token with the Public Key Token for the CustomSecurityTrimmerSample.dll file, and replace FileServer1 with file share server name.
Example
Following is the complete sample code for the CustomSecurityTrimmerSample class described in this step.
using System;
using System.Collections.Generic;
using Microsoft.Office.Server.Search.Query;
using Microsoft.Office.Server.Search.Administration;
using System.Collections;
using System.Collections.Specialized;
using System.Security.Principal;
namespace CustomSecurityTrimmerSample
{
class CustomSecurityTrimmer : ISecurityTrimmer2
{
/*
Sets a default limit of 200. You can change this
to a value that meets your specific requirements.
*/
private int intCheckLimit = 200;
public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication)
{
if (staticProperties["CheckLimitProperty"] != null)
{
intCheckLimit = Convert.ToInt32(staticProperties["CheckLimitProperty"]);
}
}
public BitArray CheckAccess(IList<String> documentCrawlUrls, IDictionary<String, Object> sessionProperties, IIdentity passedUserIdentity)
{
if (!this.CheckLimit(sessionProperties, documentCrawlUrls.Count))
{
throw (new PluggableAccessCheckException("<Display Message>"));
}
BitArray retArray = new BitArray(documentCrawlUrls.Count);
IIdentity userIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
for (int x = 0; x < documentCrawlUrls.Count; x++)
{
/*
To fully implement the security trimmer,
add code to perform the security check
and determine if userIdentity can access documentCrawlUrls[x].
If userIdentity can access documentCrawlUrls[x], then:
*/
retArray[x] = true;
//If not:
retArray[x] = false;
}
return retArray;
}
private bool CheckLimit(IDictionary<String, Object> sessionProperties, int numChecks)
{
Object currentCount;
sessionProperties.TryGetValue("currentCheckCount", out currentCount);
if (currentCount == null)
{
sessionProperties["currentCheckCount"] = numChecks;
return (true);
}
int currentCountInt = Convert.ToInt32(currentCount);
currentCountInt += numChecks;
sessionProperties["currentCheckCount"] = currentCountInt;
if (currentCountInt <= intCheckLimit)
{
return true;
}
else
{
return false;
}
}
}
}
See Also
Reference
Microsoft.Office.Server.Search.Query.ISecurityTrimmer2
Microsoft.Office.Server.Search.Query.PluggableAccessCheckException
Concepts
Writing a Custom Security Trimmer for SharePoint Server Search