ASP.NET Web处理程序运行命令作为请求用户

时间:2015-07-20 13:38:09

标签: asp.net

从Web处理程序(xxx.ashx)我需要使用网页作为同一用户运行命令并发送请求。我有使用模拟的IIS设置,在我的.ashx中有代码,表明它模仿用户,然后我使用C#Process.start()来运行命令。 (它是我正在运行的.cmd文件)

问题是.cmd文件是作为分配给应用程序池而不是Web用户的用户运行的。我甚至试过这段代码:

WindowsImpersonationContext impersonationContext =((WindowsIdentity)System.Security.Principal.WindowsIdentity.GetCurrent())。Impersonate();

这可能是一个问题:我编写.ashx文件并将其放在IIS wwwroot / myapp文件夹下,并从Web浏览器的URL中调用它。我使用DefaultAppPool用户和操作系统用户设置了应用程序池,但没有区别。

我是IIS& amp;的新手ASP也是如此,这就像在黑盒子里工作一样。

1 个答案:

答案 0 :(得分:0)

我们必须使用本机Windows方法:CreateProcessAsUser(),并且必须调用DuplicateTokenEx()来复制安全令牌。

    <%@ WebHandler Language="C#" Class="batchRunSAS" %>
    using System;

    using System;
    using System.IO;
    using System.Web;
    using System.Diagnostics;
    using System.Security.Principal;

    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Security;
    using System.Runtime.InteropServices;
    using System.ComponentModel;

            public class batchRun : IHttpHandler
    {
        public void ProcessRequest (HttpContext context)
        {
            //Call DuplicateTokenEx
            //https://msdn.microsoft.com/en-us/library/ms682429(VS.85).aspx
            //http://stackoverflow.com/questions/9095909/createprocessasuser-creating-window-in-active-session
            Process process = null;

            process = NativeMethods.CreateProcessAsUser("C:\\temp\\test.exe");
        }

        public bool IsReusable
        {
            get { return false; }
        }

        [SuppressUnmanagedCodeSecurity]
        class NativeMethods
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct STARTUPINFO
            {
                public Int32 cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public Int32 dwX;
                public Int32 dwY;
                public Int32 dwXSize;
                public Int32 dwXCountChars;
                public Int32 dwYCountChars;
                public Int32 dwFillAttribute;
                public Int32 dwFlags;
                public Int16 wShowWindow;
                public Int16 cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }

            [StructLayout(LayoutKind.Sequential)]
            public struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public Int32 dwProcessID;
                public Int32 dwThreadID;
            }

            [StructLayout(LayoutKind.Sequential)]
            public struct SECURITY_ATTRIBUTES
            {
                public Int32 Length;
                public IntPtr lpSecurityDescriptor;
                public bool bInheritHandle;
            }

            public enum SECURITY_IMPERSONATION_LEVEL
            {
                SecurityAnonymous,
                SecurityIdentification,
                SecurityImpersonation,
                SecurityDelegation
            }

            public enum TOKEN_TYPE
            {
                TokenPrimary = 1,
                TokenImpersonation
            }

            public const int GENERIC_ALL_ACCESS = 0x10000000;
            public const int CREATE_NO_WINDOW = 0x08000000;

            [
               DllImport("kernel32.dll",
                  EntryPoint = "CloseHandle", SetLastError = true,
                  CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
            ]
            public static extern bool CloseHandle(IntPtr handle);

            [
               DllImport("advapi32.dll",
                  EntryPoint = "CreateProcessAsUser", SetLastError = true,
                  CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
            ]
            public static extern bool
               CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
                                   ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
                                   bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
                                   string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
                                   ref PROCESS_INFORMATION lpProcessInformation);

            [
               DllImport("advapi32.dll",
                  EntryPoint = "DuplicateTokenEx")
            ]
            public static extern bool
               DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
                                ref SECURITY_ATTRIBUTES lpThreadAttributes,
                                Int32 ImpersonationLevel, Int32 dwTokenType,
                                ref IntPtr phNewToken);

            public static Process CreateProcessAsUser(string filename, string args)
            {
                var hToken = WindowsIdentity.GetCurrent().Token;
                var hDupedToken = IntPtr.Zero;

                var pi = new PROCESS_INFORMATION();
                var sa = new SECURITY_ATTRIBUTES();
                sa.Length = Marshal.SizeOf(sa);

                try
                {
                    if (!DuplicateTokenEx(
                            hToken,
                            GENERIC_ALL_ACCESS,
                            ref sa,
                            (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                            (int)TOKEN_TYPE.TokenPrimary,
                            ref hDupedToken
                        ))
                        throw new Win32Exception(Marshal.GetLastWin32Error());

                    var si = new STARTUPINFO();
                    si.cb = Marshal.SizeOf(si);
                    si.lpDesktop = "";

                    var path = Path.GetFullPath(filename);
                    var dir = Path.GetDirectoryName(path);

                    // Revert to self to create the entire process; not doing this might
                    // require that the currently impersonated user has "Replace a process
                    // level token" rights - we only want our service account to need
                    // that right.
                    using (var ctx = WindowsIdentity.Impersonate(IntPtr.Zero))
                    {
                        if (!CreateProcessAsUser(
                                                hDupedToken,
                                                path,
                                                string.Format("\"{0}\" {1}", filename.Replace("\"", "\"\""), args),
                                                ref sa, ref sa,
                                                false, 0, IntPtr.Zero,
                                                dir, ref si, ref pi
                                        ))
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    return Process.GetProcessById(pi.dwProcessID);
                }
                finally
                {
                    if (pi.hProcess != IntPtr.Zero)
                        CloseHandle(pi.hProcess);
                    if (pi.hThread != IntPtr.Zero)
                        CloseHandle(pi.hThread);
                    if (hDupedToken != IntPtr.Zero)
                        CloseHandle(hDupedToken);
                }
            }
        }
    }