Installing PFX certificate on a different user

天涯浪子 提交于 2019-12-07 19:16:58

问题


The code below works pefectly to install a pfx on the current user. I want to install it on another user, by giving the username and password (without having to log in with that user). I did this a while ago with a batch file, how could I do this using C#?

I've tried a few things, including impersonation but couldn't make it work.

X509Certificate2 certificate = new X509Certificate2("C:\\teste\\cert.pfx", "password");
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();

Update:

Thanks to Bill's code, the process is working fine, as long as the users are logged in. Once they log off, an exception is thrown when trying to install the pfx. "The system could not find the specified file". If the users log back in, it works again!!

This code is very useful as it is, but if it could also work when the users are OFFLINE it would be perfect for the job! Is there a way to do it?

Thanks in advance!

// obtains user token
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
    int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

// closes open handes returned by LogonUser
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);

public void DoWorkUnderImpersonation() {
    //elevate privileges before doing file copy to handle domain security
    WindowsImpersonationContext impersonationContext = null;
    IntPtr userHandle = IntPtr.Zero;
    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;
    string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];
    string user = ConfigurationManager.AppSettings["ImpersonationUser"];
    string password = ConfigurationManager.AppSettings["ImpersonationPassword"];

    try {
        Console.WriteLine("windows identify before impersonation: " + WindowsIdentity.GetCurrent().Name);

        // if domain name was blank, assume local machine
        if (domain == "")
            domain = System.Environment.MachineName;

        // Call LogonUser to get a token for the user
        bool loggedOn = LogonUser(user,
                                    domain,
                                    password,
                                    LOGON32_LOGON_INTERACTIVE,
                                    LOGON32_PROVIDER_DEFAULT,
                                    ref userHandle);

        if (!loggedOn) {
            Console.WriteLine("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
            return;
        }

        // Begin impersonating the user
        impersonationContext = WindowsIdentity.Impersonate(userHandle);

        Console.WriteLine("Main() windows identify after impersonation: " + WindowsIdentity.GetCurrent().Name);

        //run the program with elevated privileges (like file copying from a domain server)
        DoWork();

    } catch (Exception ex) {
        Console.WriteLine("Exception impersonating user: " + ex.Message);
    } finally {
        // Clean up
        if (impersonationContext != null) {
            impersonationContext.Undo();
        }

        if (userHandle != IntPtr.Zero) {
            CloseHandle(userHandle);
        }
    }
}


private void DoWork() {
    //everything in here has elevated privileges
    X509Certificate2 certificate = new X509Certificate2("C:\\teste\\cert.pfx", "password");
    X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    store.Open(OpenFlags.ReadWrite);
    store.Add(certificate);
    store.Close();
}

回答1:


How did you go about doing impersonation? I've used the impersonation snippet from this answer in the past successfully before: How to use LogonUser properly to impersonate domain user from workgroup client

The way I used it was wrapping it up in a DLL and calling it from powershell. It may work for accessing that user's certificate store, thereby allowing StoreLocation.CurrentUser to do its thing.

To apply this to your situation, you could try:

// obtains user token
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
    int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

// closes open handes returned by LogonUser
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);

public void DoWorkUnderImpersonation() {
    //elevate privileges before doing file copy to handle domain security
    WindowsImpersonationContext impersonationContext = null;
    IntPtr userHandle = IntPtr.Zero;
    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;
    string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];
    string user = ConfigurationManager.AppSettings["ImpersonationUser"];
    string password = ConfigurationManager.AppSettings["ImpersonationPassword"];

    try {
        Console.WriteLine("windows identify before impersonation: " + WindowsIdentity.GetCurrent().Name);

        // if domain name was blank, assume local machine
        if (domain == "")
            domain = System.Environment.MachineName;

        // Call LogonUser to get a token for the user
        bool loggedOn = LogonUser(user,
                                    domain,
                                    password,
                                    LOGON32_LOGON_INTERACTIVE,
                                    LOGON32_PROVIDER_DEFAULT,
                                    ref userHandle);

        if (!loggedOn) {
            Console.WriteLine("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
            return;
        }

        // Begin impersonating the user
        impersonationContext = WindowsIdentity.Impersonate(userHandle);

        Console.WriteLine("Main() windows identify after impersonation: " + WindowsIdentity.GetCurrent().Name);

        //run the program with elevated privileges (like file copying from a domain server)
        DoWork();

    } catch (Exception ex) {
        Console.WriteLine("Exception impersonating user: " + ex.Message);
    } finally {
        // Clean up
        if (impersonationContext != null) {
            impersonationContext.Undo();
        }

        if (userHandle != IntPtr.Zero) {
            CloseHandle(userHandle);
        }
    }
}


private void DoWork() {
    //everything in here has elevated privileges
    X509Certificate2 certificate = new X509Certificate2("C:\\teste\\cert.pfx", "password");
    X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    store.Open(OpenFlags.ReadWrite);
    store.Add(certificate);
    store.Close();
}


来源:https://stackoverflow.com/questions/33189898/installing-pfx-certificate-on-a-different-user

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!