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?

  • Are you referring any managed properties in query text, and if they marked to be indexed and searchable? – Falak Mahmood Jul 3 '15 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) – Robert Lindgren Jul 3 '15 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; – Falak Mahmood Jul 3 '15 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? – Robert Lindgren Jul 3 '15 at 10:33
  • Yes, get it from actual site instead – Falak Mahmood Jul 3 '15 at 13:12
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;
  • 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? – Robert Lindgren Jul 8 '15 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 Jul 8 '15 at 13:51
  • After changing the last row to if(HttpContext.Current == null) it seems to work better! – Robert Lindgren Jul 8 '15 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! – Robert Lindgren Jul 8 '15 at 13:54
  • @RobertLindgren Cool :) I'm glad it solved it. – user2536 Jul 8 '15 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;

  • 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 :) – Robert Lindgren Jul 8 '15 at 11:24
  • I will do it in a try catch finally to make sure to not kill the HttpContext.Current though ;) – Robert Lindgren Jul 8 '15 at 11:26
  • Sadly, still the same behavior of executing the query as current user! – Robert Lindgren Jul 8 '15 at 12:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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