Validating User Credentials

G

Guest

We have a need to prompt the user for their domain, username and password in
order to authenticate them against Active Directory. We have to support
Windows 2000, XP and 2003. I know that I can authenticate all of the
supported platforms using Directory Services/LDAPqueries but doing this
doesn't return a token (which I need) as in the case of LogonUser.
Unfortunately LogonUser requires "act as part of operating system" privliges
for Win 2000. Keith Brown has an SSPI work-around but I can't get it to work
in Beta2 of Whidbey. He basically uses the NegotiateStream class to perform a
handshake between client and server but I'm getting a "Authentication failed
because the remote party has closed the transport stream." error on the
AuthenticateAsClient method (code shown next).

MemoryStream couple = new MemoryStream();

using (NegotiateStream clientStream = new NegotiateStream(couple))
using (NegotiateStream serverStream = new NegotiateStream(couple))
{
string spn = WindowsIdentity.GetCurrent().Name;
NetworkCredential cred = new NetworkCredential(principal, password,
authority);
clientStream.AuthenticateAsClient(cred, spn, ProtectionLevel.None,
TokenImpersonationLevel.Impersonation);

serverStream.AuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, ProtectionLevel.None, TokenImpersonationLevel.None);

return serverStream.IsAuthenticated ?
(WindowsIdentity)serverStream.RemoteIdentity : null;
}


I guess I'm wondering if anyone has been able to get his sample working or
has done something similar for Windows 2000 clients. I've found some samples
using the NegotiateStream class but they are opening sockets, etc and I don't
really want to do all that just to authenticate login credentials.

Also, can any of the experts on the board recommend best practices for
authenticating users in a client/server (winform) environment? Any comments
or suggestions would be greatly appreciated.
 
G

Guest

Forgot to mention that one of the requirements is the need to authenticate
when the client is disconnected from the network. LogonUser provides this
facility which is what makes it a really attractive choice except for it's
limitation with Win 2000.
 
W

Willy Denoyette [MVP]

You need a "networkstream" to establish a network authentication handshake.
One option is to set-up a local tcp connection using the loopback interface
and use the socket stream to negotiate. Note that this way you can't use
domain credentials.
Something like this will do...

// Requires Whidbey - Beta2 !!!!!!!!
WindowsIdentity wi = null;
Thread t = new Thread(delegate() {
TcpListener l = new TcpListener(IPAddress.Parse("127.0.0.1"),9999);
l.Start();
TcpClient s = l.AcceptTcpClient();
NegotiateStream nsServ = new NegotiateStream(s.GetStream());
nsServ.AuthenticateAsServer(CredentialCache.DefaultNetworkCredentials,ProtectionLevel.None,
TokenImpersonationLevel.Impersonation);
wi = (WindowsIdentity)nsServ.RemoteIdentity;
});
t.Start();
TcpClient cli = new TcpClient();
cli.Connect("127.0.0.1", 9999);
NegotiateStream nsCli = new NegotiateStream(cli.GetStream());
string spn = WindowsIdentity.GetCurrent().Name;
NetworkCredential cred = new NetworkCredential("testuser", "kevin");
nsCli.AuthenticateAsClient(cred, spn,
ProtectionLevel.None, TokenImpersonationLevel.Impersonation);
Console.WriteLine("Client Identity: {0} - Token {1}", wi.Name,
wi.Token.ToString());

Willy.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top