How to implement Security on SharePoint 2010 Search Content Sources?
-
Friday, March 12, 2010 1:47 AMI want to index some external applications. For testing purposes, I have created a simple SQL Server Database and created an External Content Type with it through SharePoint Designer 2010. I then added a Content Source in the Search Administration and crawled it.Works perfectly, except that everyone can search it.Can you give me some pointers on how I would implement security? What if I only want certain people to see it? And what if the external application has it's own user database which makes a 1:1 mapping or NTLM/Kerberos not possible?Ignore the fact that it's a SQL Server database - that is just my current test system. I can keep it in a SQL (2008) DB if it helps, but I can also implement a WebService.
All Replies
-
Friday, March 12, 2010 8:22 PM
If you hav NT ACLs avialable for every URL of your external application ( That would be for every row of the table your are indexing) you can use the WindowsSecurityDescriptorField property to secure your external content in search results as shown in the sample below. You can do the same with Webservices too. Just add a field to your Finder and SpecificFinder methods that returns the windows NT security descriptor.
<Method IsStatic="false" Name="Item SpecificFinder"> <Properties> <Property Name="RdbCommandType" Type="System.Data.CommandType, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">Text</Property> <Property Name="RdbCommandText" Type="System.String">SELECT [Identifier] , [Name] , [SecurityDescriptor] FROM [Test].[dbo].[Items] WHERE [Identifier] = @Identifier</Property> <Property Name="BackEndObjectType" Type="System.String">SqlServerTable</Property> <Property Name="BackEndObject" Type="System.String">BaseItems</Property> <Property Name="Schema" Type="System.String">dbo</Property> </Properties> <Parameters> <Parameter Direction="In" Name="@Identifier"> <TypeDescriptor TypeName="System.Int32" IdentifierName="Identifier" Name="Identifier" /> </Parameter> <Parameter Direction="Return" Name="BaseItemsRead Item"> <TypeDescriptor TypeName="System.Data.IDataReader, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" IsCollection="true" Name="BaseItemsRead Item"> <TypeDescriptors> <TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Name="BaseItemsRead ItemElement"> <TypeDescriptors> <TypeDescriptor TypeName="System.Int32" IdentifierName="Identifier" Name="Identifier"> <Properties> <Property Name="RequiredInForms" Type="System.Boolean">true</Property> </Properties> </TypeDescriptor> <TypeDescriptor TypeName="System.String" Name="Name"> <Properties> <Property Name="Size" Type="System.Int32">4000</Property> </Properties> </TypeDescriptor> <TypeDescriptor TypeName="System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" IsCollection="true" Name="SecurityDescriptor"> <TypeDescriptors> <TypeDescriptor TypeName="System.Byte" Name="SecurityDescriptorElement" /> </TypeDescriptors> </TypeDescriptor> </TypeDescriptors> </TypeDescriptor> </TypeDescriptors> </TypeDescriptor> </Parameter> </Parameters> <MethodInstances> <MethodInstance Type="SpecificFinder" ReturnParameterName="BaseItemsRead Item" ReturnTypeDescriptorName="BaseItemsRead ItemElement" ReturnTypeDescriptorLevel="1" Default="true" Name="BaseItemsRead Item" DefaultDisplayName="Read Item New Business Data Entity"> <Properties> <Property Name="WindowsSecurityDescriptorField" Type="System.String">SecurityDescriptor</Property> </Properties> </MethodInstance> </MethodInstances> </Method>If you cannot map the external users 1:1 to NT users, you need to implement a AccessCheck method that can be called at query time for custom security trimming. Sharepoint 2010 ships with a Business Data Custom security trimmer that will call this CheckAccess method during query time. You can register the trimmer for a URL pattern using PowerShell cmdlets as shown below:- $searchapp = Get-SPEnterpriseSearchServiceApplication
- new-spenterprisesearchsecuritytrimmer -SearchApplication $searchapp -TypeName "Microsoft.Office.Server.Search.Connector.BDC.SPBDC.SPBdcSecurityTrimmer, Microsoft.Office.Server.Search.Connector, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" -RulePath bdc3://* -Id 1
Apart from the registration of the trimmer, the process has not changed in 2010. You can look at the 2007 walkthrough here for details:
http://msdn.microsoft.com/en-us/library/bb447548.aspx- Marked As Answer by Michael Stum Tuesday, March 23, 2010 12:35 AM
-
Tuesday, March 23, 2010 12:42 AM
Do you know if I have to use the PowerShell/Crawl Rule approach? Can I somehow use an AccessChecker method to have everything in one BCS Model?
Or could I somehow build my own SecurityDescriptor? I could ask our IT Team to create ActiveDirectory Groups and put users in it. Then I somehow would need to generate a SecurityDescriptor that basically says "This group has read access".
-
Tuesday, March 30, 2010 7:36 PM
You can build your own security descriptor using the sample code below. If you are crawling databases, you would have to create a new view with a column that contains this security descriptor.
Byte[] GetSecurityDescriptor(string domain, string username)
{
NTAccount acc = new NTAccount(domain, username);
SecurityIdentifier sid = (SecurityIdentifier)acc.Translate(typeof(SecurityIdentifier));
CommonSecurityDescriptor sd = new CommonSecurityDescriptor(false, false, ControlFlags.None,
sid,
null, null, null);
sd.SetDiscretionaryAclProtection(
true, false);
//Deny access to everyone
SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
sd.DiscretionaryAcl.RemoveAccess(
AccessControlType.Allow, everyone, unchecked((int)0xffffffffL), InheritanceFlags.None, PropagationFlags.None);
//Grant full access to specified user
sd.DiscretionaryAcl.AddAccess(
AccessControlType.Allow, sid, unchecked((int)0xffffffffL), InheritanceFlags.None, PropagationFlags.None);
byte[] secDes = new Byte[sd.BinaryLength];
sd.GetBinaryForm(secDes, 0);
return secDes;
}
-
Thursday, May 20, 2010 6:16 PM
Thank you so much! This helped me a lot!
-Matthias
-
Saturday, May 29, 2010 1:40 AMIs it possible to implement 1:N security mapping (i.e. mapping multiple security groups to one list item) using the SQL way?
-
Thursday, May 26, 2011 12:37 PM
On a recent project this approach to implementing crawl-time security worked great on the first attempt. Thank you!
-Jason -
Monday, July 04, 2011 9:35 AM
@Nitin Ved
While your Code works for a single user (i.e., Byte[] GetSecurityDescriptor(string domain, string username)) , it does not work for a Group. That is if username is replaced by groupname in the above code, we get an error . Can someone please help me with this. Is this possible for groups?
Thanks & Regards
Prashanth
-
Wednesday, November 09, 2011 10:07 PM
Nitin,
Thank you for these helpful posts.
What would I have to do (in code) to add a security group descriptor, rather than a security descriptor for a specific user? My security trimming is based upon membership of a particular group or groups in AD.
Thanks,
Step
-
Monday, April 29, 2013 4:39 AM
I have SQL table having 3 columns namely DiscussionID,DiscussionSubject,DiscussionBody, I have created an ECT via Sharepoint Designer2010, I then added a Content Source in the Search Administration and crawled it. Works perfectly, except that everyone can search it.
Consider there are two rows in the table.How do i implement security trimming to these rows. Only the first row should appear in the search results when certain people(James and Anderson) search it. Similarly the second row should be searchable only to certain people(Arnold and Bruce) alone.
I read about the "WindowsSecurityDescriptorField" property , but my doubt is when i use this property in my BDC model , how does sharepoint generates the Security descriptor for each row and how does it identifies which row belongs to which user. How is this mapping done?
Thanks in advance!!

