Skip to content

Commit 6b227ba

Browse files
author
msJinLei
committed
Store secrets to encrypted storage
1 parent ba2086f commit 6b227ba

19 files changed

+772
-36
lines changed

src/Accounts/Accounts.Test/AutosaveTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
using Xunit.Abstractions;
2323
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
2424
using System;
25+
using System.Security;
2526
using Microsoft.Azure.Commands.Profile.Context;
2627
using Microsoft.Azure.Commands.ScenarioTest;
2728
using Microsoft.Azure.Commands.ResourceManager.Common;
2829
using Microsoft.Azure.Commands.TestFx.Mocks;
30+
using Moq;
2931

3032
namespace Microsoft.Azure.Commands.Profile.Test
3133
{
@@ -41,6 +43,18 @@ public AutosaveTests(ITestOutputHelper output)
4143
ResetState();
4244
}
4345

46+
private void SetMockedAzKeyStore()
47+
{
48+
var storageMocker = new Mock<IStorage>();
49+
storageMocker.Setup(f => f.Create()).Returns(storageMocker.Object);
50+
storageMocker.Setup(f => f.ReadData()).Returns(new byte[0]);
51+
var keyStore = new AzKeyStore(AzureSession.Instance.ARMProfileDirectory, "keystore.cache", false, false, storageMocker.Object);
52+
AzKeyStore.RegisterJsonConverter(typeof(ServicePrincipalKey), typeof(ServicePrincipalKey).Name);
53+
AzKeyStore.RegisterJsonConverter(typeof(SecureString), typeof(SecureString).Name, new SecureStringConverter());
54+
AzureSession.Instance.RegisterComponent(AzKeyStore.Name, () => keyStore);
55+
keyStore.LoadStorage();
56+
}
57+
4458
void ResetState()
4559
{
4660

@@ -54,6 +68,7 @@ void ResetState()
5468
Environment.SetEnvironmentVariable("Azure_PS_Data_Collection", "false");
5569
PowerShellTokenCacheProvider tokenProvider = new InMemoryTokenCacheProvider();
5670
AzureSession.Instance.RegisterComponent(PowerShellTokenCacheProvider.PowerShellTokenCacheProviderKey, () => tokenProvider, true);
71+
SetMockedAzKeyStore();
5772
}
5873

5974
[Fact]

src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
using Microsoft.Azure.PowerShell.Common.Config;
4242
using Microsoft.Identity.Client;
4343
using Microsoft.WindowsAzure.Commands.Common;
44-
using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
4544
using Microsoft.WindowsAzure.Commands.Common.Utilities;
4645
using Microsoft.WindowsAzure.Commands.Utilities.Common;
4746
using Microsoft.Azure.PowerShell.Common.Share.Survey;
@@ -426,7 +425,6 @@ public override void ExecuteCmdlet()
426425
azureAccount.SetProperty(AzureAccount.Property.CertificatePath, resolvedPath);
427426
if (CertificatePassword != null)
428427
{
429-
azureAccount.SetProperty(AzureAccount.Property.CertificatePassword, CertificatePassword.ConvertToString());
430428
keyStore?.SaveKey(new ServicePrincipalKey(AzureAccount.Property.CertificatePassword, azureAccount.Id, Tenant), CertificatePassword);
431429
}
432430
}
@@ -449,7 +447,6 @@ public override void ExecuteCmdlet()
449447

450448
if (azureAccount.Type == AzureAccount.AccountType.ServicePrincipal && password != null)
451449
{
452-
azureAccount.SetProperty(AzureAccount.Property.ServicePrincipalSecret, password.ConvertToString());
453450
keyStore?.SaveKey(new ServicePrincipalKey(AzureAccount.Property.ServicePrincipalSecret
454451
,azureAccount.Id, Tenant), password);
455452
if (GetContextModificationScope() == ContextModificationScope.CurrentUser)
@@ -713,16 +710,23 @@ public void OnImport()
713710
WriteInitializationWarnings(Resources.FallbackContextSaveModeDueCacheCheckError.FormatInvariant(ex.Message));
714711
}
715712

716-
if(!InitializeProfileProvider(autoSaveEnabled))
713+
AzKeyStore keyStore = null;
714+
//AzureSession.Instance.KeyStoreFile
715+
keyStore = new AzKeyStore(AzureSession.Instance.ARMProfileDirectory, "keystore.cache", false, autoSaveEnabled);
716+
AzKeyStore.RegisterJsonConverter(typeof(ServicePrincipalKey), typeof(ServicePrincipalKey).Name);
717+
AzKeyStore.RegisterJsonConverter(typeof(SecureString), typeof(SecureString).Name, new SecureStringConverter());
718+
AzureSession.Instance.RegisterComponent(AzKeyStore.Name, () => keyStore);
719+
720+
if (!InitializeProfileProvider(autoSaveEnabled))
717721
{
718722
AzureSession.Instance.ARMContextSaveMode = ContextSaveMode.Process;
719723
autoSaveEnabled = false;
720724
}
721725

722-
#pragma warning disable CS0618 // Type or member is obsolete
723-
var keyStore = new AzKeyStore(AzureRmProfileProvider.Instance.Profile);
724-
#pragma warning restore CS0618 // Type or member is obsolete
725-
AzureSession.Instance.RegisterComponent(AzKeyStore.Name, () => keyStore);
726+
if (!keyStore.LoadStorage())
727+
{
728+
WriteInitializationWarnings(Resources.KeyStoreLoadingError);
729+
}
726730

727731
IAuthenticatorBuilder builder = null;
728732
if (!AzureSession.Instance.TryGetComponent(AuthenticatorBuilder.AuthenticatorBuilderKey, out builder))

src/Accounts/Accounts/AutoSave/DisableAzureRmContextAutosave.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ void DisableAutosave(IAzureSession session, bool writeAutoSaveFile, out ContextA
9292
builder.Reset();
9393
}
9494

95+
if (AzureSession.Instance.TryGetComponent(AzKeyStore.Name, out AzKeyStore keystore))
96+
{
97+
keystore.DisableAutoSaving();
98+
}
99+
95100
if (writeAutoSaveFile)
96101
{
97102
FileUtilities.EnsureDirectoryExists(session.ProfileDirectory);

src/Accounts/Accounts/AutoSave/EnableAzureRmContextAutosave.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ void EnableAutosave(IAzureSession session, bool writeAutoSaveFile, out ContextAu
102102
AzureSession.Instance.RegisterComponent(PowerShellTokenCacheProvider.PowerShellTokenCacheProviderKey, () => newCacheProvider, true);
103103
}
104104

105+
if (AzureSession.Instance.TryGetComponent(AzKeyStore.Name, out AzKeyStore keystore))
106+
{
107+
keystore.Flush();
108+
keystore.DisableAutoSaving();
109+
}
110+
105111

106112
if (writeAutoSaveFile)
107113
{

src/Accounts/Accounts/Properties/Resources.Designer.cs

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Accounts/Accounts/Properties/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,4 +571,7 @@
571571
<value>The command {0} is part of Azure PowerShell module "{1}" and it is not installed. Run "Install-Module {1}" to install it.</value>
572572
<comment>0: command being not found; 1: its module</comment>
573573
</data>
574+
<data name="KeyStoreLoadingError" xml:space="preserve">
575+
<value>KeyStore cannot be loaded from storage. Please check the keystore file integrity or system compablity. The functions relate to context autosaving may be affected.</value>
576+
</data>
574577
</root>

src/Accounts/Authentication.ResourceManager/AzureRmProfile.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using Microsoft.Azure.Commands.Common.Authentication.ResourceManager.Properties;
2626
using Microsoft.Azure.Commands.ResourceManager.Common;
2727
using Microsoft.Azure.Commands.ResourceManager.Common.Serialization;
28+
using Microsoft.WindowsAzure.Commands.Common;
2829

2930
using Newtonsoft.Json;
3031

@@ -205,15 +206,39 @@ private void Initialize(AzureRmProfile profile)
205206
EnvironmentTable[environment.Key] = environment.Value;
206207
}
207208

209+
AzKeyStore keystore = null;
210+
AzureSession.Instance.TryGetComponent(AzKeyStore.Name, out keystore);
211+
208212
foreach (var context in profile.Contexts)
209213
{
210-
this.Contexts.Add(context.Key, context.Value);
214+
this.Contexts.Add(context.Key, MigrateSecretToKeyStore(context.Value, keystore));
211215
}
212216

213217
DefaultContextKey = profile.DefaultContextKey ?? (profile.Contexts.Any() ? null : "Default");
214218
}
215219
}
216220

221+
private IAzureContext MigrateSecretToKeyStore(IAzureContext context, AzKeyStore keystore)
222+
{
223+
if (keystore != null)
224+
{
225+
var account = context.Account;
226+
if (account.IsPropertySet(AzureAccount.Property.ServicePrincipalSecret))
227+
{
228+
keystore?.SaveKey(new ServicePrincipalKey(AzureAccount.Property.ServicePrincipalSecret, account.Id, account.GetTenants().First())
229+
, account.ExtendedProperties.GetProperty(AzureAccount.Property.ServicePrincipalSecret).ConvertToSecureString());
230+
account.ExtendedProperties.Remove(AzureAccount.Property.ServicePrincipalSecret);
231+
}
232+
if (account.IsPropertySet(AzureAccount.Property.CertificatePassword))
233+
{
234+
keystore?.SaveKey(new ServicePrincipalKey(AzureAccount.Property.CertificatePassword, account.Id, account.GetTenants().First())
235+
, account.ExtendedProperties.GetProperty(AzureAccount.Property.CertificatePassword).ConvertToSecureString());
236+
account.ExtendedProperties.Remove(AzureAccount.Property.CertificatePassword);
237+
}
238+
}
239+
return context;
240+
}
241+
217242
private void LoadImpl(string contents)
218243
{
219244
}
@@ -311,6 +336,10 @@ public void Save(IFileProvider provider, bool serializeCache = true)
311336
// so that previous data is overwritten
312337
provider.Stream.SetLength(provider.Stream.Position);
313338
}
339+
340+
AzKeyStore keystore = null;
341+
AzureSession.Instance.TryGetComponent(AzKeyStore.Name, out keystore);
342+
keystore?.Flush();
314343
}
315344
finally
316345
{

0 commit comments

Comments
 (0)