Example #1
0
        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);
        }
Example #2
0
        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);
            }
        }
Example #7
0
        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);
        }
Example #10
0
        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);
                }
            }
        }
Example #11
0
        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);
                }
            }
        }