C # Программная аутентификация удаленных папок / файлов в недоменной среде Windows

Мне нужно иметь возможность программной аутентификации при попытке чтения и записи файлов на удаленном компьютере в среде, не относящейся к домену.

Когда вы вводите команду в командной строке Windows RUN, которая похожа на \\ targetComputer \ C $ \ targetFolder или \\ targetComputer \ admin $, где целевой компьютер НЕ находится в домене, вам будет предложено ввести имя пользователя и пароль. После ввода имени пользователя и пароля у вас будет полный доступ к удаленной папке.

Как я могу выполнить эту аутентификацию программно на C #?

Я пробовал..

- Выдача себя за другое лицо, но похоже, что это работает только в среде домена.

--CMDKEY.exe, но похоже, что он работает только в доменной среде.

Должен быть способ сделать это, но я пока безуспешно искал везде и всюду. Может я просто не то ищу? Я уверен, что не первый, кто задает этот вопрос. Любая помощь будет принята с благодарностью.

Спасибо!

РЕДАКТИРОВАТЬ:

Думаю, я только что нашел другую публикацию SO, которая отвечает на мой вопрос: Доступ к общему файлу (UNC) из удаленного ненадежного домена с учетными данными

Я буду работать с этим сейчас и посмотрю, к чему это приведет.

Спасибо!


person dizzy.stackoverflow    schedule 20.06.2013    source источник
comment
Я думаю, что я только что нашел другую публикацию SO, которая отвечает на мой вопрос: Доступ к общему файлу (UNC) из удаленного, ненадежного домена с учетными данными. Я буду работать с этим сейчас и посмотрю, к чему это приведет. Спасибо!   -  person dizzy.stackoverflow    schedule 21.06.2013


Ответы (1)


Выдача себя за другое лицо также работает с одноранговой / локальной сетью. У меня есть обычная домашняя сеть с некоторыми машинами по умолчанию в «Рабочей группе», а некоторые с именованными, если я вспомнил, что делал это при установке.

Вот код, который я использую из своего серверного приложения IIS для доступа к файлам на другом моем компьютере (без необходимости иметь одного и того же пользователя и пароля на обеих задействованных машинах, скопированных откуда-то и модифицированных для моего использования):

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.ComponentModel;

/// <summary>
/// Class to impersonate another user. Requires user, pass and domain/computername
/// All code run after impersonationuser has been run will run as this user.
/// Remember to Dispose() afterwards.
/// </summary>
public class ImpersonateUser:IDisposable {

    private WindowsImpersonationContext LastContext = null;
    private IntPtr LastUserHandle = IntPtr.Zero;

    #region User Impersonation api
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateLoggedOnUser(int Token);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool DuplicateToken(IntPtr token, int impersonationLevel, ref IntPtr duplication);

    [DllImport("kernel32.dll")]
    public static extern Boolean CloseHandle(IntPtr hObject);

    public const int LOGON32_PROVIDER_DEFAULT = 0;
    public const int LOGON32_PROVIDER_WINNT35 = 1;
    public const int LOGON32_LOGON_INTERACTIVE = 2;
    public const int LOGON32_LOGON_NETWORK = 3;
    public const int LOGON32_LOGON_BATCH = 4;
    public const int LOGON32_LOGON_SERVICE = 5;
    public const int LOGON32_LOGON_UNLOCK = 7;
    public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;// Win2K or higher
    public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;// Win2K or higher
    #endregion

    public ImpersonateUser(string username, string domainOrComputerName, string password, int nm = LOGON32_LOGON_NETWORK) {

        IntPtr userToken = IntPtr.Zero;
        IntPtr userTokenDuplication = IntPtr.Zero;

        bool loggedOn = false;

        if (domainOrComputerName == null) domainOrComputerName = Environment.UserDomainName;

        if (domainOrComputerName.ToLower() == "nt authority") {
            loggedOn = LogonUser(username, domainOrComputerName, password, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, out userToken);
        } else {
            loggedOn = LogonUser(username, domainOrComputerName, password, nm, LOGON32_PROVIDER_DEFAULT, out userToken);
        }

        WindowsImpersonationContext _impersonationContext = null;
        if (loggedOn) {
            try {
                // Create a duplication of the usertoken, this is a solution
                // for the known bug that is published under KB article Q319615.
                if (DuplicateToken(userToken, 2, ref userTokenDuplication)) {
                    // Create windows identity from the token and impersonate the user.
                    WindowsIdentity identity = new WindowsIdentity(userTokenDuplication);
                    _impersonationContext = identity.Impersonate();
                } else {
                    // Token duplication failed!
                    // Use the default ctor overload
                    // that will use Mashal.GetLastWin32Error();
                    // to create the exceptions details.
                    throw new Win32Exception();
                }
            } finally {
                // Close usertoken handle duplication when created.
                if (!userTokenDuplication.Equals(IntPtr.Zero)) {
                    // Closes the handle of the user.
                    CloseHandle(userTokenDuplication);
                    userTokenDuplication = IntPtr.Zero;
                }

                // Close usertoken handle when created.
                if (!userToken.Equals(IntPtr.Zero)) {
                    // Closes the handle of the user.
                    CloseHandle(userToken);
                    userToken = IntPtr.Zero;
                }
            }
        } else {
            // Logon failed!
            // Use the default ctor overload that 
            // will use Mashal.GetLastWin32Error();
            // to create the exceptions details.
            throw new Win32Exception();
        }

        if (LastContext == null) LastContext = _impersonationContext;
    }

    public void Dispose() {
        LastContext.Undo();
        LastContext.Dispose();
    }
}

Конкретный код, который я обнаружил, работал после некоторых попыток:

using (var impersonation = new ImpersonateUser("OtherMachineUser", "OtherMachineName", "Password", LOGON32_LOGON_NEW_CREDENTIALS))
    {
        var files = System.IO.Directory.GetFiles("\\OtherMachineName\fileshare");
    }
person Wolf5    schedule 25.07.2013
comment
Мне удалось использовать следующий код для решения своей проблемы: stackoverflow.com/questions/659013/. Однако мне любопытно проверить ваш код позже (я думаю, что на самом деле я мог бы ... почувствовать, что видел этот код на SO, прежде чем опубликовал этот вопрос) и посмотреть, как он сравнивается с моим исходным кодом олицетворения. Первый взгляд на ваш код - это то, что он выглядит точно так же, как код, который я использовал ранее, только с успехом в средах домена. Позже я рассмотрю это более внимательно. Спасибо. - person dizzy.stackoverflow; 07.10.2013
comment
Ключ: LOGON32_LOGON_NEW_CREDENTIALS. Я пробовал все варианты, и LOGON32_LOGON_NEW_CREDENTIALS оказался тем, что сработало. Остальной код является общим. - person Wolf5; 08.10.2013
comment
Очень интересно. Я обязательно попробую и доложу. Спасибо! - person dizzy.stackoverflow; 08.10.2013
comment
Этот код у меня тоже сработал, хотя я решил немного другую проблему. Моя цель состояла в том, чтобы получить доступ к файлу в сетевой папке, которая использовала другой домен, чем моя локальная машина. Удивительно, но, несмотря на импорт dll, он работал прямо из коробки! - person stephen; 23.09.2014
comment
Я забыл сообщить об этом, но просто хотел сказать, что этот код работает отлично. Еще раз спасибо! - person dizzy.stackoverflow; 14.11.2014
comment
Можно ли получить доступ к необщему файлу / папке с помощью этого метода? - person Pabitra Dash; 22.06.2015
comment
Это просто олицетворение, так что да, его можно использовать локально для доступа к файлам под разными учетными данными. Он не может получить доступ к файлам на другом компьютере, к которым не был предоставлен общий доступ. - person Wolf5; 22.06.2015
comment
Как только я получил доступ к файлам, используя приведенный выше код. После этого, как я отключу доступ к общей папке? . Потому что во время доступа к общей папке в Window он будет хранить идентификатор пользователя и пароль в кеше. Так есть ли необходимость удалять этот кеш? - person Karthick Rajan; 22.09.2016
comment
Мне неизвестен какой-либо механизм кеширования с этим методом. Я бы предположил, что кеширования не происходит. Кэширование происходит, когда вы получаете всплывающее окно в окнах и вводите учетные данные и проверяете Запомнить мои учетные данные. Просто протестируйте запуск кода и проверьте диспетчер учетных данных, чтобы увидеть, были ли добавлены какие-либо новые записи. - person Wolf5; 22.09.2016
comment
вы можете указать действительный путь к файлу на удаленной машине? имя моей машины - Server, и мне нужно получить доступ к диску D на нем, при попытке я получаю сообщение об ошибке: var files = System.IO.Directory.GetFiles (\\ Server \\ D :); - person Yahya Hussein; 21.12.2016
comment
ммммм. Это недопустимый сетевой путь. Откройте общий доступ к папке или диску на сервере, откройте его через проводник, скопируйте путь и используйте его в своей программе. Например, \\ server \ myshare или \\ server \ d (ЕСЛИ u использовал d: disk как d) - person Wolf5; 23.12.2016
comment
Когда я получаю доступ к общему каталогу удаленного компьютера, возникает ошибка Устройство не готово - person Rizwan Ali Sabir; 21.07.2017