Use permissions for search
You can configure Sitecore content search to retrieve and show only items that the user executing the search has permission to read (permission-enabled search). The feature is available when you search through a Sitecore client and use the search API to build search queries in code.
By default, the feature is only enabled for Sitecore clients (in the Sitecore UI), and only for the sitecore_master_index
index, but you can change this in the configuration.
Configure permission-enabled search
The content search configuration has a computed field called _readaccess
. For example, for the Solr search provider, this field is in the contentSearch/indexConfigurations/defaultSolrIndexConfiguration/documentOptions
node in the Sitecore/ContentSearch/ Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config
file.
The EnableReadAccessIndexing
setting in the index configuration specifies two things:
-
Whether Sitecore stores the
item:read
access rights in thesecurity
field in the index. -
Whether you can add additional clauses for the
_readaccess
field to the query.
If the value of the EnableReadAccessIndexing
setting is true
, both of these things are true. If the value is false
, both things are false, and permissions are not used for searching in this index.
The feature is only enabled for the sitecore_master_index
index by default.
To use permissions for searching the website:
-
Change the value of the
enableReadAccessIndexing
setting for thesitecore_web_index
totrue
.
The indexing strategies check changes to the security
field when you use permissions-enabled search.
Use permissions when you search from the API
Indexing strategies react to changes in the security
field in content items, not to changes in the security domain configuration. Therefore, when you change the security domain, you must rebuild indexes that use permission-enabled search.
We recommend completing the security configuration before you turn the permission-enabled search on. Adding new users to the system or assigning users to roles does not require index updates unless you assign access rights directly to users.
You can use several helper methods to build search queries that consider permissions. The helper methods are in the Sitecore.ContentSearch.Security.QueryableExtensions
class:
/// <summary>
/// Filters the specified source based on "item:read" access for user.
/// </summary>.
/// <typeparam name="T">The type of the source.</typeparam>
/// <param name="source">The source.</param>
/// <param name="user">The user.</param>
/// <returns>The results.</returns>
public static IQueryable<T> WhereUserCanRead<T>(this IQueryable<T> source, User user) where T : IreadAccessSearchResult
/// <summary>
/// Filters the specified source based on "item:read" access for role.
/// </summary>.
/// <typeparam name="T">The type of the source.</typeparam>
/// <param name="source">The source.</param>
/// <param name="role">The role.</param>
/// <returns>The results.</returns>
public static IQueryable<T> WhereRoleCanRead<T>(this IQueryable<T> source, Role role) where T : IReadAccessSearchResult
To use the helper methods to build queries that consider permissions:
-
Implementing the
IReadAccessSearchResult
interface.
The scenario for using the helper methods is using a single method call. You cannot override the method parameter.
If you chain method calls (for example: query.WhereUserCanRead(userA).WhereUserCanRead(userB)
), Sitecore filters the search results for both users.
The IReadAccessSearchResult interface
You use the IReadAccessSearchResult
interface to specify that search query results must be filtered based on the value of the _readaccess
field. It has a single property called ReadAccess
. This property matches the _readaccess
index field:
/// <summary>
/// Interface for the search result that support <see cref="BuiltinFields.ReadAccess"/> index field.
/// </summary>
public interface IReadAccessSearchResult
{
/// <summary>
/// Gets or sets <see cref="BuiltinFields.ReadAccess"/> field.
/// </summary>
[IndexField(BuiltinFields.ReadAccess)]
IEnumerable<string> ReadAccess { get; }
}
If you use a custom search result type and need the helper methods, you must implement the IReadAccessSearchResult
interface in the custom type.
The built-in search result types, for example, SearchResultItem
and UISearchResultItem
, implement these interfaces and support using the Sitecore.ContentSearch.Security.QueryableExtensions
class.
The SearchSecurityOptions property
When you use the API to build a search query, you use the SearchSecurityOptions
property:
public enum SearchSecurityOptions
{
/// <summary>The default security options.</summary>
Default = 0,
/// <summary>
/// Disables all security checks.
/// </summary>
DisableSecurityCheck = 1 << 0,
/// <summary>
/// Runs a security check on all items.
/// </summary>
EnableSecurityCheck = 1 << 1,
}
When you set the value of the SearchSecurityOptions
property to EnableSecurityCheck
, Sitecore automatically applies the .WhereUserCanRead(Context.User)
extension method to the query built by the client application or the API. This means that the following two code samples do the same:
var index = ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = index.CreateSearchContext(SearchSecurityOptions.EnableSecurityCheck))
{
var query = context.GetQueryable<SearchResultItem>();
}
and
var index = ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = index.CreateSearchContext())
{
var user = Context.User;
var query = context.GetQueryable<SearchResultItem>().WhereUserCanRead(user);
}
Override search limitations
Permission-enabled search has some limitations for users with multiple roles.
Given a user with two roles, for example, Role1 and Role2, if an item is configured to deny read permissions for Role1 and one of its descendants allows reading for Role2, the descendants of the second item will not be returned in query results. This behavior respects the restrictions set on the first ancestor item.
The following content tree outline illustrates the limiting access rights configuration:
sitecore
- content
-- Home {item:read access denied for descendants} for Role1
--- Level1
---- Level2
----- Level3 {item:read access allowed for descendants} for Role2
------ Item1
------ Item2
------ Item3
To return results listed under the Level3 item, you must override the restrictions set on ancestor items by configuring access rights for the role of interest on each descendant you want to retrieve in your search queries.
To override ancestor restrictions:
-
Download and install the SC Hotfix 591876-1.zip package.
-
Add the following setting to your Sitecore configuration:
RequestResponsexml<!-- CONTENT SEARCH - INDEXING READACCESS WITH PRIORITY TO ENABLE FIX FOR 493002 This setting specifies whether or not to indexing readaccess permission with proprity and search with prioriry. When enabled it will have extra priority to the readaccess permission when indexing e.g. User > Entity > Descendents. Default value: false--> <setting name="ContentSearch.Enable-493002" value="false"/>
-
Rebuild indexes.
-
For the intended role (Role2 in this example), explicitly set access rights on the descendent items you want to be returned by enabling
item:read
access on each item:RequestResponseshellsitecore - content -- Home {item:read access denied for descendants} for Role1 --- Level1 ---- Level2 ----- Level3 {item:read access allowed for descendants} for Role2 ------ Item1 {item:read access allowed for the item} for Role2 ------ Item2 {item:read access allowed for the item} for Role2 ------ Item3 {item:read access allowed for the item} for Role2