我们有一些遗留的Web应用程序代码,我们正在更新并移植到.NET 4.0运行时。
代码位于类库中,并使用WCF连接到命名管道端点。
当我从控制台应用程序启动连接时,一切正常。
当我从Web应用程序启动连接时,我收到一个例外:
Access is denied
Server stack trace:
at System.ServiceModel.Channels.AppContainerInfo.GetCurrentProcessToken()
at System.ServiceModel.Channels.AppContainerInfo.RunningInAppContainer()
at System.ServiceModel.Channels.AppContainerInfo.get_IsRunningInAppContainer()
at System.ServiceModel.Channels.PipeSharedMemory.BuildPipeName(String pipeGuid)
at System.ServiceModel.Channels.PipeSharedMemory.get_PipeName()
at System.ServiceModel.Channels.PipeConnectionInitiator.GetPipeName(Uri uri, IPipeTransportFact… Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
错误源自托管代码和非托管代码之间的边界,其中存在对advapi32.dll
的调用:
[SecurityCritical]
private static SafeCloseHandle GetCurrentProcessToken()
{
SafeCloseHandle TokenHandle = (SafeCloseHandle) null;
if (!UnsafeNativeMethods.OpenProcessToken(UnsafeNativeMethods.GetCurrentProcess(), TokenAccessLevels.Query, out TokenHandle))
throw System.ServiceModel.FxTrace.Exception.AsError((Exception) new Win32Exception(Marshal.GetLastWin32Error()));
return TokenHandle;
}
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr ProcessHandle, TokenAccessLevels DesiredAccess, out SafeCloseHandle TokenHandle);
网络上的各种主题建议删除元素或设置impersonate="false"
:
<system.web>
<identity impersonate="true"/>
</system.web>
事实上,这可以解决我的问题。但是,我不确定这可能会对应用程序产生什么副作用(SharePoint 2016),因此我不愿意简单地删除此属性。
SecurityCritical
属性给了我一些提示,或许这与.NET 2.0和.NET 4.0之间的CAS模型的变化有关。代码安装在GAC中,因此它应该在完全信任的情况下运行,但我还是试了一下。
我还尝试将[SecuritySafeCritical]
添加到方法中,并且调用IChannel.Open()
的类无效。
我还尝试在程序集上添加[assembly: SecurityRules(SecurityRuleSet.Level1)]
,因为这应该会锁定到.NET Framework 2.0安全规则中。
我正在寻找任何其他见解和其他方法来尝试解决此问题。
与其他Stack帖子有一些相似之处:How to call net.pipe (named pipe) WCF services while impersonating in a Windows Service除了没有明确的冒充发生,所以我不确定修复是否适用。
另外需要注意的是,当我尝试调用System.Diagnostics.Process.GetCurrentProcess()
时,会抛出相同的错误。当尝试获取当前执行过程的句柄时,错误也会产生。
答案 0 :(得分:0)
我得出的结论是,这个问题与.NET 4.0中System.ServiceModel
的内部结构有关。
最初,我认为这可能与Server 2016 UAC或.NET 4.0 / IIS 10 Web应用程序运行时设置(例如.NET 2.0 vs .NET 4.0 CAS模型)有关。我在.NET 3.5中创建了一个简单的Web应用程序,并尝试调用Process.GetCurrentProcess().Handle
。我在新服务器上运行了它,并且它失败并且#34;访问被拒绝&#34;错误。
我把它带到旧服务器(Windows Server 2008 R2,.NET 3.5)并在那里运行它,希望这可以工作,而且看起来也很失败。所以我在3.5中浏览了System.ServiceModel
的源代码,发现没有AppContainerInfo
因此很可能3.5代码根本没有进行相同的Win32 API级别调用。
我的结论是我们之前没有遇到此错误,因为旧的3.0库不需要从advapi32.dll
调用API或者有其他机制来创建管道名称。
确实,这是3.0 {&#34;中PipeConnectionInitiator.GetPipeName
的实施的前几行:
internal static string GetPipeName(Uri uri)
{
string[] strArray = new string[3]
{
"+",
uri.Host,
"*"
};
bool[] flagArray = new bool[2]{ true, false };
for (int index1 = 0; index1 < strArray.Length; ++index1)
{
for (int index2 = 0; index2 < flagArray.Length; ++index2)
{
以下是4.0中的前几行:
internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
{
AppContainerInfo appContainerInfo = PipeConnectionInitiator.GetAppContainerInfo(transportFactorySettings);
string[] strArray = new string[3]
{
"+",
uri.Host,
"*"
};
bool[] flagArray = new bool[2]{ true, false };
string str1 = string.Empty;
string str2 = (string) null;
for (int index1 = 0; index1 < strArray.Length; ++index1)
{
for (int index2 = 0; index2 < flagArray.Length; ++index2)
{
if (appContainerInfo == null || !flagArray[index2])
因此4.0实现需要访问执行OpenProcessToken
。
如果代码足够孤立,一个选项是使用程序集绑定重定向:
<runtime>
<assemblyBinding>
<dependentAssembly>
<assemblyIdentity name="System.ServiceProcess" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="4.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
只需强制运行时绑定到旧版本。
不幸的是,该应用程序对System.ServiceModel
4.0有一些依赖性,所以切换它并不是那么简单。