Git Product home page Git Product logo

credentialmanager's Introduction

Build status

Nuget Package

AdysTech.CredentialManager

Supports .NET Framework 4.5+, and .NET Standard 2.1+.

Latest Download

AdysTech.CredentialManager

CredentialManager

C# wrapper around CredWrite / CredRead functions to store and retrieve from Windows Credential Store. Windows OS comes equipped with a very secure robust Credential Manager from Windows XP onwards, and good set of APIs to interact with it. However .NET Framework did not provide any standard way to interact with this vault until Windows 8.1.

Microsoft Peer Channel blog (WCF team) has written a blog post in 2005 which provided basic structure of using the Win32 APIs for credential management in .NET. I used their code, and improved up on it to add PromptForCredentials function to display a dialog to get the credentials from user.

Need: Many web services and REST Urls use basic authentication. .Net does not have a way to generate basic auth text (username:password encoded in Base64) for the current logged in user, with their credentials. ICredential.GetCredential (uri, "Basic") does not provide a way to get current user security context either as it will expose the current password in plain text. So only way to retrieve Basic auth text is to prompt the user for the credentials and storing it, or assume some stored credentials in Windows store, and retrieving it.

This project provides access to all three

1. Prompt user for Credentials

var cred = CredentialManager.PromptForCredentials ("Some Webservice", ref save, "Please provide credentials", "Credentials for service");

2. Save Credentials

var cred = new NetworkCredential ("TestUser", "Pwd");
CredentialManager.SaveCredentials ("TestSystem", cred);

3. Retrieve saved Credentials

var cred = CredentialManager.GetCredentials ("TestSystem");

With v2.0 release exposes raw credential, with additional information not available in normal NetworkCredential available in previous versions. This library also allows to store comments and additional attributes associated with a Credential object. The attributes are serialized using BinaryFormatter and API has 256 byte length. BinaryFormatter generates larger than what you think the object size is going to be, si keep an eye on that.

Comments and attributes are only accessible programmatically. Windows always supported such a feature (via CREDENTIALW structure) but Windows Credential Manager applet does not have any way to show this information to user. So if an user edits the saved credentials using control panel comments and attributes gets lost. The lack of this information may be used as a tamper check. Note that this information is accessible all programs with can read write to credential store, so don't assume the information is secure from everything.

4. Save and retrieve credentials with comments and attributes

    var cred = (new NetworkCredential(uName, pwd, domain)).ToICredential();
    cred.TargetName = "TestSystem_Attributes";
    cred.Attributes = new Dictionary<string, Object>();
    var sample = new SampleAttribute() { role = "regular", created = DateTime.UtcNow };
    cred.Attributes.Add("sampleAttribute", sample);
    cred.Comment = "This comment is only visible via API, not in Windows UI";
    cred.SaveCredential();

5. Getting ICredential from previously saved credential

    var cred =  CredentialManager.GetICredential(TargetName);
    cred.Comment = "Update the credential data and save back";
    cred.SaveCredential();

deprecated

AdysTech.CredentialManager.Core

credentialmanager's People

Contributors

aschoelzhorn avatar drewnoakes avatar erikjon avatar esrahofstede avatar jairbubbles avatar kvvinokurov avatar ldattilo avatar leptitdev avatar mvadu avatar nguillermin avatar pmiossec avatar strzalkowski avatar vonspiczak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

credentialmanager's Issues

CredentialManager.GetCredentials() throws System.ArgumentOutOfRangeException with "Not a valid Win32 FileTime"

Using commit 9978cb6, this code

var credential = CredentialManager.GetCredentials("Target");

can throw a System.ArgumentOutOfRangeException with "Not a valid Win32 FileTime".

The exception is thrown in Credentials.cs at line 43.

Solution:
Change the typecast of the right operand of the bitwise or-operator from ulong to uint:
from

LastWritten = DateTime.FromFileTime((long)((ulong)ncred.LastWritten.dwHighDateTime << 32 | (ulong)ncred.LastWritten.dwLowDateTime));

to

LastWritten = DateTime.FromFileTime((long)((ulong)ncred.LastWritten.dwHighDateTime << 32 | (uint)ncred.LastWritten.dwLowDateTime));

Rationale: The typecast to ulong extends the sign bit. For negative values, the upper 32 bits are set to 1.

Support .NET Standard?

Hi there,
We use your package in Git Extensions, which we are currently porting to .NET Core and .NET Standard. CredentialManager is built against .NET 4.5 which is causing some frictions.

Are there any plans to migrate to .NET Standard?

Thanks

Passwords with length one are always returned as empty

Passwords with length 1 are always returned as empty passwords.

Error is in the class Credential in method internal Credential(NativeCode.NativeCredential ncred).

            if (ncred.CredentialBlobSize > 2)
            {

should be

            if (ncred.CredentialBlobSize >= 2)
            {

Doesn't support blank passwords

When setting credentials directly in Windows, you are allowed to store credentials with a blank password. Credential.SaveCredential currently blocks this via the following:

if (String.IsNullOrEmpty(this.CredentialBlob)) throw new ArgumentNullException("CredentialBlob", "CredentialBlob can't be Null or Empty");

Could this be removed, or made optional? Have tried removing it on a local version and everything else seems to work as intended.

Nuget package target framework

I see that the target frameworks have changed in the past few versions:
2.1.1 had netstandard2.1 and net45
2.2.0 has netcoreapp2.2 and net45

Was there a reason for the change? I'm getting compatibility warnings in my netstandard2.0 library project.
.net standard is recommended for library projects, and according to
https://docs.microsoft.com/en-us/dotnet/standard/net-standard
the recommendation is to target the lowest possible version.
I tried fiddling around with the target frameworks, and the lowest .net standard version that compiles is 2.0. This is also compatible with .net core 2.2 and up, so if the requirement is to retain compatibility with framework 4.5 and core 2.2, the most sensible thing would be to have target frameworks set to:

  • net45 - only compatible version of standard is 1.0 which won't do, so it has to be targeted specifically
  • netstandard2.0 - compatible with .net core 2.2 and up

The tests csproj file would also have to be updated to target runtimes specifically.

GetCredentials fails when saved by PromptForCredentialsConsole

When selecting to Remember this password, you cannot retrieve the credential using GetCredentials. The credential is saved under the Windows Credentials rather than Generic. I found that adding | NativeCode.CredentialUIFlags.GenericCredentials to line 166 resolves this.

Can't retrieve credentials when using windows service

I'm creating Worker in .NET Core 3.1 for Windows Service as described here: https://dotnetcoretutorials.com/2019/12/07/creating-windows-services-in-net-core-part-3-the-net-core-worker-way
I'm using AdysTech.CredentialManager for API credentials in the Worker.

var target = "MyAppName";
var cred = CredentialManager.GetCredentials(target)

I have generic credentials defined using Control Panel\All Control Panel Items\Credential Manager. When I run worker locally then credentials are retrieved correctly. However, when I install the worker as a service

sc create MyAppName ...
sc start MyAppName

Windows service runs correctly, but CredentialManager returns the list with a single item "XboxLive" which is the last item on the list in Credential Manager UI. The other credentials are missing. The server runs on my local account with admin rights.

Do you have any idea why it behaves this way?

CredWrite failed with the error code 87.

Hi, Sir I am Prem Murmu, i wrote the main class as mentioned in readme.
This is..

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace webcredential3
{
class mainclasscredential
{
public static void Main(string[] args)
{

     //CredentialManagerTest obj=new CredentialManagerTest();

        bool save = false;
        var cred = CredentialManager.PromptForCredentials("Some Webservice", ref save, "Please provide credentials", "Credentials for service");


        var cred2 = new NetworkCredential("TestUser", "Pwd");
        CredentialManager.SaveCredentials("TestSystem", cred);
        var cred1 = CredentialManager.GetCredentials("TestSystem");


    }
}

}
but when i run this i am getting an error and unable to fix it.
" CredWrite failed with the error code 87."
this pointing to the method -> CredentialManager.SaveCredentials("TestSystem", cred);
but unable to understand..

Question about GetCredentials() implementation

Following code exists in GetCredentials() implementation in CredentialManager.cs:

                    var ret1 = NativeCode.CredUIParseUserName(user, userBuilder, userBuilder.Capacity, domainBuilder, domainBuilder.Capacity);
                    lastError = Marshal.GetLastWin32Error();

                    //assuming invalid account name to be not meeting condition for CredUIParseUserName
                    //"The name must be in UPN or down-level format, or a certificate"
                    if (ret1 == NativeCode.CredentialUIReturnCodes.InvalidAccountName)
                        userBuilder.Append(user);
                    else if ((uint)ret1 > 0)
                        throw new Win32Exception(lastError, "CredUIParseUserName threw an error");

Can you explain why you execute userBuilder.Append(user) when ret1 is NativeCode.CredentialUIReturnCodes.InvalidAccountName?

Essentially InvalidAccountName is treated as an "OK" outcome and I don't really understand the logic behind that.

CLR Access violation on GetCredentials after saving them with SaveCredentials

Fairly simple, this code

Credential = CredentialManager.GetCredentials(CredentialTarget);

Potential error message:

Exception thrown: 'System.ArgumentOutOfRangeException' in mscorlib.dll

Also this:

Exception thrown at 0x73BDFEC2 (clr.dll) in OdinSyncD.exe: 0xC0000005: Access violation reading location 0x00AF0000.
The Common Language Runtime cannot stop at this exception. Common causes include: incorrect COM interop marshalling and memory corruption. To investigate further use native-only debugging.
Managed Debugging Assistant 'FatalExecutionEngineError' 
The runtime has encountered a fatal error. The address of the error was at 0x73bdfec2, on thread 0x313c. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

This happens whether or not I save the credentials myself or use Adystech. It only seems to happen for certain username/passwords pairings and not others.

I also sometimes get a Error: 0 : Not a valid Win32 FileTime. Parameter name: fileTime

AccessViolationException in CredUiParseUserName

The more my username is long the more I get this exception:

System.AccessViolationException: Tentative de lecture ou d'écriture de mémoire protégée. Cela indique souvent qu'une autre mémoire est endommagée.
  at à AdysTech.CredentialManager.NativeCode.CredUIParseUserName(String userName, StringBuilder user, Int32 userMaxChars, StringBuilder domain, Int32 domainMaxChars)
  at à AdysTech.CredentialManager.CredentialManager.ParseUserName(String usernameBuf, Int32 maxUserName, Int32 maxDomain, String& user, String& domain)
  at à AdysTech.CredentialManager.CredentialManager.PromptForCredentials(String target, CredentialUIInfo credUI, Boolean& save, String& user, String& password, String& domain)
  at à AdysTech.CredentialManager.CredentialManager.PromptForCredentials(String target, Boolean& save, String message, String caption, String& user, String& password, String& domain)
  at à AdysTech.CredentialManager.CredentialManager.PromptForCredentials(String target, Boolean& save, String message, String caption)

When quickly looking at the code it seems pass new empty string builders to the native function while max size is 100:

StringBuilder user1 = new StringBuilder();
StringBuilder domain1 = new StringBuilder();
user = string.Empty;
domain = string.Empty;
NativeCode.CredentialUIReturnCodes userName = NativeCode.CredUIParseUserName(usernameBuf, user1, maxUserName, domain1, maxDomain);

Getting Multiple targets

Hi,

In my application i need to store multiple credentials. Targets will be different like below.
Target "My App:user=Gnana", username=Gnana
Target "My App:user=Jason", username=Jason
Target "My App:user=Ryan", username=Ryan
there is no problem in saving these values. problem is in retrieving the entries. Target name is dynamic based on the username. When i call EnumerateCredentials() without target i get list of all NetworkCredential stored in my machine. From that no way i can filter only the credentials that is specific to my app say target starts with 'My App'.
Since EnumerateCredentials() returns list of NetworkCredential i cannot able to find the target on this.
If i can able to directly enumerate ICredential then it would have satisfied my requirement.
Another way we can do it?

Thanks
Gnana

Password is exposed in the process memory after saving in the Windows credentials storage

bool save = false;
NetworkCredential nc = new NetworkCredential();
nc.UserName = inputWindow.userTextBox.Text;
nc.SecurePassword = authSecureString;
AdysTech.CredentialManager.CredentialManager.SaveCredentials(assemblyName, nc);
nc = null;

Hello.
After SaveCredentials(...) is called, I can find an exposed password in the process memory with Cheat Engine 7.0. Before that moment I can't find the password with Cheat Engine, until I request the NetworkCredential.Password property's value.
The authSecureString is an instance of the System.Security.SecureString class.
There is the same situation with the "CredentialManagement" by iLya Lozovyy.

Additional initialization needed on Windows Server 2008 R2

File: CredentialManager.cs,
function: private static bool PromptForCredentials(string target, NativeCode.CredentialUIInfo credUI, ref bool save, out string user, out string password, out string domain)

On Windows 10 and Windows Server 2016 this works fine the way it is now but on Windows Server 2008 R2 dialog to enter credentials never appears and following exception is thrown:

System.NullReferenceException: Object reference not set to an instance of an object.
at AdysTech.CredentialManager.Credential..ctor(NetworkCredential credential)
at AdysTech.CredentialManager.CredentialManager.SaveCredentials(String Target, NetworkCredential credential)

I found this SO post related to this issue: https://stackoverflow.com/questions/25885369/windows-api-function-creduipromptforwindowscredentials-also-returns-an-error-of

The SO post is for C++, for C# following needs to be added after credUI.cbSize = Marshal.SizeOf(credUI);

        credUI.hwndParent = IntPtr.Zero;
        credUI.pszMessageText = "User Credentials";
        credUI.pszCaptionText = "Enter User Credentials";
        credUI.hbmBanner = IntPtr.Zero;

Support for other credential types

Will there be support for other credential types other than generic ? Nice if there could be an option for that.
Reading a credential already saved in other than generic category, leads to a program crash.

CRED_MAX_CREDENTIAL_BLOB_SIZE is now (5*512)

Expected Behavior

SaveCredential can save large tokens. This works if calling the Windows API directly.

Actual Behavior

Credential.cs is forcing credentials to be less than 512 bytes.
if (ncred.CredentialBlobSize > 512)

The Windows 10 SDKs header file, wincred.h sets the CRED_MAX_CREDENTIAL_BLOB_SIZE to 5*512. This allows much bigger passwords such as tokens over 2k to be stored.

Steps to reproduce

     public void TestSaveLongPassword()
     {
         string longPwd = string.Empty.PadRight(1080, '1');
         try
         {
                var cred = new NetworkCredential("AdysTech.CredentialManager.LongPassword", longPwd);
                Assert.IsNotNull(CredentialManager.SaveCredentials("TestSystem", cred), "SaveCredential failed");
         }
         catch (Exception e)
         {
             Assert.Fail("Unexpected exception of type {0} caught: {1}",
             e.GetType(), e.Message);
             return;
         }

Delete Generic Certificate and Domain Password type credentials

Dear all, I am having as per the above object:

I am able to use CredentialManager.RemoveCredentials() method to remove Type: Generic credentials.

But I cannot remove Generic Certificate and Domain Password credential types. I am new to c#, am I missing something?

Thanks in advance

Angelo
image

CredUnPackAuthenticationBuffer() never parses domain name

CredUnPackAuthenticationBuffer() never parses domain name

In file CredentialManager.cs, function private static bool PromptForCredentials(string target, NativeCode.CredentialUIInfo credUI, ref bool save, out string user, out string password, out string domain) makes following call:

if (NativeCode.CredUnPackAuthenticationBuffer(0, outCredBuffer, outCredSize, usernameBuf, ref maxUserName, domainBuf, ref maxDomain, passwordBuf, ref maxPassword))
{
....
}

No matter what I enter ([email protected] or domain1\user444) that call always fails to return anything in domainbuf

How can this be explained?

CredentialManager.GetCredentials() failed

When I want to retrieve credential CredentialManager.GetCredentials() throws an exception:
System.ArgumentOutOfRangeException was unhandled
HResult=-2146233086
Message=Nieprawidłowy element Win32 FileTime.
Nazwa parametru: fileTime
Source=mscorlib
ParamName=fileTime
StackTrace:
w System.DateTime.FromFileTimeUtc(Int64 fileTime)
w System.DateTime.FromFileTime(Int64 fileTime)
w AdysTech.CredentialManager.Credential..ctor(NativeCredential ncred)
w AdysTech.CredentialManager.CriticalCredentialHandle.GetCredential()
w AdysTech.CredentialManager.CredentialManager.GetCredentials(String Target)
w WebDAVPOC.Program.Main(String[] args) w d:\Users\andrzejp\Documents\Visual Studio 2013\Projects\WebDAVPOC\WebDAVPOC\Program.cs:wiersz 20
w System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
w System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
w Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
w System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
w System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
w System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
w System.Threading.ThreadHelper.ThreadStart()
InnerException:

Expose Credential directly

Would it be possible to expose the Credentials directly?

They contain quite some information that doesn't fit inside the NetworkCredential class.

E.g.:

/// <summary>
        /// Enumerate the specified stored credentials in the Windows Credential store
        /// </summary>
        /// <param name="target">Name of the application or URL for which the credential is used</param>
        /// <returns>Return a <see cref="List{NetworkCredential}"/> if success, null if target not found, throw if failed to read stored credentials</returns>
        public static List<Credential> EnumerateCredentialsOriginal(string target = null)
        {
            IntPtr pCredentials = IntPtr.Zero;
            uint count = 0;

            var success = NativeCode.CredEnumerate(target, 0, out count, out pCredentials);

            if (!success)
            {
                var lastError = Marshal.GetLastWin32Error();
                if (lastError == (int)NativeCode.CredentialUIReturnCodes.NotFound)
                {
                    return null;
                }

                throw new Win32Exception(lastError,
                    string.Format("'CredEnumerate' call throw an error (Error code: {0})", lastError));
            }

            List<NetworkCredential> networkCredentials = new List<NetworkCredential>();
            Credential[] credentials;

            try
            {
                using (var criticalSection = new CriticalCredentialHandle(pCredentials))
                {
                    credentials = criticalSection.EnumerateCredentials(count);
                }
            }
            catch (Exception)
            {
                return null;
            }

            return credentials.ToList();
        }

Main class for CredentialManager

hi, I am Prem Murmu, New for .net programmer, I need this program main class or method to execute the code.
Thanks for advance..

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.