2

後で不確定な時間にユーザーに代わってコマンドをキューに入れて実行するWCFサービスがあります。私は、WindowsIdentityをバイト配列として格納し、それをデータベースに詰め込んでから、後でそのオブジェクトを逆シリアル化して使用することを望んでいました。

場合によっては、サービスは期待どおりに実行されます。つまり、ユーザーとしてコマンドを正しくシリアル化、保存、逆シリアル化、および実行します。また、WindowsIdentityを逆シリアル化すると、「呼び出しのターゲットによって例外がスローされました」というエラーが発生します。また、逆シリアル化は機能しますが、コマンド実行の途中で、IDが無効になる場合もあります。

私の質問はこれです:WCFを使用する.NET 4.0フレームワークで、明示的なユーザー名とパスワードなしで、後でユーザーに代わってコマンドを実行することは可能ですか?

私が使用しているコードは以下のとおりです。

シリアル化:

''' <summary>
''' Serializes a WindowsIdentity as a binary encoded byte array.
''' </summary>
''' <param name="identity">The identity to serialize.</param>
''' <returns>A byte array containing a binary representation of the identity.</returns>
Private Function SerializeWindowsIdentity(ByVal identity As WindowsIdentity) As Byte()
    If IsNothing(identity) Then Return Nothing
    Try
        Dim bf As New BinaryFormatter
        Using ms As New MemoryStream()
            bf.Serialize(ms, identity)
            Return ms.ToArray()
        End Using
    Catch ex As Exception
        Return Nothing
    End Try
End Function ' SerializeWindowsIdentity

デシリアライズ:

''' <summary>
''' Deserializes a WindowsIdentity from a binary encoded byte array.
''' </summary>
''' <param name="identity">A byte array containing a binary representation of a WindowsIdentity</param>
''' <returns>The deserialized WindowsIdentity from the byte array.</returns>
Private Function DeserializeWindowsIdentity(ByVal identity As Byte()) As WindowsIdentity
    If IsNothing(identity) OrElse identity.Count = 0 Then Return Nothing
    Try
        Dim bf As New BinaryFormatter()
        Using ms As New MemoryStream(identity)
            Dim obj As Object = bf.Deserialize(ms)
            Return CType(obj, WindowsIdentity)
        End Using
    Catch ex As Exception
        Return Nothing
    End Try
End Function ' DeserializeWindowsIdentity

WindowsIdentityキャプチャ:

identity = SerializeWindowsIdentity(ServiceSecurityContext.Current.WindowsIdentity)

使用法:

Dim cxt As WindowsImpersonationContext
Try
    Dim wi As WindowsIdentity = DeserializeWindowsIdentity(identity)
    If Not IsNothing(wi) Then cxt = wi.Impersonate()

    ' Do Stuff
Finally
    If Not IsNothing(cxt) Then cxt.Dispose()
End If
4

2 に答える 2

0

ここにいくつかの疑似コードがあります:

    //When command comes in from the user, queue the work
    private void QueueWork()
    {
        //Authorization Check
        if (IsAuthorized(DoWork, ServiceSecurityContext.Current.WindowsIdentity))
            throw new SecurityAccessDeniedException("Unauthorized");

        //Queue the work for later
        Queue.Enqueue(ServiceSecurityContext.Current.WindowsIdentity.Name);
    }

    //check if 
    private bool IsAuthorized(Action doWork, WindowsIdentity windowsIdentity)
    {
        //custom logic
    }

    //Command executed at a later point in time
    private void DoWork()
    {
        var user = Queue.Dequeue() as string;

        Log(user + " is invoking DoWork");

        //Perform command on behalf of user
        //...
    }

WindowsIdentity を取得するために Windows 認証が有効になっていることを前提としています。

また、コマンドをどのようにキューに入れているのか、後でどのように実行しているのかわかりません。

必要に応じて、IsAuthorized メソッドを他の認証方法に置き換えることができます。

サービスには操作を実行する権限があり、実行中のユーザーとコマンドを単にログに記録します。

これがあなたのシナリオに完全に適合しない場合は、私に知らせて詳細情報を提供してください。回答を変更できます. しかし、これがあなたを正しい方向に導くことを願っています

于 2013-03-07T22:58:41.837 に答える
0

したがって、これまでの最善の解決策は、 からのトークンを使用して、ServiceSecurityContext.Current.WindowsIdentityシリアル化して後で保存する新しいプライマリ トークンを作成することです。欠点は、サービスが再起動されるとトークンが無効になることですが、ユーザーからの永続的な承認を必要としないようにサービスを修正できるようになるまでの一時的な回避策としては問題ありません。S4U2Proxyの使用を検討しましたやりたいことはできますが、サービスを実行するドメイン アカウントを構成するための要件は、ユーザーにとって少し面倒です。動作するコード スニペットを以下に示します (注: おそらくこれ以上シリアル化する必要はありませんが、データベース スキーマを更新する必要がないため、維持するのが簡単でした。また、シリアル化ルーチンをコードをより管理しやすくするためのトークンの複製):

コードを逆シリアル化します。

''' <summary>
''' Deserializes a user token from a binary encoded byte array.
''' </summary>
''' <param name="identity">A byte array containing an binary representation of a user token.</param>
''' <returns>The deserialized user token from the byte array.</returns>
Private Function DeserializeWindowsIdentityToken(ByVal identity As Byte()) As IntPtr
    If IsNothing(identity) Then Return Nothing
    Dim stream As New MemoryStream(identity)
    Dim serializer As New BinaryFormatter()
    Try
        Dim obj As Object = serializer.Deserialize(stream)
        Return CType(obj, IntPtr)
    Catch ex As Exception
        Return IntPtr.Zero
    End Try
End Function ' DeserializeWindowsIdentityToken

コードのシリアル化:

''' <summary>
''' Serializes a user token as a binary encoded byte array.
''' </summary>
''' <param name="identity">The token to serialize.</param>
''' <returns>A byte array containing a binary representation of the token.</returns>
Private Function SerializeWindowsIdentityToken(ByVal identity As IntPtr) As Byte()
    Try
        Dim newToken As IntPtr = IntPtr.Zero
        Const securityDelegation As Int16 = 3
        Const tokenPrimary As Integer = 1
        Const maximumAllowed As Integer = &H2000000

        Dim sa As New SecurityAttributes()
        sa.bInheritHandle = True
        sa.Length = Marshal.SizeOf(sa)
        sa.lpSecurityDescriptor = IntPtr.Zero

        If DuplicateTokenEx(identity, maximumAllowed, sa, securityDelegation, tokenPrimary, newToken) = 0 Then Return Nothing

        Dim streamWriter As New MemoryStream()
        Dim serializer As New BinaryFormatter
        serializer.Serialize(streamWriter, newToken)
        Return streamWriter.ToArray()
    Catch ex As Exception
        Return Nothing
    End Try
End Function ' SerializeWindowsIdentityToken

<StructLayout(LayoutKind.Sequential)>
Private Structure SecurityAttributes
    Public Length As Integer
    Public lpSecurityDescriptor As IntPtr
    Public bInheritHandle As Boolean
End Structure ' SecurityAttributes

<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function DuplicateTokenEx(ByVal existingTokenHandle As IntPtr,
                                         ByVal desiredAccess As UInteger,
                                         ByRef threadAttributes As SecurityAttributes,
                                         ByVal impersonationLevel As Integer,
                                         ByVal tokenType As Integer,
                                         ByRef duplicateTokenHandle As IntPtr) As Integer
End Function ' DuplicateTokenEx

トークンのキャプチャ:

Dim storedToken As Byte() = SerializeWindowsIdentityToken(ServiceSecurityContext.Current.WindowsIdentity.Token)

使用法:

Dim identity As IntPtr = DeserializeWindowsIdentityToken(storedToken)
Dim cxt As WindowsImpersonationContext = Nothing
If Not IsNothing(identity) AndAlso identity <> IntPtr.Zero Then
    Try
        Dim identity As New WindowsIdentity(identity)
        cxt = identity.Impersonate()
    Catch ex As Exception
        ' Perform error handling
    End Try
End If

' Perform operations

If Not IsNothing(cxt) Then cxt.Dispose()
于 2013-03-13T15:27:37.743 に答える