Try Now
More in this section
Blogs RSS feed

Trim the Search Results based on permissions / roles

by Vesselin Vasilev
Edit: The code was updated to work correctly when Paging is enabled.

This blog post will guide you through the steps on how to trim the search results based on permissions or roles. Let's start with the use case: 
I've got a page which is visible only to authenticated users:
Figure: This page is visible only to Authenticated users.

So, if you are not logged in in the front end you will not see the page in the navigation. Even if you manually type its URL in the address bar you will be first redirected to the login screen. So far so good.
Imagine now that an anonymous user performs a search that returns this particular page as a result. He would be able to see it in the search results and maybe even see some confidential information:

Figure: an Anonymous user performs a search which returns the page he's not supposed to see

Note: the unauthenticated user will not be able to open the page, but still be able to see its title, URL and some of the content.

The steps below will show you how to change the behaviour of the SearchResults widget so that it takes into account the permissions of the individual result items.

1. Create a class in your Visual Studio solution that inherit from the SearchResults class:

public class SearchResultsByPermissions : SearchResults

2. Override the InitializeControls method:

public class SearchResultsByPermissions : SearchResults
    protected override void InitializeControls(GenericContainer container)
        Label resultsStats = this.ResultsStats;
        //this is the original localized stats message. It shows all the results
        var resultsStatsMessage = resultsStats.Text;          
        if (string.IsNullOrEmpty(this.Query))
            this.ResultsStats.Text = string.Empty;
        int numberOfAllResults = 0;         
        SearchResults.ISearcher searcher = this.GetSearcher();
        //these are all the results (not filtered by permissions)
        var allResults = searcher.Search(this.Query, this.IndexCatalogue, 0, 0, out numberOfAllResults);
        if (allResults == null)
        //here we will store only the results we have permissions to see
        List<IDocument> securedResultSet = new List<IDocument>();
        foreach (var document in allResults)
            var type = document.GetValue("ContentType");
            var ID = new Guid(document.GetValue("OriginalItemId"));
            if (TypeResolutionService.ResolveType(type) == typeof(PageNode))
                var manager = PageManager.GetManager();
                //suppress the security checks so the code can be executed even if
                //the current user doesn't have enough permissions
                manager.Provider.SuppressSecurityChecks = true;
                var page = manager.GetPageNode(ID);
                if (page != null)
                    ISecuredObject securedObject = (ISecuredObject)page;
                    if (SecurityExtensions.IsSecurityActionTypeGranted(securedObject, SecurityActionTypes.View))
                manager.Provider.SuppressSecurityChecks = false;
        var numberOfSecuredSearchResults = securedResultSet.Count;
        char[] chrArray = new char[] { '\"' };
        string str = this.Query.Trim(chrArray);
        resultsStats.Text = string.Format(resultsStatsMessage, numberOfSecuredSearchResults, HttpUtility.HtmlEncode(str));
        this.ResultsList.DataSource = null;
        int itemsToSkip = this.GetItemsToSkip();
        int itemsToTake = this.GetItemsToTake();
        ResultsList.DataSource = securedResultSet.Skip(itemsToSkip).Take(itemsToTake);
    private int GetItemsToSkip()
        if (this.AllowPaging)
            int pageNumber = this.GetPageNumber(this.GetUrlEvaluationMode(), this.PageKey, 0, "PageNumber");
            if (pageNumber > 0)
                return (pageNumber - 1) * this.ItemsPerPage;
        return 0;
    private int GetItemsToTake()
        if (!this.AllowPaging)
            return 0;
        return this.ItemsPerPage;

Here is some explanation: we call the base InitializeControls method because it takes care of calling the search service and binding the results to the ResultsList repeater. The ResultsList repeater is part of the UI that shows the results. 
Remember, this results collection is not yet trimmed by permissions, so we need to alter it and include only the items that the current user is allowed to see.
To do that, we iterate through the collection and for each item we check its type. Based on the content type we invoke the appropriate manager and check if the View permission type is granted to the current user. If it is, then we add it to our securedResultSet collection.
At the end we bind the ResultsList repeater to the securedResultSet collection.
Note, you can use the same logic to perform checks on other content types like News, Documents, etc.

Finally, the message that shows the number of the returned results is updated, because the securedResultSet collection might contain less items than the original results collection. 

3. Build and Register the new widget using Thunder in the page's toolbox.

4. Drag the new widget to a page and start using it.

That's it. Now the anonymous users will not find the pages they are not supposed to see:

Figure: the search results do not include the page that is hidden for anonymous users

Thanks to Svetla Yankova for the best parts of the code.

Attached is the complete C# file: SearchResultsByPermissions


Leave a comment
  1. Jimmy May 02, 2013
    Hi Vesselin,

    I have tried the Search Result by Permission widget.  Its implementation includes searching in pages only.  It only works when the search index searches through Static Html. It doesn’t ever get into the condition when the documents are News items or Events.

    Do you have a more complete sample code that can search through all other content types, such News, Events, Documents & Files, Lists, and Content blocks?

  2. Vesselin May 03, 2013
    Hey Jimmy,

    the above code works with Page nodes only, but you can apply the same approach with other content types as News, Events, etc.

    Just check the type of the item and then invoke the corresponding manager to find the item and check its permissions.
  3. Chanan May 17, 2013
    Just a word of caution: this works on search results afterbinding, so if your visitors' searches are likely to produce multiple results pages, this would present a problem. At least this is our experience.
  4. Chanan May 20, 2013
    Just been informed that this blog will be updated by the end of this month (May 2013) to fix the paging problem.
  5. Vesselin May 21, 2013
    The code was updated to include the paging scenarios. It will be live soon.

    Leave a comment