安装证书时模拟用户

时间:2013-09-23 13:54:11

标签: c#

有问题冒充管理员用户将.cer(证书文件)文件安装到LocalComputer ...安装当前用户工作费用。

我总是收到错误消息" Acces Denied"。

使用以下代码进行模拟:

using System;

using System.ComponentModel;

using System.Runtime.InteropServices;

using System.Security.Principal;

public class ImpersonatedUser : IDisposable
{

    IntPtr userHandle;

    WindowsImpersonationContext impersonationContext;



    public ImpersonatedUser(string domain,string user, string password)
    {

        userHandle = IntPtr.Zero;

        bool loggedOn = LogonUser(

            user,

            domain,

            password,

            LogonType.Interactive,

            LogonProvider.Default,

            out userHandle);



        if (!loggedOn)

            throw new Win32Exception(Marshal.GetLastWin32Error());



        // Begin impersonating the user

        impersonationContext = WindowsIdentity.Impersonate(userHandle);



    }



    public void Dispose()
    {

        if (userHandle != IntPtr.Zero)
        {

            CloseHandle(userHandle);

            userHandle = IntPtr.Zero;

            impersonationContext.Undo();

        }

    }



    [DllImport("advapi32.dll", SetLastError = true)]

    static extern bool LogonUser(

        string lpszUsername,

        string lpszDomain,

        string lpszPassword,

        LogonType dwLogonType,

        LogonProvider dwLogonProvider,

        out IntPtr phToken

        );



    [DllImport("kernel32.dll", SetLastError = true)]

    static extern bool CloseHandle(IntPtr hHandle);



    enum LogonType : int
    {

        Interactive = 2,

        Network = 3,

        Batch = 4,

        Service = 5,

        NetworkCleartext = 8,

        NewCredentials = 9,

    }



    enum LogonProvider : int
    {

        Default = 0,
        WINNT50 = 3,

    }

这是证书安装方法:

private static void InstallCertificate(string cerFileName, StoreName storeName)
        {
            LoginInfo loginInfo = new LoginInfo();
            X509Certificate2 certificate = new X509Certificate2(cerFileName);
            X509Store store = new X509Store(storeName, StoreLocation.LocalMachine);
            try
            {

                    store.Open(OpenFlags.ReadWrite);
                    store.Add(certificate);
                    store.Close();

            }
            catch (Exception e)
            {
                string CertName = Path.GetFileName(cerFileName);
                string source = e.Source.ToString();
                string message = e.Message.ToString();
                string messagetext = string.Format("Certificate installation \"{0}\" was not succsessfull Error: {1}", CertName, message);
                StringBuilder messagestring = new StringBuilder();
                messagestring.Append(source);
                messagestring.Append(message);
                MessageBox.Show(messagetext, "Install Certificate Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

这就是我在ImpersonatedUser中调用Method的方式。

using (new ImpersonatedUser(loginInfo.DomainName, loginInfo.UserName, loginInfo.Password))
                            {


                                MessageBox.Show(WindowsIdentity.GetCurrent().Name);
                                InstallCertificate(certpath, StoreName.TrustedPublisher);

                }

2 个答案:

答案 0 :(得分:0)

MS有一个很好的帮助页面,例如:http://msdn.microsoft.com/en-us/library/w070t6ka.aspx

您的代码之间的明显区别是您不在函数中包含[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]限定符。如果这是库的一部分,您也需要为整个库执行此操作。

我假设您登录的用户有权安装证书 - 请确保您的用户拥有这些权利。

答案 1 :(得分:0)

以下是我用于模拟服务帐户的代码,事实证明它可以正常运行:

using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;
using System.Security;
using System.Configuration;

namespace ImpersonationUtil
{
    /// <summary>
    /// Facilitates impersonation of a Windows User.
    /// </summary>
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public class Impersonation : IDisposable
    {
        public string Environment { get; set; }

        public string UserName { get; set; }

        public string Password { get; set; }

        public string DomainName { get; set; }

        public enum LogonType
        {
            Interactive = 2,
            Network = 3,
            Batch = 4,
            Service = 5,
            Unlock = 7,
            NetworkClearText = 8,
            NewCredentials = 9
        }

        public enum LogonProvider
        {
            Default = 0,
            WinNT35 = 1,
            WinNT40 = 2,
            WinNT50 = 3
        }

        /// <summary>
        /// Windows Token.
        /// </summary>
        private readonly SafeTokenHandle _handle;

        /// <summary>
        /// The impersonated User.
        /// </summary>
        private WindowsImpersonationContext impersonatedUser;

        public Impersonation()
        {
        }

        /// <summary>
        /// Initializes a new instance of the Impersonation class. Provides domain, user name, and password for impersonation.
        /// </summary>
        /// <param name="domainName">Domain name of the impersonated user.</param>
        /// <param name="userName">Name of the impersonated user.</param>
        /// <param name="password">Password of the impersonated user.</param>
        /// <remarks>
        /// Uses the unmanaged LogonUser function to get the user token for
        /// the specified user, domain, and password.
        /// </remarks>
        public Impersonation(AccountCredentials credentials)
        {            
            string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');
            string name = (splitName.Length > 0) ? splitName[0] : null;

            LogonType logonType = LogonType.Interactive;
            LogonProvider logonProvider = LogonProvider.Default;

            if (name != credentials.Domain)
            {
                logonType = LogonType.NewCredentials;
                logonProvider = LogonProvider.WinNT50;
            }

            // Call LogonUser to obtain a handle to an access token.
            bool returnValue = LogonUser(
                                credentials.UserName,
                                credentials.Domain,
                                credentials.Password,
                                (int)logonType,
                                (int)logonProvider,
                                out this._handle);

            if (false == returnValue)
            {
                // Something went wrong.
                int ret = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(ret);
            }

            this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());    
        }

        /// <summary>
        /// Initializes a new instance of the Impersonation class. Provide domain, user name, and password for impersonation.
        /// </summary>
        /// <param name="domainName">Domain name of the impersonated user.</param>
        /// <param name="userName">Name of the impersonated user.</param>
        /// <param name="password">Password of the impersonated user.</param>
        /// <remarks>
        /// Uses the unmanaged LogonUser function to get the user token for
        /// the specified user, domain, and password.
        /// </remarks>
        public Impersonation(string domainName, string userName, string password)
        {
            string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');
            string name = (splitName.Length > 0) ? splitName[0] : null;

            LogonType logonType = LogonType.Interactive;
            LogonProvider logonProvider = LogonProvider.Default;

            if (name != domainName)
            {
                logonType = LogonType.NewCredentials;
                logonProvider = LogonProvider.WinNT50;
            }

            // Call LogonUser to obtain a handle to an access token.
            bool returnValue = LogonUser(
                                userName,
                                domainName,
                                password,
                                (int)logonType,
                                (int)logonProvider,
                                out this._handle);

            if (false == returnValue)
            {
                // Something went wrong.
                int ret = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(ret);
            }

            this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool LogonUser(
                string lpszUsername,
                string lpszDomain,
                string lpszPassword,
                int dwLogonType,
                int dwLogonProvider,
                out SafeTokenHandle phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(IntPtr handle);

        public void Dispose()
        {
            this.impersonatedUser.Dispose();
            this._handle.Dispose();
        }

        private static string[] GetAccountInfo(string accountInfo)
        {
            return accountInfo.Split(' ');
        }
    }

    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle()
            : base(true) { }

        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }
}

AccountCredentials.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;

namespace ImpersonationUtil
{
    public class AccountCredentials
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Domain { get; set; }

        public AccountCredentials(string userName, string password, string domain)
        {
            UserName = userName;
            Password = password;
            Domain = domain;
        }
    }
}

使用示例:

AccountCredentials credentials = new AccountCredentials("user", "password", "domain");
using (new Impersonation(credentials))
{
    // do work under the impersonated user
}

需要注意的重要一点是,在尝试模拟与活动域不在同一域中的帐户时,您必须使用正确的登录类型和登录提供程序。我检查了这一点,并在Impersonation构造函数中自动分配了正确的登录类型和登录提供程序。