views:

754

answers:

2

I have done impersonation in SharePoint quite a bit in the past by doing something such as the following.

SPWeb web = SPContext.Current.Web;
string currentWebUrl = web.Url;
SPUser user = web.EnsureUser(loginToImpersonate);
using (SPSite site = new SPSite(currentWebUrl, user.UserToken)
{
    using (SPWeb impersonatedWeb = site.OpenWeb())
    {
        // Any SharePoint access here to 'impersonatedWeb'
        // is impersonated as 'loginToImpersonate'
    }
}

Note that this does not require the password of the user you are impersonating, but does require certain code access security to run. As a side note the EnsureUser call also requires the current user to be an admin, but there are other methods that can be used in place of EnsureUser to get the SPUser object (trying to keep my code fragment simple for this question).

Now that I've set the stage... I now want to do either a FullTextSQLQuery or a KeywordQuery against either the MOSS or WSS query engine and get security trimmed results based on an impersonated user. Both objects can take a SPSite on the constructor, but ignore my impersonation logic. They go with the currently logged in user instead (HTTPContext.Current.User).

There are other constructors as well: application name (string) and for MOSS there's one with a ServerContext to the SSP, but I don't think these will help at all.

I've used Reflector on the KeywordQuery class and its base Query class and it gets pretty ugly pretty quick. I believe the actual logic that determines the user is down in unmanaged code.

So, is it possible for me to do this?

+4  A: 

You need real Windows impersonation to do this. The SPSite impersonation is not real impersonation - it just tells the WSS object model to write another user id to the created and modified fields in the content database.

For Windows impersonation you will unfortunately need both the login and password unless you want to impersonate the application pool account using SPSecurity.RunWithElevatedPrivileges

You can implement Windows impersonation as follows:

using (Impersonator imp = new Impersonator("user", "domain", "password"))
{
  // Do stuff impersonated
}

where the Impersonator class is implemented as:

public sealed class Impersonator : IDisposable
{
  private WindowsImpersonationContext impersonationContext;

  public Impersonator(string user, string domain, string password)
  {
    WindowsIdentity id = Logon(user, domain, password);
    impersonationContext = id.Impersonate();
  }

  public void Dispose()
  {
    if (impersonationContext != null)
    {
      impersonationContext.Undo();
      impersonationContext = null;
    }
  }

  private WindowsIdentity Logon(string user, string domain, string password)
  {
    WindowsIdentity identity;
    IntPtr handle = IntPtr.Zero;
    bool logonSucceeded = LogonUser(
      user, domain, password,
      8,   // LOGON32_LOGON_NETWORK_CLEARTEXT
      0,   // LOGON32_PROVIDER_DEFAULT
      ref handle);

    if (!logonSucceeded)
    {
      int errorCode = Marshal.GetLastWin32Error();
      throw new UnauthorizedAccessException("User logon failed. Error Number: " + errorCode);
    }

    identity = new WindowsIdentity(handle);
    CloseHandle(handle);

    return identity;
  }

  [DllImport("advapi32.dll", SetLastError = true)]
  private static extern bool LogonUser(string lpszUsername,
    string lpszDomain,
    string lpszPassword,
    int dwLogonType,
    int dwLogonProvider,
    ref IntPtr phToken);

  [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
  private static extern bool CloseHandle(IntPtr handle);
}
Lars Fastrup
Thanks, Lars. Not the answer I wanted to hear, of course, but it's good to know what my options are. I appreciate the Impersonator class. That looks nice.
Kirk Liemohn
Good stuff Lars, thanks for this.
Jason Watts
A: 

It turns out that you can do impersonated search in SharePoint without a password. We figured this out back in August of 2009 and I have been remiss in updating Stack Overflow with the answer.

See http://wiki.threewill.com/display/is/2010/06/18/Connect+to+SharePoint+-+Forwarding+User+Identities for the details and pay special attention to the special requirements. Note that this does work with both SharePoint 2007 and SharePoint 2010.

Many thanks to my coworker Eric Bowden who did all of the work!

Kirk Liemohn