问题描述
我有一个是排队,并在稍后,时间不定,代表用户执行命令WCF服务。我希望存储的WindowsIdentity作为一个字节数组,东西到数据库中,然后再反序列化,并使用该对象。
有些时候,服务执行预期:它正确序列化,存储,反序列化,并执行命令的用户。其他时候,我得到一个错误异常被抛出调用的目标反序列化时的WindowsIdentity,还有一些次反序列化的作品,但一部分通过命令的执行方式,身份不再有效。
我的问题是:是否有可能在.NET 4.0框架使用WCF来代表用户在稍后,时间不定,没有明确的用户名和密码,执行命令
?这是我使用的code是如下:
连载:
'''<总结>
'''序列化一的WindowsIdentity为二进制EN codeD字节数组。
'''< /总结>
'''< PARAM NAME =身份>在身份序列化和LT; /参数>
'''<返回>将含有身份的二元再presentation的字节数组< /回报>
专用功能SerializeWindowsIdentity(BYVAL身份作为的WindowsIdentity)为字节()
如果IsNothing(身份),然后返回没什么
尝试
昏暗的BF作为新的BinaryFormatter
使用MS作为新的MemoryStream()
bf.Serialize(MS,身份)
返回ms.ToArray()
结束使用
抓住EX为例外
返回任何结果
结束尝试
端功能SerializeWindowsIdentity
反序列化:
'''<总结>
'''反序列化从二进制连接codeD字节数组中的WindowsIdentity。
'''< /总结>
'''< PARAM NAME =身份与GT;含有的WindowsIdentity℃的二重presentation的字节数组; /参数>
'''<返回>从字节数组反序列化的WindowsIdentity< /回报>
专用功能DeserializeWindowsIdentity(BYVAL身份为字节())作为的WindowsIdentity
如果IsNothing(身份)OrElse运算identity.Count = 0,然后返回没什么
尝试
昏暗bf的新的BinaryFormatter()
使用MS作为新的MemoryStream(身份)
昏暗的OBJ作为对象= bf.Deserialize(MS)
返回CTYPE(OBJ,的WindowsIdentity)
结束使用
抓住EX为例外
返回任何结果
结束尝试
端功能DeserializeWindowsIdentity
的WindowsIdentity捕获:
标识= SerializeWindowsIdentity(ServiceSecurityContext.Current.WindowsIdentity)
用法:
昏暗CXT作为WindowsImpersonationContext
尝试
昏暗的无线网络作为的WindowsIdentity = DeserializeWindowsIdentity(身份)
如果不IsNothing(无线)然后CXT = wi.Impersonate()
做的东西
最后
如果不IsNothing(CXT)然后cxt.Dispose()
结束如果
所以,我们至今最好的解决办法是使用令牌从 ServiceSecurityContext.Current.WindowsIdentity
并创造出我们序列化一个新的主令牌和存储供以后使用。不足之处是,该令牌是无效的,一旦重新启动该服务,但它是个不错的临时解决,直到我们可以修改我们的服务,使我们不需要从用户的永久授权。我们着眼于使用 S4U2Proxy 其中的将会的做我们想要的,但在配置域帐户要求的服务运行的是一个有点沉重的为我们的用户。工作code段低于(注:我们可能并不需要序列化更多,但它更容易保持的地方,因为我们还没有更新我们的数据库模式的同时,我们可以打出来的从令牌重复序列化程序使code更容易管理):
反序列化code:
'''<总结>
'''反序列化从二进制连接codeD字节数组用户令牌。
'''< /总结>
'''< PARAM NAME =身份与gt;将含有用户令牌的二元再presentation的字节数组< /参数>
'''<返回>从字节数组反序列化的用户令牌LT; /回报>
专用功能DeserializeWindowsIdentityToken(BYVAL身份为字节())作为IntPtr的
如果IsNothing(身份),然后返回没什么
昏暗的流作为新的MemoryStream(身份)
昏暗的序列化作为新的BinaryFormatter()
尝试
昏暗的OBJ作为对象= serializer.Deserialize(流)
返回CTYPE(OBJ,IntPtr的)
抓住EX为例外
返回IntPtr.Zero
结束尝试
端功能DeserializeWindowsIdentityToken
序列化code:
'''<总结>
'''序列化用户令牌作为二进制EN codeD字节数组。
'''< /总结>
'''< PARAM NAME =身份>该令牌序列化和LT; /参数>
'''<返回>将含有标记的二进制重新presentation的字节数组< /回报>
专用功能SerializeWindowsIdentityToken(BYVAL身份作为IntPtr的)为字节()
尝试
昏暗newToken作为IntPtr的= IntPtr.Zero
常量securityDelegation作为的Int16 = 3
常量tokenPrimary作为整数= 1
常量maximumAllowed作为整数=安培; H2000000
昏暗SA作为新SecurityAttributes()
sa.bInheritHandle = TRUE
sa.Length = Marshal.SizeOf(SA)
sa.lpSecurityDescriptor = IntPtr.Zero
如果DuplicateTokenEx(身份证,maximumAllowed,SA,securityDelegation,tokenPrimary,newToken)= 0,然后返回没事
昏暗的StreamWriter作为新的MemoryStream()
昏暗的序列化作为新的BinaryFormatter
serializer.Serialize(StreamWriter的,newToken)
返回streamWriter.ToArray()
抓住EX为例外
返回任何结果
结束尝试
端功能SerializeWindowsIdentityToken
< StructLayout(LayoutKind.Sequential)>
PRIVATE STRUCTURE SecurityAttributes
公共长度整数
公共lpSecurityDescriptor作为IntPtr的
公共bInheritHandle由于布尔
末端结构SecurityAttributes
<的DllImport(advapi32.dll的,字符集:= CharSet.Auto,SetLastError:= TRUE)>
私人共享功能DuplicateTokenEx(BYVAL existingTokenHandle作为IntPtr的,
BYVAL desiredAccess作为UInteger,
为ByRef threadAttributes作为SecurityAttributes,
BYVAL impersonationLevel作为整数,
BYVAL tokenType作为整数,
为ByRef duplicateTokenHandle作为IntPtr的)作为整数
端功能DuplicateTokenEx
令牌捕获:
昏暗storedToken为字节()= SerializeWindowsIdentityToken(ServiceSecurityContext.Current.WindowsIdentity.Token)
用法:
昏暗的身份识别的IntPtr = DeserializeWindowsIdentityToken(storedToken)
昏暗的CXT作为WindowsImpersonationContext =无
如果不IsNothing(身份)AndAlso身份<> IntPtr.Zero然后
尝试
昏暗的身份作为新的WindowsIdentity(身份)
CXT = identity.Impersonate()
抓住EX为例外
执行错误处理
结束尝试
结束如果
执行操作
如果不IsNothing(CXT)然后cxt.Dispose()
I've a WCF service that queues and executes commands on behalf of the user at a later, indeterminate time. I was hoping to store the WindowsIdentity as a byte array and stuff it into a database, and then later deserialize and use that object.
Some of the time, the service performs as expected: it correctly serializes, stores, deserializes, and executes the command as the user. Other times, I get an error "Exception has been thrown by the target of an invocation" when deserializing the WindowsIdentity, and still other times the deserialization works but part way through the command execution, the identity is no longer valid.
My question is this: is it possible in the .NET 4.0 framework using WCF to execute a command on behalf of a user at a later, indeterminate time with no explicit username and password?
The code that I'm using is below:
Serialization:
''' <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
Deserialization:
''' <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 capture:
identity = SerializeWindowsIdentity(ServiceSecurityContext.Current.WindowsIdentity)
Usage:
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
So, the best solution we have so far is to use the token from the ServiceSecurityContext.Current.WindowsIdentity
and create a new primary token that we serialize and store for later. The downside is that the token is invalid once the service is restarted, but it's a fine temporary work-around until we can revise our service so that we don't require a persistent authorization from the user. We looked at using S4U2Proxy which would do what we want, but the requirement for configuring the domain account the service runs under is a bit onerous for our users. The working code snippet is below (note: we probably don't need to serialize any more, but it was easier to keep in place since we don't have to update our database schema. Also, we could break out the serialize routine from the token duplication to make the code more manageable):
Deserialize code:
''' <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
Serialize code:
''' <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
Token capture:
Dim storedToken As Byte() = SerializeWindowsIdentityToken(ServiceSecurityContext.Current.WindowsIdentity.Token)
Usage:
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()
这篇关于如何存储的WindowsIdentity供以后使用,时间不定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!