Retrieve credentials from Windows Credentials Store using C#
Asked Answered
L

5

50

I simply want to query the Credentials Store (or Vault as it is called in Windows 8) and get the login data. MSDN is really unhelpful in this case, and I also do not want any C++ P/Invoke 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 Windows 8 is preferred.

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

So how do I access the Windows Credentials Store?

Leonie answered 19/7, 2013 at 8:26 Comment(0)
G
66

There is a NuGet library that I've been using, called CredentialManagement.

The usage is pretty simple. I wrapped it a little, but I 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. :-)

Gnat answered 19/7, 2013 at 13:13 Comment(6)
What I don't get is the PasswordVault class is marked by the [DualApiPartition()] attribute meaning it can also be used in desktop apps (WPF). Is that a typo on their class page? msdn.microsoft.com/en-us/library/windows/apps/…Ardine
There are two considerations with this answer and they're not necessarily flaws of the library but flaws of the credential manager in Windows. You can basically load and decrypt the username and password for any credential on your machine with this, and so can any other application. This isn't safe or secure by any sense of the word. Plus there is of course the use of plain text string, as other users have mentioned. However, the first point alone should make you very skeptical of this whole system.Submission
I found this page helpful for understanding what different things mean in the Credential class: msdn.microsoft.com/en-us/library/windows/desktop/…Aphesis
Scary! I can just execute CredentialManager.GetCredentials("outlook.office365.com"); and get my username/password in clear text!Ellaelladine
I know this is a very old answer, but has anyone been able to use this library to store Windows Credentials, not Generic Credentials, in this format \\192.168.0.1 ?Felisafelise
Its useless on server as it can be read by account only by which it was created. So you can't use it in web-apps.Threegaited
A
4

This works from a Windows Server 2012. I don't have a Windows 8 box to test from.

Using Windows 8 WinRT APIs in .NET Desktop Applications

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;
}
Auden answered 9/6, 2014 at 8:26 Comment(0)
K
2

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.

Killie answered 8/5, 2014 at 15:19 Comment(1)
You are right and in general I use SecureString. But the MSDN Page you linked does not answer the question. It only answer how to handle Credentials/CredentialSets and Password Prompts, not how to deal with the Password Vault built into Windows.Leonie
P
0

Using CredentialManagement (view answer Retrieve credentials from Windows Credentials Store using C#).

It may be 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;
        }
    }
Pyx answered 2/1, 2015 at 12:27 Comment(0)
F
0

Many of the above answers are obsolete these days, the NuGet library called CredentialManagement hasn't been updated in 10 years, and the source is no longer accessible.

My recommendation would be to use this Nuget package. The interface is nice and clean, and it's up-to date (Updated 2022) and works well, and the source is all present and correct on Github and licensed for use under the permissive MIT license.

Nuget: https://www.nuget.org/packages/AdysTech.CredentialManager

Source: https://github.com/AdysTech/CredentialManager

Forever answered 21/3 at 14:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.