11

I'm trying to documents of a certain content type that has a certain tagging (the documents are spread over several site collection). To get some performance I'm trying to do it with a KeywordQuery.

The problem I have is that the user executing the code might not have access to all documents, but the check must still be made on all documents. Therefore I have tried to run the query in an elevated mode:

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    using (SPSite eSite = new SPSite(siteUrl))
    {
        KeywordQuery keywordQuery = new KeywordQuery(eSite);
        keywordQuery.QueryText = "Some search query";
        keywordQuery.TrimDuplicates = false;
        SearchExecutor searchExecutor = new SearchExecutor();
        ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery);
        var resultTables = resultTableCollection.Filter("TableType", KnownTableTypes.RelevantResults);
        resultTable = resultTables.FirstOrDefault();
    }
});

This code returns an error

Operation is not valid due to the current state of the object

on this row KeywordQuery keywordQuery = new KeywordQuery(eSite);

Then I tried opening up the SPSite with the user token of the system account, like this:

using (SPSite scSite = new SPSite(siteCollection.Url, SPUserToken.SystemAccount))
{
     KeywordQuery keywordQuery = new KeywordQuery(scSite);
     keywordQuery.QueryText = "Some query"
     keywordQuery.TrimDuplicates = false;
     SearchExecutor searchExecutor = new SearchExecutor();
     ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery);
     var resultTables = resultTableCollection.Filter("TableType", KnownTableTypes.RelevantResults);
     resultTable = resultTables.FirstOrDefault();
}

This throws no error, but returns results only for the logged in user (not the system account).

Is it possible to execute a KeywordQuery in elevation, or without security trimming, without using some hardcore impersonation?

7
  • Are you referring any managed properties in query text, and if they marked to be indexed and searchable? Commented Jul 3, 2015 at 7:29
  • @FalakMahmood, I do not see how that is relevant to the question? Yes I do, and yes the retreival works perfectly (the problem is only that the results is security trimmed still) Commented Jul 3, 2015 at 7:30
  • I misunderstood the question, thinking if query ever worked. I believe underlying error message is more do with permissions than anything else. Why don't you try SPSite constructor, which receives system account user token SPUserToken from new but existing site collection object SPSite site = new SPSite("http://sharepoint1"); SPUserToken systoken = site.SystemAccount.UserToken; Commented Jul 3, 2015 at 10:09
  • Like I already do above? Or should I try retreiving the system account token from the actual web instead of the SPUserToken.SystemAccount? Commented Jul 3, 2015 at 10:33
  • Yes, get it from actual site instead Commented Jul 3, 2015 at 13:12

2 Answers 2

7
+50

I think @LeopoldLerch is on to the correct approach.

Try doing the following

Guid siteId = SPContext.Current.Site.ID;
SPUserToken systemAccountUserToken = SPContext.Current.Site.SystemAccount.UserToken;
HttpContext currentUserContext = HttpContext.Current;

if (SPContext.Current != null)
    HttpContext.Current = null;

SPSecurity.RunWithElevatedPrivileges(() =>
{
    using (SPSite elevatedSite = new SPSite(siteId, systemAccountUserToken))
    {
        HttpRequest httpRequest = new HttpRequest(string.Empty, elevatedSite.RootWeb.Url, string.Empty);
        HttpContext.Current = new HttpContext(httpRequest, new HttpResponse(new StringWriter()));
        SPControl.SetContextWeb(HttpContext.Current, elevatedSite.RootWeb);

        KeywordQuery keywordQuery = new KeywordQuery(elevatedSite);
        keywordQuery.QueryText = "Some query"
        keywordQuery.TrimDuplicates = false;
        // And then try setting SiteContext as well. Might not be necessary, but try it.
        keywordQuery.SiteContext = new Uri(elevatedSite.Url);
        SearchExecutor searchExecutor = new SearchExecutor();
        ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery);
        var resultTables = resultTableCollection.Filter("TableType", KnownTableTypes.RelevantResults);
        resultTable = resultTables.FirstOrDefault();
    }
});

HttpContext.Current = currentUserContext;
6
  • The part with checking if SPContext.Current is null the second time (when to set HttpContext.Current back does not work since SPContext.Current becomes null on setting HttpContext.Current to null. Do you recognize that? Commented Jul 8, 2015 at 13:45
  • @RobertLindgren Yes I do recognize that. Copy/pasted the code from a project where I had a situation where it might end up becoming null again before reaching that point. Removed it from here.
    – user2536
    Commented Jul 8, 2015 at 13:51
  • After changing the last row to if(HttpContext.Current == null) it seems to work better! Commented Jul 8, 2015 at 13:52
  • Dude! It seems to work (without the keywordQuery.SiteContext)! Not sure how your code differs from the original trials but something around nulling the context and getting the systemAccountUserToken seems to solve it! Commented Jul 8, 2015 at 13:54
  • @RobertLindgren Cool :) I'm glad it solved it.
    – user2536
    Commented Jul 8, 2015 at 13:55
4

Try to delete the current httpcontext before elevating (but do not forget to remember it and set it back

like

var storedContext = HttpContext.Current;
HttpContext.Current = null;
<Do something>
HttpContext.Current = storedContext;

Because it seems to use still your curentUsers Credentials when calling the search service (which it still does in the background). This trick works also in similar cases;

3
  • I've seen this when working with metadata-service and user profile-service. I will give it a try as soon as I have a minute :) Commented Jul 8, 2015 at 11:24
  • I will do it in a try catch finally to make sure to not kill the HttpContext.Current though ;) Commented Jul 8, 2015 at 11:26
  • Sadly, still the same behavior of executing the query as current user! Commented Jul 8, 2015 at 12:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.