private static bool WriteCredential(string key, string userName, string secret) { var byteArray = Encoding.Unicode.GetBytes(secret); if (byteArray.Length > 512) { throw new ArgumentOutOfRangeException("secret", "The secret message has exceeded 512 bytes."); } var cred = new CredUi.Credential(); cred.TargetName = key; cred.UserName = userName; cred.CredentialBlob = secret; cred.CredentialBlobSize = (UInt32)Encoding.Unicode.GetBytes(secret).Length; cred.AttributeCount = 0; cred.Attributes = IntPtr.Zero; cred.Comment = null; cred.TargetAlias = null; cred.Type = CredUi.CredTypes.CRED_TYPE_GENERIC; cred.Persist = CredUi.IsWindowsVistaOrEarlier ? CredUi.CredPersistance.Session : CredUi.CredPersistance.LocalMachine; var ncred = CredUi.NativeCredential.GetNativeCredential(cred); var written = CredUi.CredWrite(ref ncred, 0); var lastError = Marshal.GetLastWin32Error(); if (!written) { var message = string.Format("CredWrite failed with the error code {0}.", lastError); throw new CredentialException(lastError, message); } return(true); }
private static CredUi.SimpleCredentials ReadCredential(string key) { IntPtr nCredPtr; var read = CredUi.CredRead(key, CredUi.CredTypes.CRED_TYPE_GENERIC, 0, out nCredPtr); var lastError = Marshal.GetLastWin32Error(); if (!read) { if (lastError == (int)CredUi.CredUIReturnCodes.ERROR_NOT_FOUND) { return(null); } else { throw new CredentialException(lastError); } } var credential = new CredUi.SimpleCredentials(); using (var criticalCredentialHandle = new CredUi.CriticalCredentialHandle(nCredPtr)) { var cred = criticalCredentialHandle.GetCredential(); credential.UserName = cred.UserName; credential.Password = cred.CredentialBlob; } return(credential); }
private bool DeleteCredential(string key) { Argument.IsNotNullOrWhitespace(() => key); var found = false; Log.Debug("Deleting credentials with key '{0}'", key); if (CredUi.CredDelete(key, CredUi.CredTypes.CRED_TYPE_GENERIC, 0)) { Log.Debug("Successfully deleted credentials"); found = true; } else { var error = Marshal.GetLastWin32Error(); if (error != (int)CredUi.CredUiReturnCodes.ERROR_NOT_FOUND) { throw Log.ErrorAndCreateException(x => new CredentialException(error), "Failed to delete credentials, error code '{0}'", error); } } return(found); }
private void WriteCredential(string key, string userName, string secret) { if (_credentialStoragePolicy == CredentialStoragePolicy.None) { Log.Debug("Writing credentials disabled according to used storage policy"); return; } if (_credentialStoragePolicy == CredentialStoragePolicy.Configuration) { Log.Debug("Force writing credentials to configuration"); WriteCredentialToConfiguration(key, userName, secret); return; } var byteArray = Encoding.Unicode.GetBytes(secret); if (byteArray.Length > 512) { throw Log.ErrorAndCreateException(x => new ArgumentOutOfRangeException(nameof(secret), x), "The secret message has exceeded 512 bytes."); } Log.Debug("Writing credentials with username '{0}' for key '{1}'", userName, key); var cred = new CredUi.Credential { TargetName = key, UserName = userName, CredentialBlob = secret, CredentialBlobSize = (uint)Encoding.Unicode.GetBytes(secret).Length, AttributeCount = 0, Attributes = IntPtr.Zero, Comment = null, TargetAlias = null, Type = CredUi.CredTypes.CRED_TYPE_GENERIC, Persist = CredUi.IsWindowsVistaOrEarlier ? CredUi.CredPersistance.Session : CredUi.CredPersistance.LocalMachine }; Log.Debug("Persisting credentials as '{0}'", cred.Persist); var ncred = CredUi.NativeCredential.GetNativeCredential(cred); var written = CredUi.CredWrite(ref ncred, 0); var lastError = Marshal.GetLastWin32Error(); if (!written) { throw Log.ErrorAndCreateException(x => new CredentialException(lastError, x), "CredWrite failed with the error code '{0}'", lastError); } // Note: immediately read it for ORCOMP-229 var credential = ReadCredential(key, false); if ((credential is null || string.IsNullOrWhiteSpace(credential.Password)) && _credentialStoragePolicy == CredentialStoragePolicy.WindowsVaultConfigurationFallback) { WriteCredentialToConfiguration(key, cred.UserName, secret); } Log.Debug("Successfully written credentials for key '{0}'", key); }
private bool WriteCredential(string key, string userName, string secret) { var byteArray = Encoding.Unicode.GetBytes(secret); if (byteArray.Length > 512) { throw Log.ErrorAndCreateException(x => new ArgumentOutOfRangeException("secret", x), "The secret message has exceeded 512 bytes."); } Log.Debug("Writing credentials with username '{0}' for key '{1}'", userName, key); var cred = new CredUi.Credential(); cred.TargetName = key; cred.UserName = userName; cred.CredentialBlob = secret; cred.CredentialBlobSize = (uint)Encoding.Unicode.GetBytes(secret).Length; cred.AttributeCount = 0; cred.Attributes = IntPtr.Zero; cred.Comment = null; cred.TargetAlias = null; cred.Type = CredUi.CredTypes.CRED_TYPE_GENERIC; cred.Persist = CredUi.IsWindowsVistaOrEarlier ? CredUi.CredPersistance.Session : CredUi.CredPersistance.LocalMachine; Log.Debug("Persisting credentials as '{0}'", cred.Persist); var ncred = CredUi.NativeCredential.GetNativeCredential(cred); var written = CredUi.CredWrite(ref ncred, 0); var lastError = Marshal.GetLastWin32Error(); if (!written) { throw Log.ErrorAndCreateException(x => new CredentialException(lastError, x), "CredWrite failed with the error code '{0}'", lastError); } // Note: immediately read it for ORCOMP-229 var credential = ReadCredential(key, false); if (credential == null || string.IsNullOrWhiteSpace(credential.Password)) { var configurationKey = GetPasswordConfigurationKey(key, cred.UserName); var encryptionKey = GetEncryptionKey(key, cred.UserName); Log.Debug("Failed to write credentials to vault, probably a company policy. Falling back to writing configuration key '{0}'", configurationKey); var encryptedPassword = EncryptionHelper.Encrypt(secret, encryptionKey); _configurationService.SetRoamingValue(configurationKey, encryptedPassword); } Log.Debug("Successfully written credentials for key '{0}'", key); return(true); }
private bool PromptForCredentials(IntPtr owner, bool storedCredentials, ref IntPtr inBuffer, ref IntPtr outBuffer) { var info = CreateCredUIInfo(owner, false); var flags = CredUi.PromptForWindowsCredentials.Generic; if (ShowSaveCheckBox) { flags |= CredUi.PromptForWindowsCredentials.Checkbox; } uint inBufferSize = 0; if (UserName.Length > 0) { // First call is only to get the required buffer size CredUi.CredPackAuthenticationBuffer(0, UserName, Password, IntPtr.Zero, ref inBufferSize); if (inBufferSize > 0) { inBuffer = Marshal.AllocCoTaskMem((int)inBufferSize); if (!CredUi.CredPackAuthenticationBuffer(0, UserName, Password, inBuffer, ref inBufferSize)) { throw Log.ErrorAndCreateException(x => new CredentialException(Marshal.GetLastWin32Error()), "Failed to create the authentication buffer before prompting"); } } } uint package = 0; Log.Debug("Prompting user for credentials"); var result = CredUi.CredUIPromptForWindowsCredentials(ref info, 0, ref package, inBuffer, inBufferSize, out outBuffer, out var outBufferSize, ref _isSaveChecked, flags); switch (result) { case CredUi.CredUiReturnCodes.NO_ERROR: ManageCredentialsStorage(outBuffer, outBufferSize, storedCredentials); return(true); case CredUi.CredUiReturnCodes.ERROR_CANCELLED: Log.Debug("User canceled the credentials prompt"); return(false); default: throw Log.ErrorAndCreateException(x => new CredentialException((int)result), "Failed to prompt for credentials, error code '{0}'", result); } }
private static bool DeleteCredential(string key) { Argument.IsNotNullOrWhitespace(() => key); var found = false; if (CredUi.CredDelete(key, CredUi.CredTypes.CRED_TYPE_GENERIC, 0)) { found = true; } else { var error = Marshal.GetLastWin32Error(); if (error != (int)CredUi.CredUiReturnCodes.ERROR_NOT_FOUND) { throw new CredentialException(error); } } return(found); }
private void ManageCredentialsStorage(IntPtr outBuffer, uint outBufferSize, bool storedCredentials) { var userName = new StringBuilder(CredUi.CREDUI_MAX_USERNAME_LENGTH); var password = new StringBuilder(CredUi.CREDUI_MAX_PASSWORD_LENGTH); var userNameSize = (uint)userName.Capacity; var passwordSize = (uint)password.Capacity; uint domainSize = 0; if (!CredUi.CredUnPackAuthenticationBuffer(0, outBuffer, outBufferSize, userName, ref userNameSize, null, ref domainSize, password, ref passwordSize)) { throw Log.ErrorAndCreateException(x => new CredentialException(Marshal.GetLastWin32Error()), "Failed to create the authentication buffer after prompting"); } UserName = userName.ToString(); Password = password.ToString(); Log.Debug("User entered credentials with username '{0}'", UserName); if (!ShowSaveCheckBox) { return; } // If the NativeCredential was stored previously but the user has now cleared the save checkbox, // we want to delete the NativeCredential. if (storedCredentials && !IsSaveChecked) { DeleteCredential(Target); } if (IsSaveChecked) { WriteCredential(Target, UserName, Password); } }
private CredUi.SimpleCredentials ReadCredential(string key, bool allowConfigurationFallback) { Log.Debug("Trying to read credentials for key '{0}'", key); // Immediately return if saved credentials disabled by policy if (_credentialStoragePolicy == CredentialStoragePolicy.None) { return(null); } var credential = new CredUi.SimpleCredentials(); if (_credentialStoragePolicy == CredentialStoragePolicy.Configuration) { ReadCredentialFromConfiguration(key, credential); return(credential); } var read = CredUi.CredRead(key, CredUi.CredTypes.CRED_TYPE_GENERIC, 0, out var nCredPtr); var lastError = Marshal.GetLastWin32Error(); if (!read) { if (lastError == (int)CredUi.CredUIReturnCodes.ERROR_NOT_FOUND) { Log.Debug("Failed to read credentials, credentials are not found"); return(null); } throw Log.ErrorAndCreateException(x => new CredentialException(lastError), "Failed to read credentials, error code is '{0}'", lastError); } using (var criticalCredentialHandle = new CredUi.CriticalCredentialHandle(nCredPtr)) { var cred = criticalCredentialHandle.GetCredential(); Log.Debug("Retrieved credentials: {0}", cred); credential.UserName = cred.UserName; credential.Password = cred.CredentialBlob; // Some company policies don't allow us reading the credentials, so // that results in an empty password being returned if (string.IsNullOrWhiteSpace(credential.Password)) { if (allowConfigurationFallback) { try { ReadCredentialFromConfiguration(key, credential); } catch (Exception ex) { Log.Error(ex, "Failed to read credentials from alternative configuration"); } } if (string.IsNullOrWhiteSpace(credential.Password)) { // We failed to read credentials from both vault and configuration return(null); } } } return(credential); }
private bool PromptForCredentialsCredUIWin(IntPtr owner, bool storedCredentials) { if (AllowStoredCredentials) { var credentials = ReadCredential(Target); if (credentials != null) { UserName = credentials.UserName; Password = credentials.Password; return(true); } } if (!IsAuthenticationRequired) { return(false); } var info = CreateCredUIInfo(owner, false); var flags = CredUi.CredUiWinFlags.Generic; if (ShowSaveCheckBox) { flags |= CredUi.CredUiWinFlags.Checkbox; } var inBuffer = IntPtr.Zero; var outBuffer = IntPtr.Zero; try { uint inBufferSize = 0; if (UserName.Length > 0) { CredUi.CredPackAuthenticationBuffer(0, UserName, Password, IntPtr.Zero, ref inBufferSize); if (inBufferSize > 0) { inBuffer = Marshal.AllocCoTaskMem((int)inBufferSize); if (!CredUi.CredPackAuthenticationBuffer(0, UserName, Password, inBuffer, ref inBufferSize)) { throw new CredentialException(Marshal.GetLastWin32Error()); } } } uint outBufferSize = 0; uint package = 0; var result = CredUi.CredUIPromptForWindowsCredentials(ref info, 0, ref package, inBuffer, inBufferSize, out outBuffer, out outBufferSize, ref _isSaveChecked, flags); switch (result) { case CredUi.CredUiReturnCodes.NO_ERROR: var userName = new StringBuilder(CredUi.CREDUI_MAX_USERNAME_LENGTH); var password = new StringBuilder(CredUi.CREDUI_MAX_PASSWORD_LENGTH); var userNameSize = (uint)userName.Capacity; var passwordSize = (uint)password.Capacity; uint domainSize = 0; if (!CredUi.CredUnPackAuthenticationBuffer(0, outBuffer, outBufferSize, userName, ref userNameSize, null, ref domainSize, password, ref passwordSize)) { throw new CredentialException(Marshal.GetLastWin32Error()); } UserName = userName.ToString(); Password = password.ToString(); if (ShowSaveCheckBox) { _confirmTarget = Target; // If the NativeCredential was stored previously but the user has now cleared the save checkbox, // we want to delete the NativeCredential. if (storedCredentials && !IsSaveChecked) { DeleteCredential(Target); } if (IsSaveChecked) { WriteCredential(Target, UserName, Password); } } return(true); case CredUi.CredUiReturnCodes.ERROR_CANCELLED: return(false); default: throw new CredentialException((int)result); } } finally { if (inBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(inBuffer); } if (outBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(outBuffer); } } }
private CredUi.SimpleCredentials ReadCredential(string key, bool allowConfigurationFallback) { Log.Debug("Trying to read credentials for key '{0}'", key); var read = CredUi.CredRead(key, CredUi.CredTypes.CRED_TYPE_GENERIC, 0, out var nCredPtr); var lastError = Marshal.GetLastWin32Error(); if (!read) { if (lastError == (int)CredUi.CredUIReturnCodes.ERROR_NOT_FOUND) { Log.Debug("Failed to read credentials, credentials are not found"); return(null); } throw Log.ErrorAndCreateException(x => new CredentialException(lastError), "Failed to read credentials, error code is '{0}'", lastError); } var credential = new CredUi.SimpleCredentials(); using (var criticalCredentialHandle = new CredUi.CriticalCredentialHandle(nCredPtr)) { var cred = criticalCredentialHandle.GetCredential(); Log.Debug("Retrieved credentials: {0}", cred); credential.UserName = cred.UserName; credential.Password = cred.CredentialBlob; // Some company policies don't allow us reading the credentials, so // that results in an empty password being returned if (string.IsNullOrWhiteSpace(credential.Password)) { if (allowConfigurationFallback) { try { var configurationKey = GetPasswordConfigurationKey(key, credential.UserName); var encryptionKey = GetEncryptionKey(key, credential.UserName); Log.Debug("Failed to read credentials from vault, probably a company policy. Falling back to reading configuration key '{0}'", configurationKey); var encryptedPassword = _configurationService.GetRoamingValue(configurationKey, string.Empty); if (!string.IsNullOrWhiteSpace(encryptedPassword)) { var decryptedPassword = EncryptionHelper.Decrypt(encryptedPassword, encryptionKey); credential.Password = decryptedPassword; } } catch (Exception ex) { Log.Error(ex, "Failed to read credentials from alternative configuration"); } } if (string.IsNullOrWhiteSpace(credential.Password)) { // We failed to read credentials from both vault and configuration return(null); } } } return(credential); }
private bool PromptForCredentialsCredUIWin(IntPtr owner, bool storedCredentials) { if (AllowStoredCredentials) { Log.Debug("Stored credentials are allowed"); var credentials = ReadCredential(Target, true); if (credentials != null) { Log.Debug("Successfully read stored credentials: '{0}'", credentials); UserName = credentials.UserName; Password = credentials.Password; return(true); } } if (!IsAuthenticationRequired) { Log.Debug("No authentication is required, no need to prompt for credentials"); return(false); } var info = CreateCredUIInfo(owner, false); var flags = CredUi.CredUiWinFlags.Generic; if (ShowSaveCheckBox) { flags |= CredUi.CredUiWinFlags.Checkbox; } var inBuffer = IntPtr.Zero; var outBuffer = IntPtr.Zero; try { uint inBufferSize = 0; if (UserName.Length > 0) { // First call is only to get the required buffer size CredUi.CredPackAuthenticationBuffer(0, UserName, Password, IntPtr.Zero, ref inBufferSize); if (inBufferSize > 0) { inBuffer = Marshal.AllocCoTaskMem((int)inBufferSize); if (!CredUi.CredPackAuthenticationBuffer(0, UserName, Password, inBuffer, ref inBufferSize)) { throw Log.ErrorAndCreateException(x => new CredentialException(Marshal.GetLastWin32Error()), "Failed to create the authentication buffer before prompting"); } } } uint outBufferSize = 0; uint package = 0; Log.Debug("Prompting user for credentials"); var result = CredUi.CredUIPromptForWindowsCredentials(ref info, 0, ref package, inBuffer, inBufferSize, out outBuffer, out outBufferSize, ref _isSaveChecked, flags); switch (result) { case CredUi.CredUiReturnCodes.NO_ERROR: var userName = new StringBuilder(CredUi.CREDUI_MAX_USERNAME_LENGTH); var password = new StringBuilder(CredUi.CREDUI_MAX_PASSWORD_LENGTH); var userNameSize = (uint)userName.Capacity; var passwordSize = (uint)password.Capacity; uint domainSize = 0; if (!CredUi.CredUnPackAuthenticationBuffer(0, outBuffer, outBufferSize, userName, ref userNameSize, null, ref domainSize, password, ref passwordSize)) { throw Log.ErrorAndCreateException(x => new CredentialException(Marshal.GetLastWin32Error()), "Failed to create the authentication buffer after prompting"); } UserName = userName.ToString(); Password = password.ToString(); Log.Debug("User entered credentials with username '{0}'", UserName); if (ShowSaveCheckBox) { _confirmTarget = Target; // If the NativeCredential was stored previously but the user has now cleared the save checkbox, // we want to delete the NativeCredential. if (storedCredentials && !IsSaveChecked) { DeleteCredential(Target); } if (IsSaveChecked) { WriteCredential(Target, UserName, Password); } } return(true); case CredUi.CredUiReturnCodes.ERROR_CANCELLED: Log.Debug("User canceled the credentials prompt"); return(false); default: throw Log.ErrorAndCreateException(x => new CredentialException((int)result), "Failed to prompt for credentials, error code '{0}'", result); } } finally { if (inBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(inBuffer); } if (outBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(outBuffer); } } }