MVC:以不同的用户身份启动流程 - 无法正常工作

时间:2016-07-12 11:10:34

标签: c# asp.net-mvc process impersonation

我需要从MVC控制器在服务器上运行可执行文件。问题:可执行文件位于Program Files文件夹中,并且还将从注册表中读取值。 我已将相应文件夹的执行权限授予我的应用程序池。 所以这就是我的问题:

仅使用Process.Start(exe)运行exe将启动可执行文件,然后由于无法读取注册表值(无访问权限)而退出并出现错误。

将本地管理员用户分配给ProcessStartInfo失败:

var exe = @"C:\Program Files (x86)\[path to exe]";

var secString = new SecureString();
secString.AppendChar('character');
//...
secString.MakeReadOnly();

var procInfo = new ProcessStartInfo(exe, settingsPath)
{
    UseShellExecute = false,
    UserName = "[username]",
    Domain = "[domain]",
    Password = secString,
    RedirectStandardError = true,
    RedirectStandardOutput = true,
    RedirectStandardInput = true,
    Verb = "runas"
};
var proc = Process.Start(procInfo);
proc.WaitForExit();

这会导致conhost和可执行文件崩溃。

使用这样的模拟:

var impers = new ImpersonationService();
impers.PerformImpersonatedTask("[user]", "[domain]", "[password]",
ImpersonationService.LOGON32_LOGON_INTERACTIVE, ImpersonationService.LOGON32_PROVIDER_DEFAULT, new Action(RunClient));

...使用方法RunClient()只需使用Process.Start(exe)即可完成任务!运行该方法但该过程未启动。我知道该方法已经运行,因为我在其中添加了这一行:

_logger.Debug("Impersonated: {0}", Environment.UserName);

正确地为我提供了该过程应使用的所需用户名。该用户具有本地管理员权限,因此不存在问题。

我甚至尝试从我的Controller启动一个不同的可执行文件并让一个使用模拟(两个变体)来启动目标可执行文件 - 相同的结果。

所以现在我走到了尽头。任何人都可以告诉我,我做错了什么以及我必须做些什么才能使它发挥作用?

P.S:登录时直接在服务器上运行目标可执行文件,因为本地管理员用户工作得非常好,所以对exe本身没有任何疑问。

  

修改

我的描述中似乎有一部分是不正确的:使用模拟和RunClient方法我实际上使用Process.Start(exe)但是这样:

var procInfo = new ProcessStartInfo(exe, settingsPath)
{
    UseShellExecute = false,
};
_logger.Debug("Impersonated: {0}", Environment.UserName);
var proc = Process.Start(procInfo);

出于绝望,我现在已经绕过了procInfo(实际上并不需要它)而真的被称为

var proc = Process.Start(exe, argument);

现在.exe开始了!似乎使用ProcessStartInfo会覆盖进程的模拟?

但仍然不行,因为现在我得到一个"访问被拒绝"错误。尽管是本地管理员。这很奇怪。

  

编辑2:   这就是我最近的尝试:

  • 切换回调用助手.exe,传递稍后用于程序文件中的实际目标exe的相同参数
  • 使用level="requireAdministrator"
  • 向该帮助程序exe添加了一个清单
  • 在启动目标进程的方法之前添加了https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]并向我的助手exe添加了模拟。
  • 通过向ProcessStartInfo提供所有jazz
  • 来启动此过程

结果代码:

try
{
    var secString = new SecureString();
    //...
    secString.MakeReadOnly();
    var procInfo = new ProcessStartInfo()
    {
        FileName = Path.GetFileName(exe),
        UserName = "[UserName]",
        Domain = "[domain]",
        Password = secString,
        UseShellExecute = false,
        RedirectStandardError = true,
        RedirectStandardOutput = true,
        RedirectStandardInput = true,
        Arguments = settingsPath,
        WorkingDirectory = @"C:\Program Files (x86)\[rest]"
    };
    var proc = Process.Start(procInfo);
    proc.WaitForExit();
    if (proc.ExitCode != 0)
    {
        using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.log"), true))
        {
            sw.WriteLine("Error running process:\r\n{0}", proc.ExitCode.ToString());
        }
    }
}
catch (Exception ex)
{
    using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.log"), true))
    {
        sw.WriteLine("Error running process:\r\n{0}\r\nRunning as: {1}", ex.ToString(), WindowsIdentity.GetCurrent().Name);
    }
}

产生的输出到error.log:

  

帮助者跑步!   [通过论证]   运行进程出错:System.ComponentModel.Win32Exception   (0x80004005):拒绝访问   System.Diagnostics.Process.StartWithCreateProcess(的ProcessStartInfo   startInfo)在System.Diagnostics.Process.Start()at   System.Diagnostics.Process.Start(ProcessStartInfo startInfo)at   RunClient.ImpersonationDemo.RunClient(String settingsPath)   运行方式:[管理员组中的正确域用户]

所以我可以启动帮助程序exe但是 无法在程序文件中启动真正的exe,因为Acess被拒绝了,尽管在本地Admin帐户下运行并且所有文件都在本地访问,而不是在网络驱动器上访问。 / p>

这是我的逻辑。

  

编辑3

更新:我已经向目标.exe添加了一个清单,

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

这意味着我现在:

  • 从控制器调用帮助程序exe:工作
  • 帮助程序.exe具有使用提升权限(Admin)运行的清单
  • 帮助程序.exe使用模拟来假定本地管理员的身份以启动进程
  • 使用ProcessStartInfo启动所述进程,其中用户名,域名和密码另外设置为同一本地管理员用户
  • 然后帮助程序exe尝试使用Process.Start(Startinfo)运行目标exe并使用本地管理员用户设置,同时仍模拟该用户的Windows身份

并且仍然错误日志spouts&#34;访问被拒绝&#34;正确地将WindowsIdentity.GetCurrent().Name正确地返回给本地管理员。

现在,最重要的是:我在该服务器上创建了一个新的本地用户,将他添加到本地管理员组并使用用户进行模拟,以防域名出现问题用户。你猜怎么着?现在我收到一个错误Access denied to ...\error.log - 写入了生成错误日志。

真的?

  

编辑4

我想我会尝试使用TopShelf将这个shebang转换为服务。希望在周末完成这项工作。

2 个答案:

答案 0 :(得分:5)

根据this article,您的mvc控制器线程应具有完全信任权限才能运行该进程:

  

此类包含适用于类级别的链接需求   所有成员。直接调用者抛出SecurityException   没有完全信任的许可。有关安全性的详细信息   需求,请参阅链接需求。

似乎你的问题不是用户而是完全信任。我不知道您使用的是哪个版本的MVC,但您可以阅读文章Trust LevelsCode Access以找出配置应用程序的最佳方法。似乎您只能向特定的.exe文件授予完全信任权限,或者向应用程序池用户授予完全信任权限(不要忘记文件夹权限)。

但最好的方法是编写一些Windows服务并运行它,而不是直接运行一些.exe文件。

答案 1 :(得分:0)

您可以在应用的web.config中尝试信任级别

<system.web>
  <securityPolicy>
    <trustLevel name="Full" policyFile="internal"/>
  </securityPolicy>
</system.web>