Search code examples
asp.netauthenticationweb-parts

How do I impersonate using aspnet_personalization Windows Authentication


Having trouble figuring out how to impersonate another user while using aspnet_personalization with Windows authentication.

I am using asp.net's personalization framework on my page:

        <asp:WebPartManager ID="WebPartManager1" runat="server" >
            <Personalization Enabled="True" />
        </asp:WebPartManager>

My page is in an existing web app that uses AuthenticationMode="Windows" (which I cannot change, and IIS is also set to Windows Authentication). This web app has a page that allows super-users to impersonate any other user. This is accomplished by manipulating a connection string that is built dynamically every time we hit the database.

My problem is that aspnet_personalization still uses windows authentication. When I try to edit the connection string used by aspnet_personalization dynamically, aspnet does not seem to use it - it still uses the username of the current NT account.

I have the following in my web.config's configuration tag:

  <connectionStrings>
    <remove name="LocalSqlServer"/>
    <add name="AnotherConnectionString" connectionString="Data Source=serverName;Initial Catalog=dbName;Integrated Security=True" providerName="System.Data.SqlClient"/>
  </connectionStrings>
<system.web>
  <membership>
    <providers>
      <remove name="AspNetSqlMembershipProvider"/>
      <add name="AspNetSqlMembershipProvider"  
         type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" 
         applicationName="/" 
         connectionStringName="AnotherConnectionString" />
    </providers>
  </membership>
  <profile enabled="true" defaultProvider="TableProfileProvider">
    <providers>
      <clear />
      <add name="TableProfileProvider" type="Microsoft.Samples.SqlTableProfileProvider" connectionStringName="AnotherConnectionString" table="aspnet_Profile" applicationName="/" />
    </providers>
  <!--<properties></properties>-->
  </profile>

I tried editing the connection string by adding code as follows whenever we impersonate a user, hoping asp.net would use it, but it does not:

    Dim settings = ConfigurationManager.ConnectionStrings("AnotherConnectionString")
    Dim fi = GetType(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance Or BindingFlags.NonPublic)
    fi.SetValue(settings, False)
    settings.ConnectionString = "data source=serverName;database=dbName;user id=" & login & "; password=" & password

I did confirm on page_load of the page containing the webPartManager that "AnotherConnectionString" does contain the desired username, but asp.net_personalization still calls its stored procs using the NT username.

ANSWER:

Stackoverflow won't let me post an answer. That's ridiculous, so after I post the answer inside the question, I'm deleting my account and will encourage others to do the same.

I solved the problem by extending SqlPersonalizationProvider:

Imports System.Web.UI.WebControls.WebParts
Public Class MySqlPersonalizationProvider
   Inherits SqlPersonalizationProvider

    Protected Overrides Sub LoadPersonalizationBlobs(ByVal webPartManager As System.Web.UI.WebControls.WebParts.WebPartManager, ByVal path As String, ByVal userName As String, ByRef sharedDataBlob() As Byte, ByRef userDataBlob() As Byte)
        Dim impersonatedName As String = MySession.UserLoginName()
        path = path & "|" & impersonatedName
        userName = impersonatedName
        MyBase.LoadPersonalizationBlobs(webPartManager, path, userName, sharedDataBlob, userDataBlob)
    End Sub

    Protected Overrides Sub SavePersonalizationBlob(ByVal webPartManager As System.Web.UI.WebControls.WebParts.WebPartManager, ByVal path As String, ByVal userName As String, ByVal dataBlob() As Byte)
        Dim impersonatedName As String = MySession.UserLoginName()
        path = path & "|" & impersonatedName
        userName = impersonatedName
        MyBase.SavePersonalizationBlob(webPartManager, path, userName, dataBlob)
    End Sub
End Class

And then in web.config:

<system.web>
  <webParts>
    <personalization defaultProvider="AspNetSqlPersonalizationProvider">
      <providers>
        <remove name="AspNetSqlPersonalizationProvider"/>
        <add name="AspNetSqlPersonalizationProvider"
             type="MyProject.MySqlPersonalizationProvider"
             connectionStringName="MyConnectionString"
             applicationName="/"></add>
      </providers>
    </personalization>
  </webParts>

  <profile enabled="true" defaultProvider="TableProfileProvider">
    <providers>
      <clear />
      <add name="TableProfileProvider" type="Microsoft.Samples.SqlTableProfileProvider" connectionStringName="iCaseHomepage" table="aspnet_Profile" applicationName="/" />
    </providers>
  </profile>
</system.web>
<connectionStrings>
  <remove name="LocalSqlServer"/>
  <add name="MyConnectionString" connectionString="Data Source=MyServerName;Initial Catalog=MyDatabaseName;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>

and on the page:

        <asp:WebPartManager ID="WebPartManager1" runat="server" >
            <Personalization Enabled="True" />
        </asp:WebPartManager>

Solution

  • Looks like I'm allowed to post an answer now. I guess I won't delete my account after all. But geez, SO isn't very friendly to noobs.

    Anyway, I solved the problem by extending SqlPersonalizationProvider:

    Imports System.Web.UI.WebControls.WebParts
    Public Class MySqlPersonalizationProvider
       Inherits SqlPersonalizationProvider
    
        Protected Overrides Sub LoadPersonalizationBlobs(ByVal webPartManager As System.Web.UI.WebControls.WebParts.WebPartManager, ByVal path As String, ByVal userName As String, ByRef sharedDataBlob() As Byte, ByRef userDataBlob() As Byte)
            Dim impersonatedName As String = MySession.UserLoginName()
            path = path & "|" & impersonatedName
            userName = impersonatedName
            MyBase.LoadPersonalizationBlobs(webPartManager, path, userName, sharedDataBlob, userDataBlob)
        End Sub
    
        Protected Overrides Sub SavePersonalizationBlob(ByVal webPartManager As System.Web.UI.WebControls.WebParts.WebPartManager, ByVal path As String, ByVal userName As String, ByVal dataBlob() As Byte)
            Dim impersonatedName As String = MySession.UserLoginName()
            path = path & "|" & impersonatedName
            userName = impersonatedName
            MyBase.SavePersonalizationBlob(webPartManager, path, userName, dataBlob)
        End Sub
    End Class
    

    And then in web.config:

    <system.web>
      <webParts>
        <personalization defaultProvider="AspNetSqlPersonalizationProvider">
          <providers>
            <remove name="AspNetSqlPersonalizationProvider"/>
            <add name="AspNetSqlPersonalizationProvider"
                 type="MyProject.MySqlPersonalizationProvider"
                 connectionStringName="MyConnectionString"
                 applicationName="/"></add>
          </providers>
        </personalization>
      </webParts>
    
      <profile enabled="true" defaultProvider="TableProfileProvider">
        <providers>
          <clear />
          <add name="TableProfileProvider" type="Microsoft.Samples.SqlTableProfileProvider" connectionStringName="iCaseHomepage" table="aspnet_Profile" applicationName="/" />
        </providers>
      </profile>
    </system.web>
    <connectionStrings>
      <remove name="LocalSqlServer"/>
      <add name="MyConnectionString" connectionString="Data Source=MyServerName;Initial Catalog=MyDatabaseName;Integrated Security=True" providerName="System.Data.SqlClient"/>
    </connectionStrings>
    

    and on the page:

            <asp:WebPartManager ID="WebPartManager1" runat="server" >
                <Personalization Enabled="True" />
            </asp:WebPartManager>