Windows Server 2008 impersonation.

Discussion in 'ASP .Net Security' started by Ron, Sep 23, 2009.

  1. Ron

    Ron Guest

    I have an application that ran fine under Server 2003 x32 and now has
    intermittent failures under Windows Server 2008 x64.

    The application allow users to reset their password in the active directory
    when the have lost their password entirely.

    When the problem occurrs, no error is returned, but the password is not reset.

    I suspect that the problem may be with the impersonation, but I have not
    been able to locate any documentation on the correct way to accomplish an
    impersonation under Windows Server 2008. Any help would be appreciated.

    There was no change to the domain when we started using Windows Server 2008
    and the website appears to run just fine on the old Windows Server 2003
    machine.

    One issue that I am not sure of…the impersonator uses the advapi32.dll and
    kernel32.dll libraries. Note that the machine is a Windows Server 2008 x64
    machine.

    Basically it does the following.
    1) Impersonate a user with password set access to the OU that contains the
    user.
    2) objUSer.AuthenticationType = AuthenticationTypes.Secure
    3) objUSer.Invoke("SetPassword", strPassword)
    4) objUSer.CommitChanges()
    5) Undo Impersonation

    Impersonation is by:
    Public Function ImpersonateUser( _
    ByVal Domain As String, _
    ByVal userName As String, _
    ByVal password As String) As Boolean
    Dim tempWindowsIdentity As WindowsIdentity
    Dim token As IntPtr = IntPtr.Zero
    Dim tokenDuplicate As IntPtr = IntPtr.Zero
    Dim iError As Integer
    Dim ret As Integer
    Dim strErr As String

    Try
    If RevertToSelf() Then
    iError = LogonUserA(userName, Domain, password,
    LogonType.LOGON32_LOGON_INTERACTIVE, _
    LogonProvider.LOGON32_PROVIDER_DEFAULT, token)
    If iError <> 0 Then
    If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
    tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
    impersonationContext = tempWindowsIdentity.Impersonate()
    If Not impersonationContext Is Nothing Then
    ImpersonateUser = True
    Else
    ret = Marshal.GetLastWin32Error()
    strErr = "No Context returned:" & ErrorMessage(ret)
    Throw New ApplicationException(strErr)
    End If
    Else
    CloseHandle(token)
    ret = Marshal.GetLastWin32Error()
    strErr = "Failed To Duplicate Token:" & ErrorMessage(ret)
    Throw New ApplicationException(strErr)
    End If
    Else
    ret = Marshal.GetLastWin32Error()
    strErr = "LogonUser failed:" & ErrorMessage(ret)
    Throw New ApplicationException(strErr)

    End If
    Else
    ret = Marshal.GetLastWin32Error()
    strErr = "RevertToSelf Failed:" & ErrorMessage(ret)
    Throw New ApplicationException(strErr)
    End If
    If Not tokenDuplicate.Equals(IntPtr.Zero) Then
    CloseHandle(tokenDuplicate)
    End If
    If Not token.Equals(IntPtr.Zero) Then
    CloseHandle(token)
    End If

    Catch appEx As ApplicationException
    sError = appEx.Message
    'objErrorLog.WriteTOErrorLog(sLoginUserName, Err.Number, appEx.Source,
    appEx.TargetSite.Name, appEx.Message, appEx.StackTrace)
    ImpersonateUser = False

    End Try

    End Function
     
    Ron, Sep 23, 2009
    #1
    1. Advertising

  2. Ron

    Joe Kaplan Guest

    Invoke of the ADSI SetPassword method should throw an exception if the
    password modification operation fails. So, it seems like something may be
    getting lost in translation here.

    Normally, you don't need impersonation code for this. You would just put
    the creds used for impersonation directly into the DirectoryEntry
    constructor. That's quite a bit less code. :)

    Normally I'd use a network login type for this sort of impersonation too
    rather than interactive, but as long as the user has interactive login
    rights on the server where this runs, that should still work.

    --
    Joe Kaplan-MS MVP Directory Services Programming
    Co-author of "The .NET Developer's Guide to Directory Services Programming"
    http://www.directoryprogramming.net
    "Ron" <> wrote in message
    news:...
    >I have an application that ran fine under Server 2003 x32 and now has
    > intermittent failures under Windows Server 2008 x64.
    >
    > The application allow users to reset their password in the active
    > directory
    > when the have lost their password entirely.
    >
    > When the problem occurrs, no error is returned, but the password is not
    > reset.
    >
    > I suspect that the problem may be with the impersonation, but I have not
    > been able to locate any documentation on the correct way to accomplish an
    > impersonation under Windows Server 2008. Any help would be appreciated.
    >
    > There was no change to the domain when we started using Windows Server
    > 2008
    > and the website appears to run just fine on the old Windows Server 2003
    > machine.
    >
    > One issue that I am not sure of…the impersonator uses the advapi32.dll and
    > kernel32.dll libraries. Note that the machine is a Windows Server 2008 x64
    > machine.
    >
    > Basically it does the following.
    > 1) Impersonate a user with password set access to the OU that contains the
    > user.
    > 2) objUSer.AuthenticationType = AuthenticationTypes.Secure
    > 3) objUSer.Invoke("SetPassword", strPassword)
    > 4) objUSer.CommitChanges()
    > 5) Undo Impersonation
    >
    > Impersonation is by:
    > Public Function ImpersonateUser( _
    > ByVal Domain As String, _
    > ByVal userName As String, _
    > ByVal password As String) As Boolean
    > Dim tempWindowsIdentity As WindowsIdentity
    > Dim token As IntPtr = IntPtr.Zero
    > Dim tokenDuplicate As IntPtr = IntPtr.Zero
    > Dim iError As Integer
    > Dim ret As Integer
    > Dim strErr As String
    >
    > Try
    > If RevertToSelf() Then
    > iError = LogonUserA(userName, Domain, password,
    > LogonType.LOGON32_LOGON_INTERACTIVE, _
    > LogonProvider.LOGON32_PROVIDER_DEFAULT, token)
    > If iError <> 0 Then
    > If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
    > tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
    > impersonationContext = tempWindowsIdentity.Impersonate()
    > If Not impersonationContext Is Nothing Then
    > ImpersonateUser = True
    > Else
    > ret = Marshal.GetLastWin32Error()
    > strErr = "No Context returned:" & ErrorMessage(ret)
    > Throw New ApplicationException(strErr)
    > End If
    > Else
    > CloseHandle(token)
    > ret = Marshal.GetLastWin32Error()
    > strErr = "Failed To Duplicate Token:" & ErrorMessage(ret)
    > Throw New ApplicationException(strErr)
    > End If
    > Else
    > ret = Marshal.GetLastWin32Error()
    > strErr = "LogonUser failed:" & ErrorMessage(ret)
    > Throw New ApplicationException(strErr)
    >
    > End If
    > Else
    > ret = Marshal.GetLastWin32Error()
    > strErr = "RevertToSelf Failed:" & ErrorMessage(ret)
    > Throw New ApplicationException(strErr)
    > End If
    > If Not tokenDuplicate.Equals(IntPtr.Zero) Then
    > CloseHandle(tokenDuplicate)
    > End If
    > If Not token.Equals(IntPtr.Zero) Then
    > CloseHandle(token)
    > End If
    >
    > Catch appEx As ApplicationException
    > sError = appEx.Message
    > 'objErrorLog.WriteTOErrorLog(sLoginUserName, Err.Number,
    > appEx.Source,
    > appEx.TargetSite.Name, appEx.Message, appEx.StackTrace)
    > ImpersonateUser = False
    >
    > End Try
    >
    > End Function
    >
     
    Joe Kaplan, Sep 23, 2009
    #2
    1. Advertising

  3. Ron

    Ron Guest

    When that was first developed, we could not get the password to reset without
    doing the impersonation. That was several years ago, however.

    Thanks for your help...I will try it with the authorization in the
    DirectoryEntry constructor.

    "Joe Kaplan" wrote:

    > Invoke of the ADSI SetPassword method should throw an exception if the
    > password modification operation fails. So, it seems like something may be
    > getting lost in translation here.
    >
    > Normally, you don't need impersonation code for this. You would just put
    > the creds used for impersonation directly into the DirectoryEntry
    > constructor. That's quite a bit less code. :)
    >
    > Normally I'd use a network login type for this sort of impersonation too
    > rather than interactive, but as long as the user has interactive login
    > rights on the server where this runs, that should still work.
    >
    > --
    > Joe Kaplan-MS MVP Directory Services Programming
    > Co-author of "The .NET Developer's Guide to Directory Services Programming"
    > http://www.directoryprogramming.net
    > "Ron" <> wrote in message
    > news:...
    > >I have an application that ran fine under Server 2003 x32 and now has
    > > intermittent failures under Windows Server 2008 x64.
    > >
    > > The application allow users to reset their password in the active
    > > directory
    > > when the have lost their password entirely.
    > >
    > > When the problem occurrs, no error is returned, but the password is not
    > > reset.
    > >
    > > I suspect that the problem may be with the impersonation, but I have not
    > > been able to locate any documentation on the correct way to accomplish an
    > > impersonation under Windows Server 2008. Any help would be appreciated.
    > >
    > > There was no change to the domain when we started using Windows Server
    > > 2008
    > > and the website appears to run just fine on the old Windows Server 2003
    > > machine.
    > >
    > > One issue that I am not sure of…the impersonator uses the advapi32.dll and
    > > kernel32.dll libraries. Note that the machine is a Windows Server 2008 x64
    > > machine.
    > >
    > > Basically it does the following.
    > > 1) Impersonate a user with password set access to the OU that contains the
    > > user.
    > > 2) objUSer.AuthenticationType = AuthenticationTypes.Secure
    > > 3) objUSer.Invoke("SetPassword", strPassword)
    > > 4) objUSer.CommitChanges()
    > > 5) Undo Impersonation
    > >
    > > Impersonation is by:
    > > Public Function ImpersonateUser( _
    > > ByVal Domain As String, _
    > > ByVal userName As String, _
    > > ByVal password As String) As Boolean
    > > Dim tempWindowsIdentity As WindowsIdentity
    > > Dim token As IntPtr = IntPtr.Zero
    > > Dim tokenDuplicate As IntPtr = IntPtr.Zero
    > > Dim iError As Integer
    > > Dim ret As Integer
    > > Dim strErr As String
    > >
    > > Try
    > > If RevertToSelf() Then
    > > iError = LogonUserA(userName, Domain, password,
    > > LogonType.LOGON32_LOGON_INTERACTIVE, _
    > > LogonProvider.LOGON32_PROVIDER_DEFAULT, token)
    > > If iError <> 0 Then
    > > If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
    > > tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
    > > impersonationContext = tempWindowsIdentity.Impersonate()
    > > If Not impersonationContext Is Nothing Then
    > > ImpersonateUser = True
    > > Else
    > > ret = Marshal.GetLastWin32Error()
    > > strErr = "No Context returned:" & ErrorMessage(ret)
    > > Throw New ApplicationException(strErr)
    > > End If
    > > Else
    > > CloseHandle(token)
    > > ret = Marshal.GetLastWin32Error()
    > > strErr = "Failed To Duplicate Token:" & ErrorMessage(ret)
    > > Throw New ApplicationException(strErr)
    > > End If
    > > Else
    > > ret = Marshal.GetLastWin32Error()
    > > strErr = "LogonUser failed:" & ErrorMessage(ret)
    > > Throw New ApplicationException(strErr)
    > >
    > > End If
    > > Else
    > > ret = Marshal.GetLastWin32Error()
    > > strErr = "RevertToSelf Failed:" & ErrorMessage(ret)
    > > Throw New ApplicationException(strErr)
    > > End If
    > > If Not tokenDuplicate.Equals(IntPtr.Zero) Then
    > > CloseHandle(tokenDuplicate)
    > > End If
    > > If Not token.Equals(IntPtr.Zero) Then
    > > CloseHandle(token)
    > > End If
    > >
    > > Catch appEx As ApplicationException
    > > sError = appEx.Message
    > > 'objErrorLog.WriteTOErrorLog(sLoginUserName, Err.Number,
    > > appEx.Source,
    > > appEx.TargetSite.Name, appEx.Message, appEx.StackTrace)
    > > ImpersonateUser = False
    > >
    > > End Try
    > >
    > > End Function
    > >

    >
    >
     
    Ron, Sep 23, 2009
    #3
  4. Ron

    Joe Kaplan Guest

    ADSI was more limited years ago so perhaps that was the issue. In some
    cases, the SetPassword method can be a pain to deal with in general and some
    use cases may actually require the impersonation.

    It is often cleaner just to set up a separate app pool for this app on the
    server, run it as the admin user, add the user to the appropriate IIS_WPG
    group and get rid of the impersonation AND the hard coded credentials. The
    key is getting the right windows identity to do the work on the remote
    machine and any of those approaches could work but this one is probably
    easiest and most secure in that the admin is more in charge since the config
    change to the app pool is made externally.

    Best of luck!

    --
    Joe Kaplan-MS MVP Directory Services Programming
    Co-author of "The .NET Developer's Guide to Directory Services Programming"
    http://www.directoryprogramming.net
    "Ron" <> wrote in message
    news:...
    > When that was first developed, we could not get the password to reset
    > without
    > doing the impersonation. That was several years ago, however.
    >
    > Thanks for your help...I will try it with the authorization in the
    > DirectoryEntry constructor.
    >
    > "Joe Kaplan" wrote:
    >
    >> Invoke of the ADSI SetPassword method should throw an exception if the
    >> password modification operation fails. So, it seems like something may
    >> be
    >> getting lost in translation here.
    >>
    >> Normally, you don't need impersonation code for this. You would just put
    >> the creds used for impersonation directly into the DirectoryEntry
    >> constructor. That's quite a bit less code. :)
    >>
    >> Normally I'd use a network login type for this sort of impersonation too
    >> rather than interactive, but as long as the user has interactive login
    >> rights on the server where this runs, that should still work.
    >>
    >> --
    >> Joe Kaplan-MS MVP Directory Services Programming
    >> Co-author of "The .NET Developer's Guide to Directory Services
    >> Programming"
    >> http://www.directoryprogramming.net
    >> "Ron" <> wrote in message
    >> news:...
    >> >I have an application that ran fine under Server 2003 x32 and now has
    >> > intermittent failures under Windows Server 2008 x64.
    >> >
    >> > The application allow users to reset their password in the active
    >> > directory
    >> > when the have lost their password entirely.
    >> >
    >> > When the problem occurrs, no error is returned, but the password is not
    >> > reset.
    >> >
    >> > I suspect that the problem may be with the impersonation, but I have
    >> > not
    >> > been able to locate any documentation on the correct way to accomplish
    >> > an
    >> > impersonation under Windows Server 2008. Any help would be appreciated.
    >> >
    >> > There was no change to the domain when we started using Windows Server
    >> > 2008
    >> > and the website appears to run just fine on the old Windows Server 2003
    >> > machine.
    >> >
    >> > One issue that I am not sure of…the impersonator uses the advapi32.dll
    >> > and
    >> > kernel32.dll libraries. Note that the machine is a Windows Server 2008
    >> > x64
    >> > machine.
    >> >
    >> > Basically it does the following.
    >> > 1) Impersonate a user with password set access to the OU that contains
    >> > the
    >> > user.
    >> > 2) objUSer.AuthenticationType = AuthenticationTypes.Secure
    >> > 3) objUSer.Invoke("SetPassword", strPassword)
    >> > 4) objUSer.CommitChanges()
    >> > 5) Undo Impersonation
    >> >
    >> > Impersonation is by:
    >> > Public Function ImpersonateUser( _
    >> > ByVal Domain As String, _
    >> > ByVal userName As String, _
    >> > ByVal password As String) As Boolean
    >> > Dim tempWindowsIdentity As WindowsIdentity
    >> > Dim token As IntPtr = IntPtr.Zero
    >> > Dim tokenDuplicate As IntPtr = IntPtr.Zero
    >> > Dim iError As Integer
    >> > Dim ret As Integer
    >> > Dim strErr As String
    >> >
    >> > Try
    >> > If RevertToSelf() Then
    >> > iError = LogonUserA(userName, Domain, password,
    >> > LogonType.LOGON32_LOGON_INTERACTIVE, _
    >> > LogonProvider.LOGON32_PROVIDER_DEFAULT, token)
    >> > If iError <> 0 Then
    >> > If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
    >> > tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
    >> > impersonationContext = tempWindowsIdentity.Impersonate()
    >> > If Not impersonationContext Is Nothing Then
    >> > ImpersonateUser = True
    >> > Else
    >> > ret = Marshal.GetLastWin32Error()
    >> > strErr = "No Context returned:" & ErrorMessage(ret)
    >> > Throw New ApplicationException(strErr)
    >> > End If
    >> > Else
    >> > CloseHandle(token)
    >> > ret = Marshal.GetLastWin32Error()
    >> > strErr = "Failed To Duplicate Token:" & ErrorMessage(ret)
    >> > Throw New ApplicationException(strErr)
    >> > End If
    >> > Else
    >> > ret = Marshal.GetLastWin32Error()
    >> > strErr = "LogonUser failed:" & ErrorMessage(ret)
    >> > Throw New ApplicationException(strErr)
    >> >
    >> > End If
    >> > Else
    >> > ret = Marshal.GetLastWin32Error()
    >> > strErr = "RevertToSelf Failed:" & ErrorMessage(ret)
    >> > Throw New ApplicationException(strErr)
    >> > End If
    >> > If Not tokenDuplicate.Equals(IntPtr.Zero) Then
    >> > CloseHandle(tokenDuplicate)
    >> > End If
    >> > If Not token.Equals(IntPtr.Zero) Then
    >> > CloseHandle(token)
    >> > End If
    >> >
    >> > Catch appEx As ApplicationException
    >> > sError = appEx.Message
    >> > 'objErrorLog.WriteTOErrorLog(sLoginUserName, Err.Number,
    >> > appEx.Source,
    >> > appEx.TargetSite.Name, appEx.Message, appEx.StackTrace)
    >> > ImpersonateUser = False
    >> >
    >> > End Try
    >> >
    >> > End Function
    >> >

    >>
    >>
     
    Joe Kaplan, Sep 23, 2009
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. shapper

    Windows 2008 and SQL 2008

    shapper, Dec 8, 2007, in forum: ASP .Net
    Replies:
    1
    Views:
    347
    Mark Fitzpatrick
    Dec 8, 2007
  2. Replies:
    0
    Views:
    505
  3. Barry Kelly
    Replies:
    0
    Views:
    405
    Barry Kelly
    Jan 9, 2008
  4. AAaron123
    Replies:
    6
    Views:
    2,522
    AAaron123
    Oct 28, 2008
  5. Julien
    Replies:
    1
    Views:
    2,077
    Cowboy \(Gregory A. Beamer\)
    May 18, 2009
Loading...

Share This Page