FBA and SQL Server: A Love Story

My colleague has been working on a web part in an FBA environment.  Among other things, the web part pulls some data from SQL server.  The grand plan for this project dictates that a DBA configures data level security in SQL (as opposed to embedding a user ID in a SQL query or some other approach).

The problem is that SQL server doesn’t know anything about our FBA environment so it can’t trust us.  We solved this problem by, for lack of a better word, manually impersonating an AD user so that we could connect to SQL such that SQL data level security works. 

Even though FBA is an ASP.NET feature, we SharePoint Nation people have taught the various search engines that if you’re querying for FBA, you must mean you want know how to configure FBA in SharePoint.  I failed to find find any information on how to enable an FBA oriented ASP.NET application to communicate with SQL in the way we needed. 

In the course of researching this, we re-read this article: ASP.NET Impersonation

More research led us to this codproject article: http://www.codeproject.com/KB/cs/cpimpersonation1.aspx

That helped us write our code, which I’ve included below.  It’s not the most elegant stuff, but it worked.  I hope you find it helpful.

Here’s the code that worked for us:

 

protected void btnSearchCarrier_Click(object sender, EventArgs e)
 {
 try
 {
 ImpersonateUser iU = new ImpersonateUser();
 // TODO: Replace credentials
 iU.Impersonate("DomainName", "UserName", "Password");

//
 CODE
//

 iU.Undo();
 }
 catch (Exception ex)
 {

 }
 }

// Using Impersonation class as mentioned below.

public class ImpersonateUser
 {
 [DllImport("advapi32.dll", SetLastError = true)]
 public static extern bool LogonUser(
 String lpszUsername,
 String lpszDomain,
 String lpszPassword,
 int dwLogonType,
 int dwLogonProvider,
 ref IntPtr phToken);

 [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
 private extern static bool CloseHandle(IntPtr handle);

 private static IntPtr tokenHandle = new IntPtr(0);
 private static WindowsImpersonationContext impersonatedUser;

 // If you incorporate this code into a DLL, be sure to demand that it
 // runs with FullTrust.
 [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
 public void Impersonate(string domainName, string userName, string password)
 {
 try
 {

 // Use the unmanaged LogonUser function to get the user token for
 // the specified user, domain, and password.
 const int LOGON32_PROVIDER_DEFAULT = 0;

 // Passing this parameter causes LogonUser to create a primary token.
 const int LOGON32_LOGON_INTERACTIVE = 2;
 tokenHandle = IntPtr.Zero;

 // Step -1 Call LogonUser to obtain a handle to an access token.
 bool returnValue = LogonUser(
 userName,
 domainName,
 password,
 LOGON32_LOGON_INTERACTIVE,
 LOGON32_PROVIDER_DEFAULT,
 ref tokenHandle); // tokenHandle - new security token

 if (false == returnValue)
 {
 int ret = Marshal.GetLastWin32Error();
 Console.WriteLine("LogonUser call failed with error code : " +
 ret);
 throw new System.ComponentModel.Win32Exception(ret);
 }

 // Step - 2
 WindowsIdentity newId = new WindowsIdentity(tokenHandle);
 // Step -3
 impersonatedUser = newId.Impersonate();

 }
 catch (Exception ex)
 {
 Console.WriteLine("Exception occurred. " + ex.Message);
 }
 }


 /// <summary>
 /// Stops impersonation
 /// </summary>
 public void Undo()
 {
 impersonatedUser.Undo();
 // Free the tokens.
 if (tokenHandle != IntPtr.Zero)
 CloseHandle(tokenHandle);
 }
 }

</end>

Subscribe to my blog.

Technorati Tags:

One thought on “FBA and SQL Server: A Love Story

  1. David Early
    Sorry for posting this unrelated question but I could not figure out how to send you an email from this blog.
     
    You had a previous post where you offered a great way to filter a library to view untagged data.  Do you have any thoughts as to how you might view a list of untagged documents in an entire document library?  Using an empty field in advanced search does not return any results.
     
    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *