MSAL encrypted file system cache (#1945)

This commit is contained in:
Cheena Malhotra
2023-03-16 11:56:35 -07:00
committed by GitHub
parent f6fbceb5a0
commit 4d9cb17c93
11 changed files with 568 additions and 100 deletions

View File

@@ -0,0 +1,41 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.Authentication.Utility
{
/// <summary>
/// Configuration used by <see cref="Authenticator"/> to perform AAD authentication using MSAL.NET
/// </summary>
public class AuthenticatorConfiguration
{
/// <summary>
/// Application Client ID to be used.
/// </summary>
public string AppClientId { get; set; }
/// <summary>
/// Application name used for public client application instantiation.
/// </summary>
public string AppName { get; set; }
/// <summary>
/// Cache folder path, to be used by MSAL.NET to store encrypted token cache.
/// </summary>
public string CacheFolderPath { get; set; }
/// <summary>
/// File name to be used for token storage.
/// Full path of file: <see cref="CacheFolderPath"/> \ <see cref="CacheFileName"/>
/// </summary>
public string CacheFileName { get; set; }
public AuthenticatorConfiguration(string appClientId, string appName, string cacheFolderPath, string cacheFileName) {
AppClientId = appClientId;
AppName = appName;
CacheFolderPath = cacheFolderPath;
CacheFileName = cacheFileName;
}
}
}

View File

@@ -0,0 +1,76 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Security.Cryptography;
namespace Microsoft.SqlTools.Authentication.Utility
{
public static class EncryptionUtils
{
/// <summary>
/// Encrypts provided byte array with 'aes-256-cbc' algorithm.
/// </summary>
/// <param name="plainText">Plain text data</param>
/// <param name="key">Encryption Key</param>
/// <param name="iv">Encryption IV</param>
/// <returns>Encrypted data in bytes</returns>
/// <exception cref="ArgumentNullException">When arguments are null or empty.</exception>
public static byte[] AesEncrypt(byte[] plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
{
throw new ArgumentNullException(nameof(plainText));
}
using var aes = CreateAes(key, iv);
using var encryptor = aes.CreateEncryptor();
return encryptor.TransformFinalBlock(plainText, 0, plainText.Length);
}
/// <summary>
/// Decrypts provided byte array with 'aes-256-cbc' algorithm.
/// </summary>
/// <param name="cipherText">Encrypted data</param>
/// <param name="key">Encryption Key</param>
/// <param name="iv">Encryption IV</param>
/// <returns>Plain text data in bytes</returns>
/// <exception cref="ArgumentNullException">When arguments are null or empty.</exception>
public static byte[] AesDecrypt(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
{
throw new ArgumentNullException(nameof(cipherText));
}
using var aes = CreateAes(key, iv);
using var decryptor = aes.CreateDecryptor();
return decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);
}
private static Aes CreateAes(byte[] key, byte[] iv)
{
// Check arguments.
if (key == null || key.Length <= 0)
{
throw new ArgumentNullException(nameof(key));
}
if (iv == null || iv.Length <= 0)
{
throw new ArgumentNullException(nameof(iv));
}
var aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Key = key;
aes.IV = iv;
return aes;
}
}
}

View File

@@ -4,7 +4,6 @@
//
using System.Net.Mail;
using System.Runtime.InteropServices;
using Microsoft.Identity.Client;
using SqlToolsLogger = Microsoft.SqlTools.Utility.Logger;
@@ -30,59 +29,6 @@ namespace Microsoft.SqlTools.Authentication.Utility
}
}
/// <summary>
/// Builds directory path based on environment settings.
/// </summary>
/// <returns>Application directory path</returns>
/// <exception cref="Exception">When called on unsupported platform.</exception>
public static string BuildAppDirectoryPath()
{
var homedir = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
// Windows
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var appData = Environment.GetEnvironmentVariable("APPDATA");
var userProfile = Environment.GetEnvironmentVariable("USERPROFILE");
if (appData != null)
{
return appData;
}
else if (userProfile != null)
{
return string.Join(Environment.GetEnvironmentVariable("USERPROFILE"), "AppData", "Roaming");
}
else
{
throw new Exception("Not able to find APPDATA or USERPROFILE");
}
}
// Mac
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return string.Join(homedir, "Library", "Application Support");
}
// Linux
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
var xdgConfigHome = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
if (xdgConfigHome != null)
{
return xdgConfigHome;
}
else
{
return string.Join(homedir, ".config");
}
}
else
{
throw new Exception("Platform not supported");
}
}
/// <summary>
/// Log callback handler used for MSAL Client applications.
/// </summary>