Как я могу использовать олицетворение для манипулирования файлами / каталогами на удаленном компьютере с помощью UNC? - PullRequest
7 голосов
/ 02 октября 2019

Мне нужно загрузить файлы с сервера в каталог общего диска, создав каталог, если он не существует. Есть несколько вещей, которые усложняют это:

  1. У меня нет доступа на запись (равно как и учетной записи, которая будет выполнять задание в UAT / Prod) в каталог общего диска.
  2. Учетная запись службы, у которой есть доступ для записи, не имеет никаких привилегий, кроме каталога общего диска.

Я пытаюсь выдать себя за другого:

class Impersonation
{
    const int LOGON32_LOGON_NETWORK = 3;
    const int LOGON_TYPE_NEW_CREDENTIALS = 9;
    const int LOGON32_PROVIDER_WINNT50 = 3;

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    public static void Impersonate(string domain, string user, string password, Action act)
    {
        //if no user specified, don't impersonate
        if (user.Trim() == "")
        {
            act();
            return;
        }
        WindowsImpersonationContext impersonationContext = null;
        IntPtr token = IntPtr.Zero;
        try
        {
            //if no domain specified, default it to current machine
            if (domain.Trim() == "")
            {
                domain = System.Environment.MachineName;
            }
            bool result = LogonUser(user, domain, password, LOGON_TYPE_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, ref token);
            WindowsIdentity wi = new WindowsIdentity(token);
            impersonationContext = WindowsIdentity.Impersonate(token);
            act();
        }
        catch (Exception ex)
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
                impersonationContext = null;
            }
            //if something went wrong, try it as the running user just in case
            act();
        }
        finally
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
                impersonationContext = null;
            }
            if (token != IntPtr.Zero)
            {
                CloseHandle(token);
                token = IntPtr.Zero;
            }
        }
    }
}

ИЧасть действительного кода вызова (в другом классе):

private static void CreateDirectoryIfNotExist(string directory, string domain, string username, string password)
{
    Impersonation.Impersonate(domain, username, password, () => CreateIfNotExist(directory));
}

private static void CreateIfNotExist(string dir)
{
    if (!Directory.Exists(dir))
    {
        Directory.CreateDirectory(dir);
    }
}

Если я запустил его с правильной регистрационной информацией для учетной записи службы, я получу исключение при вызове Directory.CreateDirectory (string):

{System.IO.IOException: этому пользователю не разрешено входить на этот компьютер.}

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

Ответы [ 2 ]

0 голосов
/ 24 октября 2019

Вы можете решить эту проблему, как я решил. Ниже приведены шаги:

Шаг 1: Откройте IIS. Затем добавьте виртуальный каталог в ваше веб-приложение.

enter image description here

Шаг 2: Затем сопоставьте свой общий путь с виртуальным каталогом, добавленным на шаге 1

enter image description here

Шаг 3: Теперь нажмите «Подключиться как ...»

enter image description here

Шаг4: Установите учетные данные нужного пользователя, с помощью которого вы хотите подключить ваш общий путь.

enter image description here

Шаг 5. Теперь часть конфигурации IIS завершенаи вам нужно начать использовать src = "Image / Image.png" в вашем html или начать манипулировать "SharedFolder / YourFile.ext".

0 голосов
/ 18 октября 2019

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

Вы можете использовать функцию WNetAddConnection2 , которая используется для установления соединения с сетевым ресурсом.

Вот пример дляваша CreateDirectoryIfNotExist функция, использующая этот подход:

public static void CreateDirectoryIfNotExists(string directory, string sharePath, string username, string password)
{
   NETRESOURCE nr = new NETRESOURCE();
   nr.dwType = ResourceType.RESOURCETYPE_DISK;
   nr.lpLocalName = null;
   nr.lpRemoteName = sharePath;
   nr.lpProvider = null;

   int result = WNetAddConnection2(nr, password, username, 0);
   string directoryFullPath = Path.Combine(sharePath, directory);
   if (!Directory.Exists(directoryFullPath))
   {
      Directory.CreateDirectory(directoryFullPath);
   }
}

Чтобы сделать системный вызов, вам также понадобятся следующие определения из pinvoke.net .

[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
   public ResourceScope dwScope = 0;
   public ResourceType dwType = 0;
   public ResourceDisplayType dwDisplayType = 0;
   public ResourceUsage dwUsage = 0;
   [MarshalAs(UnmanagedType.LPStr)] public string lpLocalName = null;
   [MarshalAs(UnmanagedType.LPStr)] public string lpRemoteName = null;
   [MarshalAs(UnmanagedType.LPStr)] public string lpComment = null;
   [MarshalAs(UnmanagedType.LPStr)] public string lpProvider;
};
public enum ResourceScope
{
   RESOURCE_CONNECTED = 1,
   RESOURCE_GLOBALNET,
   RESOURCE_REMEMBERED,
   RESOURCE_RECENT,
   RESOURCE_CONTEXT
};

public enum ResourceType
{
   RESOURCETYPE_ANY,
   RESOURCETYPE_DISK,
   RESOURCETYPE_PRINT,
   RESOURCETYPE_RESERVED
};

public enum ResourceUsage
{
   RESOURCEUSAGE_CONNECTABLE = 0x00000001,
   RESOURCEUSAGE_CONTAINER = 0x00000002,
   RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
   RESOURCEUSAGE_SIBLING = 0x00000008,
   RESOURCEUSAGE_ATTACHED = 0x00000010,
   RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
};

public enum ResourceDisplayType
{
   RESOURCEDISPLAYTYPE_GENERIC,
   RESOURCEDISPLAYTYPE_DOMAIN,
   RESOURCEDISPLAYTYPE_SERVER,
   RESOURCEDISPLAYTYPE_SHARE,
   RESOURCEDISPLAYTYPE_FILE,
   RESOURCEDISPLAYTYPE_GROUP,
   RESOURCEDISPLAYTYPE_NETWORK,
   RESOURCEDISPLAYTYPE_ROOT,
   RESOURCEDISPLAYTYPE_SHAREADMIN,
   RESOURCEDISPLAYTYPE_DIRECTORY,
   RESOURCEDISPLAYTYPE_TREE,
   RESOURCEDISPLAYTYPE_NDSCONTAINER
};
public enum ResourceConnection
{
   CONNECT_UPDATE_PROFILE = 1,
   CONNECT_UPDATE_RECENT = 2,
   CONNECT_TEMPORARY = 4,
   CONNECT_INTERACTIVE = 8,
   CONNECT_PROMPT = 0X10,
   CONNECT_REDIRECT = 0X80,
   CONNECT_CURRENT_MEDIA = 0X200,
   CONNECT_COMMAND_LINE = 0X800,
   CONNECT_CMD_SAVECRED = 0X1000,
   CONNECT_CRED_RESET = 0X2000

};

[DllImport("mpr.dll", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
private static extern int WNetAddConnection2(NETRESOURCE lpNetResource,
      [MarshalAs(UnmanagedType.LPStr)]  string lpPassword,
      [MarshalAs(UnmanagedType.LPStr)]  string lpUserName, int dwFlags);

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

Здесь также приведены ссылки на два старых поста, в которых также используется тот же подход.

Доступ к общему файлу (UNC) из удаленного ненадежного домена с учетными данными

Как получить программный доступ к общей папке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...