【发布时间】:2016-01-06 11:26:21
【问题描述】:
我在通过 net.pipe 从 C# Windows 服务使用 Windows 模拟调用 WCF 服务时遇到问题。
背景
该服务从队列中读取数据并创建子应用程序域,每个子应用程序域根据从队列中提取的项目运行一个特定的模块。我们将 Windows 服务称为“JobQueueAgent”,将每个模块称为“Job”。我将继续使用这些术语。可以将作业配置为以指定用户身份运行。我们在作业的应用程序域内使用模拟来完成此操作。 以下是服务中的逻辑和凭证流程:
JobQueueAgent(Windows 服务 - 主用户)>> 创建作业域 >> 工作域(应用域)>>冒充子用户>> 在模拟线程上运行作业 >> 工作(模块-子用户)>>工作逻辑
“主要用户”和“子用户”都是具有“作为服务登录”权限的域帐户。
服务在运行 Windows Server 2012 R2 的虚拟服务器上运行。
以下是我正在使用的 C# 模拟代码:
namespace JobQueue.WindowsServices
{
using System;
using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Permissions;
using System.Security.Principal;
internal sealed class ImpersonatedIdentity : IDisposable
{
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public ImpersonatedIdentity(NetworkCredential credential)
{
if (credential == null) throw new ArgumentNullException("credential");
if (LogonUser(credential.UserName, credential.Domain, credential.Password, 5, 0, out _handle))
{
_context = WindowsIdentity.Impersonate(_handle);
}
else
{
throw new AuthenticationException("Impersonation failed.", newWin32Exception(Marshal.GetLastWin32Error()));
}
}
~ImpersonatedIdentity()
{
Dispose();
}
public void Dispose()
{
if (_handle != IntPtr.Zero)
{
CloseHandle(_handle);
_handle = IntPtr.Zero;
}
if (_context != null)
{
_context.Undo();
_context.Dispose();
_context = null;
}
GC.SuppressFinalize(this);
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool LogonUser(string userName, string domain, string password, int logonType,int logonProvider, out IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
private IntPtr _handle = IntPtr.Zero;
private WindowsImpersonationContext _context;
}
}
问题
需要一些作业才能对服务器上运行的另一个 Windows 服务进行 net.pipe WCF 服务调用。在模拟下运行时,net.pipe 调用失败。
这是我在这种情况下遇到的异常:
未处理的异常:System.ComponentModel.Win32Exception:访问权限为 拒绝
服务器堆栈跟踪:在 System.ServiceModel.Channels.AppContainerInfo.GetCurrentProcessToken() 在 System.ServiceModel.Channels.AppContainerInfo.RunningInAppContainer() 在 System.ServiceModel.Channels.AppContainerInfo.get_IsRunningInAppContainer() 在 System.ServiceModel.Channels.PipeSharedMemory.BuildPipeName(字符串 pipeGuid)
net.pipe 未在模拟下运行时成功。将模拟用户添加到管理员组时,net.pipe 调用也会成功。这意味着用户在模拟时需要一些特权才能拨打电话。我们无法确定用户在模拟时进行 net.pipe 调用所需的策略、特权或访问权限。将用户设置为管理员是不可接受的。
这是一个已知问题吗?用户成功需要特定的权利吗?我可以进行代码更改来解决此问题吗? Using WCF's net.pipe in a website with impersonate=true 似乎表明由于 NetworkService,这在 ASP.NET 应用程序中不起作用。不确定,但这不应该适用于此。
【问题讨论】:
-
你说net.pipe在你不冒充的时候成功了;在您尝试模拟的用户帐户的上下文中从普通应用程序(而不是服务)运行时,它是否成功?换句话说,您确定问题与模拟有关,而不仅仅是因为被模拟的用户帐户缺乏必要的连接权限?
-
另外,您应该尝试使用交互式登录类型 (2) 而不是服务登录类型 (5)。我认为这不会有什么不同,但我不确定。
-
我可以在控制台应用程序中重新创建问题。很遗憾,交互式登录无法正常工作。
-
不使用模拟时调用成功。
-
但是,模拟是一项要求,所以问题仍然存在。
标签: .net windows wcf named-pipes impersonation