понедельник, 8 марта 2010 г.

NTLM Authentication просто и со вкусом

Я довольно долго искал простой и стандартный путь для того чтобы произвести аутентификацию пользователя (текущий пользователь - вы не знаете его пароля и пользователь заданный при помощи NetworkCredential) на удаленном компьютере. Хотел уже было все написать ручками через AcquireCredentialsHandle/InitializeSecurityContext/AcceptSecurityContext/CompleteAuthToken, но совсем неожиданно нашел NegotiateStream - который и занимается данным непростым процессом. По сему поводу написал маленький примерчик (пример работает только в пределах одного компьютера, если хотите большего, то замените NamedPipeXxxStream на Socket).

  1. namespace AuthTest
  2. {
  3.   public static class Constants
  4.   {
  5.     public const string PipeName = "AuthTest";
  6.   }
  7. }

  1. using System;
  2. using System.IO.Pipes;
  3. using System.Net;
  4. using System.Net.Security;
  5. using System.Security.Principal;
  6.  
  7. namespace AuthTest.Client
  8. {
  9.   internal class Program
  10.   {
  11.     private static void Main(string[] args)
  12.     {
  13.       try
  14.       {
  15.         Console.WriteLine("AuthTest Client Copyright (C) 2010 Mikhail Pilin");
  16.         using (var stream = new NamedPipeClientStream(Constants.PipeName))
  17.         {
  18.           stream.Connect();
  19.           using (var negotiateStream = new NegotiateStream(stream, true))
  20.             negotiateStream.AuthenticateAsClient(
  21.               GetCredential(args),
  22.               "",
  23.               ProtectionLevel.EncryptAndSign,
  24.               TokenImpersonationLevel.Delegation);
  25.         }
  26.  
  27.         Console.WriteLine("Done");
  28.       }
  29.       catch (Exception e)
  30.       {
  31.         Console.Error.WriteLine(e);
  32.       }
  33.     }
  34.  
  35.     private static NetworkCredential GetCredential(string[] args)
  36.     {
  37.       switch (args.Length)
  38.       {
  39.       case 0:
  40.         return (NetworkCredential) CredentialCache.DefaultCredentials;
  41.       case 1:
  42.         return new NetworkCredential(args[0], "");
  43.       case 2:
  44.         return new NetworkCredential(args[0], args[1]);
  45.       case 3:
  46.         return new NetworkCredential(args[0], args[1], args[2]);
  47.       default:
  48.         throw new ArgumentException();
  49.       }
  50.     }
  51.   }
  52. }

  1. using System;
  2. using System.IO.Pipes;
  3. using System.Net.Security;
  4. using System.Security.Principal;
  5.  
  6. namespace AuthTest.Server
  7. {
  8.   internal class Program
  9.   {
  10.     private static void Main()
  11.     {
  12.       try
  13.       {
  14.         Console.WriteLine("AuthTest Server Copyright (C) 2010 Mikhail Pilin");
  15.         using (var stream = new NamedPipeServerStream(Constants.PipeName))
  16.         {
  17.           stream.WaitForConnection();
  18.           using (var negotiateStream = new NegotiateStream(stream, true))
  19.           {
  20.             negotiateStream.AuthenticateAsServer();
  21.             var remoteIdentity = (WindowsIdentity) negotiateStream.RemoteIdentity;
  22.             Console.WriteLine("Name: {0}", remoteIdentity.Name);
  23.             Console.WriteLine("User: {0}", remoteIdentity.User);
  24.             Console.WriteLine("AuthenticationType: {0}", remoteIdentity.AuthenticationType);
  25.             Console.WriteLine("ImpersonationLevel: {0}", remoteIdentity.ImpersonationLevel);
  26.             Console.WriteLine("IsAuthenticated: {0}", remoteIdentity.IsAuthenticated);
  27.             Console.WriteLine("IsAnonymous: {0}", remoteIdentity.IsAnonymous);
  28.             Console.WriteLine("IsSystem: {0}", remoteIdentity.IsSystem);
  29.             Console.WriteLine("IsGuest: {0}", remoteIdentity.IsGuest);
  30.           }
  31.         }
  32.         Console.WriteLine("Done");
  33.       }
  34.       catch (Exception e)
  35.       {
  36.         Console.Error.WriteLine(e);
  37.       }
  38.     }
  39.   }
  40. }