The MSDN documentation for the NegotiateStream
class says:
Using NegotiateStream, you can do the following.
- Send the client's credentials to the server for Impersonation or Delegation.
- Request server authentication.
- Encrypt and/or sign data before transmitting it.
The first point is what I'm wanting to do - impersonate the remote client's user account but on the server.
But I can't figure out how to do that and can't find any examples that actually use impersonation. All the examples just set the flag to say they want Impersonation but then all they actually use is Identification, i.e. they just check the authenticated user's username or group membership - they don't actually act AS the remote user (impersonation)
So here's my code:
Dim Client As TcpClient = Listener.AcceptTcpClient
Using AuthStream As New NegotiateStream(Client.GetStream, False)
AuthStream.AuthenticateAsServer(Net.CredentialCache.DefaultCredentials, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Impersonation)
Dim ClientUser As New WindowsPrincipal(AuthStream.RemoteIdentity)
'Now what?
End Using
Some examples seem to think that doing this is the same as doing impersonation:
Dim ClientUser As New WindowsPrincipal(AuthStream.RemoteIdentity)
Threading.Thread.CurrentPrincipal = ClientUser
But it is not the same as impersonation at all. After doing that, the program won't be able to access files that only the authenticated remote user could access for example.
So how are we meant to use the Iidentity (or WindowsPrincipal built from that) that we get from the NegotiateStream to actually do impersonation?
NOTE: This needs to be done from a desktop application or windows service, not an ASP.NET app or WCF service.
Just realised that we can cast the IIdentity
we get from the stream to a WindowsIdentity
and then use that to do the impersonation like so:
Using AuthStream As New NegotiateStream(Client.GetStream, False)
AuthStream.AuthenticateAsServer(CredentialCache.DefaultCredentials, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Impersonation)
Dim ClientIdentity As WindowsIdentity = DirectCast(AuthStream.RemoteIdentity, WindowsIdentity)
Using ClientContext As WindowsImpersonationContext = ClientIdentity.Impersonate
'Do stuff as the remote user here'
End Using
End Using
Need to test this once I've implemented the client side and run it on a test domain but I think it should work.
EDIT: Tested and all works as expected