SqlFileStream Win32Exception: Доступ запрещен Олицетворение

Моя цель здесь — получить диспетчер вложений, который (1) эффективно использует SQL FILESTREAM в том виде, в котором он был разработан, (2) ограничивает доступ к SQL FileTable и его базовому каталогу FILESTREAM Windows одной из двух учетных записей Active Directory (учетные данные предоставляются файлом web/app.config), и (3) эффективно игнорирует текущего пользователя Windows Auth для любого сайта или приложения, в которое включена эта библиотека.

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

У меня есть:

  1. Активирована встроенная защита в моей строке подключения: "Server={server};Database=AttachmentsGlobal;User ID={domain}\\{user};Password={password};Trusted_Connection=False;Integrated Security=true;"
  2. Учитывая тот же самый пользовательский доступ RW к каталогу FileTable на Windows Server 2012, где работает SQL Server 2012, путем изменения разрешений для папки.
  3. Предоставление пользователю прав на выбор, изменение, обновление, вставку и удаление файловой таблицы и столбца filestream.
  4. Реализован пользовательский класс олицетворения, который я нашел в Интернете, чтобы олицетворять того же пользователя при вызове объекта SqlFileStream (см. ниже).
  5. Пытался найти ошибки на стороне SQL Server. Все, что я могу найти в средстве просмотра событий, это то, что олицетворение, которое я пытаюсь выполнить ниже, успешно регистрирует пользователя.
  6. Убедитесь, что разрешение удаленных подключений включено в настройках FILESTREAM в SQL Server.

Он работает всякий раз, когда я отключаю блок using(Impersonator){} в SaveFile ниже, но в противном случае он не работает. Также кажется, что строка подключения игнорируется при локальной отладке: моя учетная запись пользователя имеет доступ к папке вложений, потому что я администратор, но когда я изменяю строку подключения на пользователя, который явно НЕ имеет доступа, он по-прежнему загружается нормально . Я предполагаю, что это параметр интегрированной безопасности, который передает учетные данные текущего пользователя приложения на сервер и игнорирует предоставленного пользователя. Я не уверен, как это хорошо проверить, если не считать запуска Visual Studio от имени другого пользователя (что я пробовал, и это не удалось).

Пожалуйста, скажите мне, что я делаю что-то глупое и глупое, и что я достаточно близок к решению. Эта невероятно расплывчатая ошибка отказа в доступе сводит меня с ума! Спасибо.

C#:

// SqlFileItem is just a simple model mapping all the columns of the file 
// table (except the filestream itself)
public SqlFileItem UploadFile(Stream fileStream, string fileName,
    SqlFileItem parent, AttachmentType restricted) {
    const string uploadSproc = "InsertAttachment";
    const string metadataSproc = "GetMetadata";
    SqlFileItem rt;
    using (TransactionScope ts = new TransactionScope()) {
        using (SqlConnection conn = GetConnection(restricted)) {
            conn.Open();
            string serverPath;
            byte[] serverXfer;
            Guid streamIdOfUploadedFile;
            using (SqlCommand cmd = conn.CreateCommand()) {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandText = uploadSproc;
                cmd.Parameters.Add("@fName", SqlDbType.VarChar).Value =
                    fileName;
                cmd.Parameters.Add("@parent", SqlDbType.VarChar).Value =
                    parent.path_locator.ToString();
                using (SqlDataReader rdr = cmd.ExecuteReader()) {
                    rdr.Read();
                    serverPath = rdr.GetSqlString(0).Value;
                    serverXfer = rdr.GetSqlBinary(1).Value;
                    streamIdOfUploadedFile = rdr.GetGuid(2);
                    rdr.Close();
                }
            }
            // See below for SaveFile
            SaveFile(fileStream, serverPath, serverXfer, exportRestriction);
            using (SqlCommand cmd = conn.CreateCommand()) {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandText = metadataSproc;
                cmd.Parameters.Add("@streamId",
                    SqlDbType.UniqueIdentifier).Value =
                    streamIdOfUploadedFile;
                using (SqlDataReader rdr = cmd.ExecuteReader()) {
                    rt =
                        DataReaderToList<SqlFileItem>(rdr)
                            .FirstOrDefault();
                }
            }
        }
        ts.Complete();
    }
    return rt;
}

// Performs the actual streaming/saving operation.
private static void SaveFile(Stream src, string serverPath,
    byte[] serverXfer, AttachmentType restricted) {
    const int blockSize = 1024*512;
    // My attempt at impersonating
    Impersonator imp = restricted == AttachmentType.Open
        ? new Impersonator(@"{openActiveDirectoryUser}", @"{domain}", 
            @"{password}")
        : new Impersonator(@"{restrictedActiveDirectoryUser}", @"{domain}",
            @"{password}");

    using (imp) {
        using (src) {
            using (
                // The line below is where it breaks with a Win32Exception.
                // The full text of it from VS2015 is provided below.
                SqlFileStream dest = new SqlFileStream(serverPath,
                    serverXfer, FileAccess.Write)) {
                byte[] buffer = new byte[blockSize];
                int bytesRead;
                while ((bytesRead = src.Read(buffer, 0, buffer.Length)) >
                       0) {
                    dest.Write(buffer, 0, bytesRead);
                    dest.Flush();
                }
                dest.Close();
            }
            src.Close();
        }
    }
}

Класс подражателя найден здесь

SQL:

ALTER PROCEDURE [dbo].[InsertAttachment] 
    @fileName varchar(255),
    @parent hierarchyid
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @returns TABLE (stream_id UNIQUEIDENTIFIER)
    INSERT INTO Attachments(file_stream, name, is_directory, path_locator)
    OUTPUT inserted.stream_id INTO @returns
    VALUES (0x, @fileName, 0, dbo.GetCustomPathLocator(@parent.ToString()))

    SELECT file_stream.PathName()
        ,GET_FILESTREAM_TRANSACTION_CONTEXT()
        ,aft.stream_id
    FROM Attachments att
    INNER JOIN @returns rt on att.stream_id = rt.stream_id
END

ALTER PROCEDURE [dbo].[GetMetadata]
    @streamId uniqueidentifier
AS
BEGIN
    SELECT stream_id
        -- omit file_stream varbinary(max)
        ,name
        ,path_locator
        ,parent_path_locator
        ,file_type
        ,cached_file_size
        ,creation_time
        ,last_write_time
        ,last_access_time
        ,is_directory 
        -- omit remaining is_* flags
    FROM Attachments
    WHERE stream_id = @streamId
END

Исключение:

System.ComponentModel.Win32Exception was unhandled
  ErrorCode=-2147467259
  HResult=-2147467259
  Message=Access is denied
  NativeErrorCode=5
  Source=System.Data
  StackTrace:
       at System.Data.SqlTypes.SqlFileStream.OpenSqlFileStream(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
       at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
       at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access)
       at FileTableAttachmentLibrary.AttachmentManager.SaveFile(Stream src, String serverPath, Byte[] serverXfer, AttachmentScope exportRestricted) in C:\_projects\FileTableAttachmentLibrary\FileTableAttachmentLibrary\FileTableAttachmentLibrary\AttachmentManager.cs:line 498
       at FileTableAttachmentLibrary.AttachmentManager.UploadFile(Stream fileStream, String fileName, SqlFileItem parent, AttachmentScope exportRestriction) in C:\_projects\FileTableAttachmentLibrary\FileTableAttachmentLibrary\FileTableAttachmentLibrary\AttachmentManager.cs:line 210
       at TestAttachments.Program.AttachmentManagerTest() in C:\_projects\FileTableAttachmentLibrary\FileTableAttachmentLibrary\TestAttachments\Program.cs:line 69
       at TestAttachments.Program.Main(String[] args) in C:\_projects\FileTableAttachmentLibrary\FileTableAttachmentLibrary\TestAttachments\Program.cs:line 26
  InnerException: null

person J.D. Mallen    schedule 14.12.2015    source источник
comment
Во-первых, какая строка вызывает ошибку? Есть ли внутреннее исключение? Во-вторых, когда это происходит удаленно, пробовали ли вы регистрировать какие-либо ошибки или другую полезную информацию? Если да, то что вы узнали из этого? В-третьих, этот вопрос довольно сложно читать и понимать, потому что вы начинаете рассказывать нам, что вы сделали для решения проблемы, прежде чем описать, чего вы пытаетесь достичь и в чем проблема. Вы можете отредактировать его, чтобы его было легче понять. (Помните, что никто из нас ничего не знает о вашей проблеме, кроме того, что вы записываете.)   -  person Becuzz    schedule 14.12.2015
comment
Спасибо за ваш ответ. Я отредактирую вопрос.   -  person J.D. Mallen    schedule 14.12.2015
comment
Вы предоставили своей пользовательской ОС доступ к файлам? Имеет ли пользователь вашего приложения/удостоверение пула приложений IIS доступ к этому каталогу?   -  person Becuzz    schedule 14.12.2015
comment
Да; см. № 2 выше. Пользователь приложения успешно олицетворяется в приведенном выше коде (на основе событий, запущенных на сервере), но я все еще получаю исключение, несмотря на то, что у этого пользователя есть разрешения на каталог файловой группы.   -  person J.D. Mallen    schedule 15.12.2015
comment
Является пользовательской частью «Действовать как часть операционной системы», то есть пользователем, который запускает IIS WebPool. imgur.com/TLxJaxE Чтобы туда попасть: Пуск › Выполнить › secpol.msc   -  person Snake    schedule 15.12.2015
comment
Спасибо за предложение. После добавления этих двух пользователей, к сожалению, он все еще говорит, что доступ запрещен.   -  person J.D. Mallen    schedule 16.12.2015