Сквозная авторизация в AD

152
10 ноября 2018, 15:30

Как сделать сквозную авторизацию по имени пользователя в AD на компьютерах с Windows?

Пример: пользователь заходит в приложение, вводит имя пользователя и пароль AD и от сервера получает данные связанные с этой учетной записью

Answer 1

Как-то так:

//Reference: System.DirectoryServices.AccountManagement
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Security.Principal;
using System.DirectoryServices.AccountManagement;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
    static class Program
    {
        //Проверяет, авторизован ли пользователь в домене
        public static bool IsInDomain(string domain)
        {
            bool retval = false;
            NetJoinStatus status = NetJoinStatus.NetSetupUnknownStatus;
            IntPtr pDomain = IntPtr.Zero;
            int result = NetGetJoinInformation(null, out pDomain, out status);
            if (result != 0) throw new Win32Exception("NetGetJoinInformation failed");
            if (pDomain != IntPtr.Zero)
            {
                string curr_domain = Marshal.PtrToStringUni(pDomain);
                if (status == NetJoinStatus.NetSetupDomainName &&
                    curr_domain.ToUpper().Trim() == domain.ToUpper().Trim())
                {
                    retval = true;
                }
                NetApiBufferFree(pDomain);
            }
            return retval;
        }
        //Выводит диалоговое окно ввода логина и пароля, и возвращает имя пользователя при успешной авторизации
        static string EnterCredentials(string domain)
        {
            bool save = false;
            int errorcode = 0;
            uint dialogReturn;
            uint authPackage = 0;
            IntPtr outCredBuffer;
            uint outCredSize;
            CREDUI_INFO credui = new CREDUI_INFO();
            credui.cbSize = Marshal.SizeOf(credui);
            credui.pszCaptionText = "Авторизация";
            credui.pszMessageText = "Введите логин и пароль";
            credui.hwndParent = IntPtr.Zero;
            //Show dialog
            dialogReturn = CredUIPromptForWindowsCredentials(ref credui,
            errorcode, ref authPackage, (IntPtr)0, 0, out outCredBuffer, out outCredSize, ref save,
            0x1 /*CREDUIWIN_GENERIC*/);
            if (dialogReturn != 0) return ""; //Cancel pressed
            var usernameBuf = new StringBuilder(100);
            var passwordBuf = new StringBuilder(100);
            var domainBuf = new StringBuilder(100);
            int maxUserName = 100;
            int maxDomain = 100;
            int maxPassword = 100;
            //Validate credentials
            if (CredUnPackAuthenticationBuffer(0, outCredBuffer, outCredSize, usernameBuf,
                ref maxUserName, domainBuf, ref maxDomain, passwordBuf, ref maxPassword))
            {
                CoTaskMemFree(outCredBuffer);
                using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
                {
                    bool valid;
                    valid = context.ValidateCredentials(usernameBuf.ToString(), passwordBuf.ToString());
                    if (valid) return usernameBuf.ToString();
                    else return "";
                }
            }
            else throw new ApplicationException("CredUnPackAuthenticationBuffer failed");
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            string domain = "Domain"; 
            string user = Environment.UserName;
            bool logged = IsInDomain(domain);
            if (logged)
            {
                MessageBox.Show("Здравствуйте, " + user + ". Вы уже авторизованы в " + domain);
            }
            else
            {
                user = EnterCredentials(domain);
                if (user == "")
                {
                    MessageBox.Show("Не удалось авторизоваться");
                    return;
                }
                else MessageBox.Show("Здравствуйте, " + user + ". Добро пожаловать в " + domain);
            }
            Application.Run(new Form1());
        }

        // *** WINAPI Functions ***
        [DllImport("credui.dll", CharSet = CharSet.Unicode)]
        private static extern uint CredUIPromptForWindowsCredentials(ref CREDUI_INFO notUsedHere,
          int authError,
          ref uint authPackage,
          IntPtr InAuthBuffer,
          uint InAuthBufferSize,
          out IntPtr refOutAuthBuffer,
          out uint refOutAuthBufferSize,
          ref bool fSave,
          uint flags);
        [DllImport("credui.dll", CharSet = CharSet.Auto)]
        private static extern bool CredUnPackAuthenticationBuffer(int dwFlags, IntPtr pAuthBuffer, uint cbAuthBuffer,
            StringBuilder pszUserName, ref int pcchMaxUserName, StringBuilder pszDomainName,
            ref int pcchMaxDomainame, StringBuilder pszPassword, ref int pcchMaxPassword
            );
        [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int NetGetJoinInformation(string server, out IntPtr domain, out NetJoinStatus status);
        [DllImport("Netapi32.dll")]
        public static extern int NetApiBufferFree(IntPtr Buffer);
        public enum NetJoinStatus
        {
            NetSetupUnknownStatus = 0,
            NetSetupUnjoined,
            NetSetupWorkgroupName,
            NetSetupDomainName
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct CREDUI_INFO
        {
            public int cbSize;
            public IntPtr hwndParent;
            public string pszMessageText;
            public string pszCaptionText;
            public IntPtr hbmBanner;
        }
        [DllImport("ole32.dll")]
        public static extern void CoTaskMemFree(IntPtr ptr);
    }
}

Источники

  • How to detect if machine is joined to domain (in C#)?
  • C# Validate credentials against AD
READ ALSO
Создание обработчика события из MainWindow.cs на Page1.xaml

Создание обработчика события из MainWindow.cs на Page1.xaml

В чем дело?, я хочу добавить обработчик события из MainWindowxaml

178
Игнорируется связь One-to-Many в IdentityDbContext

Игнорируется связь One-to-Many в IdentityDbContext

Есть следующий контекст БД:

157
Не понятная ошибка TorSharp

Не понятная ошибка TorSharp

Есть два метода которые я использую, и если я вызываю второй раз его прегрузку то выдает ошибку, ошибку напишу ниже Вот код методов

176
C# наполнение массива textBox&#39;ами [дубликат]

C# наполнение массива textBox'ами [дубликат]

На данный вопрос уже ответили:

174