using System.ComponentModel; using System.Runtime.InteropServices; namespace ZA.CoreService.ESBCertificateManager.Services; public sealed class WindowsCredentialManagerSecretProvider : ISecretProvider { private const uint GenericCredentialType = 1; private const int ErrorNotFound = 1168; public StoredCredential GetCredential( string credentialReference) { if (string.IsNullOrWhiteSpace(credentialReference)) { throw new ArgumentException( "Die CredentialReference ist nicht konfiguriert.", nameof(credentialReference)); } bool success = CredRead( credentialReference, GenericCredentialType, 0, out IntPtr credentialPointer); if (!success) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == ErrorNotFound) { throw new InvalidOperationException( $"Die Windows-Anmeldeinformation " + $"'{credentialReference}' wurde nicht gefunden."); } throw new Win32Exception( errorCode, "Die Windows-Anmeldeinformation konnte nicht gelesen werden."); } try { NativeCredential nativeCredential = Marshal.PtrToStructure( credentialPointer); string userName = Marshal.PtrToStringUni(nativeCredential.UserName) ?? string.Empty; string secret = string.Empty; if (nativeCredential.CredentialBlob != IntPtr.Zero && nativeCredential.CredentialBlobSize > 0) { int characterCount = checked( (int)nativeCredential.CredentialBlobSize / 2); secret = Marshal.PtrToStringUni( nativeCredential.CredentialBlob, characterCount) ?? string.Empty; } if (string.IsNullOrWhiteSpace(userName)) { throw new InvalidOperationException( $"Die Windows-Anmeldeinformation " + $"'{credentialReference}' enthält keinen Benutzernamen."); } if (string.IsNullOrEmpty(secret)) { throw new InvalidOperationException( $"Die Windows-Anmeldeinformation " + $"'{credentialReference}' enthält kein Kennwort."); } return new StoredCredential( userName, secret); } finally { CredFree(credentialPointer); } } [DllImport( "advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CredRead( string target, uint type, int reservedFlag, out IntPtr credentialPointer); [DllImport("advapi32.dll")] private static extern void CredFree( IntPtr credentialPointer); [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct NativeCredential { public uint Flags; public uint Type; public IntPtr TargetName; public IntPtr Comment; public long LastWritten; public uint CredentialBlobSize; public IntPtr CredentialBlob; public uint Persist; public uint AttributeCount; public IntPtr Attributes; public IntPtr TargetAlias; public IntPtr UserName; } }