Доступ запрещен при использовании WindowsIdentity.RunImpersonated для операций с файлами

Вопрос или проблема

Я пытаюсь выполнить операции с файлами (загрузка, скачивание, удаление) в файловой системе пользователя, используя подделку учетной записи в C#. После исследований я наткнулся на метод WindowsIdentity.RunImpersonated, который использую для делегирования полномочий для операций с файлами.

Однако я сталкиваюсь с ошибкой «Доступ запрещен». Ниже приведен соответствующий код, который я реализовал:

public class ImpersonationManager
{
    private SafeAccessTokenHandle _safeAccessTokenHandle;

    private readonly string _domainName;
    private readonly string _userName;
    private readonly string _password;

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
   int dwLogonType, int dwLogonProvider, out SafeAccessTokenHandle phToken);

    public ImpersonationManager(string domainName, string userName, string password)
    {
        _domainName = domainName;
        _userName = userName;   
        _password = password;
    }   

    public SafeAccessTokenHandle GetSafeAccessTokenHandle()
    {

        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;
        try
        {
            bool returnValue = LogonUser(_userName, _domainName, _password,
                               LOGON32_PROVIDER_DEFAULT, LOGON32_LOGON_INTERACTIVE,
                               out _safeAccessTokenHandle);

            if (!returnValue)
            {
                int ret = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(ret, $"LogonUser не удался с кодом ошибки : {ret}");
            }
        }
        catch (Exception ex)
        {
            throw;            
        }    

        return _safeAccessTokenHandle;
    }

}
public async Task<bool> UploadFileAsync(string filePath = null, File file = null, Stream fileStream = null)
{
    if (file == null)
        throw new ArgumentNullException(nameof(file));

    if (fileStream == null)
        throw new ArgumentNullException(nameof(fileStream));

    SafeAccessTokenHandle safeAccessTokenHandle = GetSafeAccessTokenHandleAsync();

    WindowsIdentity.RunImpersonated(safeAccessTokenHandle,() =>
    {
        var fileName = file.FileName;

        try
        {
            using (FileStream destinationStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                fileStream.CopyTo(destinationStream);
                return true;
            }

        }
        catch (Exception ex)
        {
            throw;
        }

    });

    return true;

}

Ответ или решение

Проблема "Access Denied" при использовании WindowsIdentity.RunImpersonated для операций с файлами

При использовании метода WindowsIdentity.RunImpersonated для выполнения операций с файлами от имени другого пользователя, ошибка "Access Denied" может возникать по нескольким причинам. Давайте разберем основные аспекты, на которые следует обратить внимание, и предложим подходы для устранения этой проблемы.

1. Проверьте права пользователя

Прежде всего, убедитесь, что пользователь, от имени которого вы выполняете операции, действительно имеет необходимые права для доступа к файлам или каталогам на файловой системе. Убедитесь, что:

  • Путь к файлу или каталогу доступен для этого пользователя.
  • У пользователя есть права на чтение, запись или удаление файлов, в зависимости от операции, которую вы выполняете.

2. Проверьте корректность логина

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

3. Использование правильного типа входа

В вашем коде используется LOGON32_LOGON_INTERACTIVE, который может не подойти для всех ситуаций. Возможно, вам понадобится использовать:

  • LOGON32_LOGON_NEW_CREDENTIALS для делегирования учетных данных.
  • LOGON32_LOGON_SERVICE, если вы обладаете необходимыми правами.

Измените часть кода, где происходит вызов LogonUser, на:

const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
// ...
bool returnValue = LogonUser(_userName, _domainName, _password,
                             LOGON32_PROVIDER_DEFAULT, LOGON32_LOGON_NEW_CREDENTIALS,
                             out _safeAccessTokenHandle);

4. Обработка SafeAccessTokenHandle

Убедитесь, что вы корректно обрабатываете объект SafeAccessTokenHandle. Необходимо убедиться в том, что он не равен null перед его использованием в RunImpersonated.

5. Синхронизация кода

Ваш метод UploadFileAsync содержит асинхронный код, но не использует async и await должным образом внутри RunImpersonated. Убедитесь, что ваш код может асинхронно обрабатывать ваши требования. Например, вы можете использовать Task.Run:

public async Task<bool> UploadFileAsync(string filePath = null, File file = null, Stream fileStream = null)
{
    if (file == null)
        throw new ArgumentNullException(nameof(file));

    if (fileStream == null)
        throw new ArgumentNullException(nameof(fileStream));

    SafeAccessTokenHandle safeAccessTokenHandle = GetSafeAccessTokenHandleAsync();

    bool result = await Task.Run(() => 
    {
        return WindowsIdentity.RunImpersonated(safeAccessTokenHandle, () =>
        {
            try
            {
                using (FileStream destinationStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    fileStream.CopyTo(destinationStream);
                }
                return true;
            }
            catch (Exception ex)
            {
                // Логирование ошибки для отладки
                Console.WriteLine(ex.Message);
                throw;
            }
        });
    });

    return result;
}

6. Логгирование ошибок

Для улучшения отладки добавьте в ваш код логирование ошибок, чтобы было легче выявлять, на каком этапе происходит сбой. Это поможет вам более точно определить, что именно вызывает ошибку "Access Denied".

Заключение

Следуя вышеуказанным шагам и рекомендациям, вы сможете диагностировать и устранить проблему "Access Denied" при использовании WindowsIdentity.RunImpersonated. Убедитесь, что ваши учетные данные, права и логика обработки кода соответствуют заданным требованиям. Если ошибка продолжает возникать, рассмотрите возможность гибкой настройки прав доступа на уровне файловой системы или обратитесь к системному администратору для дополнительной помощи.

Оцените материал
Добавить комментарий

Капча загружается...