private CredUi.SimpleCredentials ReadCredential(string key, bool allowConfigurationFallback)
{
IntPtr nCredPtr;
Log.Debug("Trying to read credentials for key '{0}'", key);
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)
{
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;
}