Retrieve Credentials from Windows Credentials Stor

2019-01-04 02:01发布

I simply want to query the Credentials Store (or Vault as it is called in Win8) and get the login data. The MSDN is really unhelpful in this case and I also do not want any C++ pInvoke approaches.

I know that similar questions have been asked here a few times, but none of those solutions work in my case. I do not use Metro App programming so things like PasswordVault are (as it looks) not available. I just create a simple C# WPF Desktop application.

Ideally it should work in several Windows versions, but Win8 is prefered.

More specifically I want to query the stored data from the CRM plugin for Outlook to automatically have my app log in to the CRM Server without having the User to ask for his Credentials. That means, if this is even possible...

So how do I access the Windows Credentials Store?

4条回答
你好瞎i
2楼-- · 2019-01-04 02:27

Using CredentialManagement (view answer https://stackoverflow.com/a/17747020/206730).

Maybe useful using Powershell too:

CredMan.ps1
https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Credentials-d44c3cde

I cannot list all credentials stored.

using CredentialManagement;
using System.Diagnostics;

namespace UnitTestProject1
{
    [TestClass]
    public class CredentialTests
    {

        [TestMethod]
        public void Set_Credentials_for_older_domain_whe_migration_to_new_domain()
        {
            var accesos = new List<string> {
            "intranet",
            "intranet.xxxxx.net",
            "intranet.zzzzzzzz.com",
            "intranetescritorio.zzzzzzzz.net",
            "more...",
            };

            accesos.ForEach(acceso => SaveCredential(acceso));
        }

        private static Credential SaveCredential(string CredentialName)
        {
            var UserName = @"OLDERDOMAIN\user";
            var Password = "pass";

            var cm = new Credential { Target = CredentialName, Type = CredentialType.DomainPassword };
            if (cm.Exists())
            {
                cm.Load();
                Console.WriteLine("Credential " + cm.Target + ". Data: " + cm.Username + " " + cm.Password);

                //if (cm.Type == CredentialType.Generic)  cm.Delete();

                return cm;
            }

            cm = new Credential
            {
                Target = CredentialName,
                Type = CredentialType.DomainPassword,
                PersistanceType = PersistanceType.Enterprise,
                Username = UserName,
                Password = Password
            };
            cm.Save();
            return cm;
        }

    }
查看更多
放荡不羁爱自由
3楼-- · 2019-01-04 02:35

There is a Nuget library that I've been using called CredentialManagement http://nuget.org/packages/CredentialManagement/

The usage is pretty simple. I wrapped it a little but probably didn't need to:

public static class CredentialUtil
{
    public static UserPass GetCredential(string target)
    {
        var cm = new Credential {Target = target};
        if (!cm.Load())
        {
            return null;
        }

        //UserPass is just a class with two string properties for user and pass
        return new UserPass(cm.Username, cm.Password);
    }

    public static bool SetCredentials(
         string target, string username, string password, PersistanceType persistenceType)
    {
       return new Credential {Target = target, Username = username, 
               Password = password, PersistanceType =  persistenceType}.Save();
    }

    public static bool RemoveCredentials(string target)
    {
        return new Credential { Target = target }.Delete();
    }
}

Sample usage:

CredentialUtil.SetCredentials("FOO", "john", "1234", PersistanceType.LocalComputer);
var userpass = CredentialUtil.GetCredential("FOO");
Console.WriteLine($"User: {userpass.Username} Password: {userpass.Password}");
CredentialUtil.RemoveCredentials("FOO");
Debug.Assert(CredentialUtil.GetCredential("FOO") == null);

If you're interested in implementing it yourself, browse the source: http://credentialmanagement.codeplex.com/SourceControl/latest

The trick is that there is no C# API into the Credential Manager. This library wraps the other .dll entry points nicely. :-)

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-04 02:35

This works from a Windows 2k12, I don't have a Win 8 box to test from

http://blogs.msdn.com/b/cdndevs/archive/2013/10/02/using-windows-8-winrt-apis-in-net-desktop-applications.aspx

In short

  1. Unload project file
  2. Edit it
  3. Add <TargetPlatformVersion>8.0</TargetPlatformVersion> to the PropertyGroup part
  4. Add reference to Windows.Security (you'll have a list of Windows Libraries)
  5. Add System.Runtime.WindowsRuntime.dll located in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5

You can then use this(from here):

private string resourceName = "My App";
private string defaultUserName;

private void Login()
{
 var loginCredential = GetCredentialFromLocker();

if (loginCredential != null)
{
    // There is a credential stored in the locker.
    // Populate the Password property of the credential
    // for automatic login.
    loginCredential.RetrievePassword();
}
else
{
    // There is no credential stored in the locker.
    // Display UI to get user credentials.
    loginCredential = GetLoginCredentialUI();
}

// Log the user in.
ServerLogin(loginCredential.UserName, loginCredential.Password);
}


private Windows.Security.Credentials.PasswordCredential GetCredentialFromLocker()
{
Windows.Security.Credentials.PasswordCredential credential = null;

var vault = new Windows.Security.Credentials.PasswordVault();
var credentialList = vault.FindAllByResource(resourceName);
if (credentialList.Count > 0)
{
    if (credentialList.Count == 1)
    {
        credential = credentialList[0];
    }
    else
    {
        // When there are multiple usernames,
        // retrieve the default username. If one doesn’t
        // exist, then display UI to have the user select
        // a default username.

        defaultUserName = GetDefaultUserNameUI();

        credential = vault.Retrieve(resourceName, defaultUserName);
    }
}

return credential;
}
查看更多
成全新的幸福
5楼-- · 2019-01-04 02:40

The answer from Randy uses System.String to store the password, which is unsafe. You will want to use System.Security.SecureString for that purpose.

You would be better off if you just read Credential Management with the .NET Framework 2.0.

查看更多
登录 后发表回答