2

ここでの私の目標は、(1)設計どおりにSQL FILESTREAMを効果的に使用し、(2) SQL FileTable とその基になる FILESTREAM Windows ディレクトリへのアクセスを 2 つの Active Directory アカウント (Web によって提供される資格情報) のいずれかに制限する、添付ファイル マネージャーを用意することです。 /app.config ファイル)、および (3) このライブラリが含まれるサイトまたはアプリの現在の Windows 認証ユーザーを効果的に無視します。

私はすでにこの問題に関する多くの投稿を見てきましたが、私が見つけたほとんどすべての提案を試してみましたが、まだほとんどまたはまったく成功していません.

私は持っている:

  1. 接続文字列で統合セキュリティを有効にしました:"Server={server};Database=AttachmentsGlobal;User ID={domain}\\{user};Password={password};Trusted_Connection=False;Integrated Security=true;"
  2. フォルダーのアクセス許可を変更することにより、SQL Server 2012 が実行されている Windows Server 2012 上の FileTable ディレクトリへの同じユーザー RW アクセスが与えられます。
  3. filestreamファイル テーブルと列に対する選択、変更、更新、挿入、および削除の権限をユーザーに付与します。
  4. オブジェクトを呼び出すときに同じユーザーを偽装するために、オンラインで見つけたカスタムの偽装クラスを実装しましたSqlFileStream(以下を参照)。
  5. SQL Server側でエラーを見つけようとしました。イベント ビューアーで確認できるのは、以下で試みたなりすましがユーザーのログオンに成功したことだけです。
  6. SQL Server の FILESTREAM 設定で「リモート接続を許可する」が有効になっていることを確認しました。

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
4

0 に答える 0