3

在模拟管理员用户将 .cer(证书文件)文件安装到 LocalComputer 时遇到问题...正在为 CurrentUser 工作完美安装。

我总是收到错误消息“拒绝访问”。

使用以下代码进行模拟:

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 中调用方法的方式。

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


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

                }
4

2 回答 2

0

Here is code that I use for impersonation of service accounts and it's proven to work well:

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;
        }
    }
}

Example usage:

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

The important thing to note is that you must be using the correct logon type and logon provider when trying to impersonate an account not on the same domain as the active domain. I check for this and automatically assign the correct logon type and logon provider in the Impersonation constructor.

于 2013-09-23T14:11:45.710 回答
0

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

您的代码之间的明显区别是您没有[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]在函数中包含限定符。如果这是图书馆的一部分,您也需要为整个图书馆这样做。

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

于 2013-09-23T14:11:06.903 回答