Skip to content

Commit 2d06c68

Browse files
committed
use mutex to prevent cross process writing
to token cache file
1 parent 841d8b3 commit 2d06c68

File tree

2 files changed

+44
-37
lines changed

2 files changed

+44
-37
lines changed

src/Accounts/Authentication/Authentication/ProtectedFileTokenCache.cs

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using Hyak.Common;
1516
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
1617
using Microsoft.Azure.Commands.Common.Authentication.Properties;
1718
using Microsoft.IdentityModel.Clients.ActiveDirectory;
1819
using System;
1920
using System.IO;
2021
using System.Security.Cryptography;
22+
using System.Threading;
2123

2224
#if NETSTANDARD
2325
namespace Microsoft.Azure.Commands.Common.Authentication.Core
@@ -41,7 +43,10 @@ public class ProtectedFileTokenCache : TokenCache, IAzureTokenCache
4143
#endif
4244
"TokenCache.dat");
4345

44-
private static readonly object fileLock = new object();
46+
/// <summary>
47+
/// A mutex to prevent IO to token cache file across threads / processes.
48+
/// </summary>
49+
private static readonly Mutex fileLock = new Mutex(false, @"Global\AzurePowerShellAdalTokenCacheFile");
4550

4651
private static readonly Lazy<ProtectedFileTokenCache> instance = new Lazy<ProtectedFileTokenCache>(() => new ProtectedFileTokenCache());
4752

@@ -123,38 +128,37 @@ void EnsureStateSaved()
123128

124129
private void ReadFileIntoCache(string cacheFileName = null)
125130
{
126-
if(cacheFileName == null)
131+
if (cacheFileName == null)
127132
{
128133
cacheFileName = ProtectedFileTokenCache.CacheFileName;
129134
}
130135

131-
lock (fileLock)
136+
fileLock.WaitOne();
137+
if (_store.FileExists(cacheFileName))
132138
{
133-
if (_store.FileExists(cacheFileName))
139+
var existingData = _store.ReadFileAsBytes(cacheFileName);
140+
if (existingData != null)
134141
{
135-
var existingData = _store.ReadFileAsBytes(cacheFileName);
136-
if (existingData != null)
137-
{
138142
#if !NETSTANDARD
139-
try
140-
{
141-
Deserialize(ProtectedData.Unprotect(existingData, null, DataProtectionScope.CurrentUser));
142-
}
143-
catch (CryptographicException)
144-
{
145-
_store.DeleteFile(cacheFileName);
146-
}
143+
try
144+
{
145+
Deserialize(ProtectedData.Unprotect(existingData, null, DataProtectionScope.CurrentUser));
146+
}
147+
catch (CryptographicException)
148+
{
149+
_store.DeleteFile(cacheFileName);
150+
}
147151
#else
148-
Deserialize(existingData);
152+
Deserialize(existingData);
149153
#endif
150-
}
151154
}
152155
}
156+
fileLock.ReleaseMutex();
153157
}
154158

155159
private void WriteCacheIntoFile(string cacheFileName = null)
156160
{
157-
if(cacheFileName == null)
161+
if (cacheFileName == null)
158162
{
159163
cacheFileName = ProtectedFileTokenCache.CacheFileName;
160164
}
@@ -165,25 +169,23 @@ private void WriteCacheIntoFile(string cacheFileName = null)
165169
var dataToWrite = Serialize();
166170
#endif
167171

168-
lock(fileLock)
172+
fileLock.WaitOne();
173+
if (HasStateChanged)
169174
{
170-
if (HasStateChanged)
171-
{
172-
_store.WriteFile(cacheFileName, dataToWrite);
173-
HasStateChanged = false;
174-
}
175+
_store.WriteFile(cacheFileName, dataToWrite);
176+
HasStateChanged = false;
175177
}
178+
fileLock.ReleaseMutex();
176179
}
177180

178181
private void EnsureCacheFile(string cacheFileName = null)
179182
{
180-
lock (fileLock)
183+
fileLock.WaitOne();
184+
if (_store.FileExists(cacheFileName))
181185
{
182-
if (_store.FileExists(cacheFileName))
186+
var existingData = _store.ReadFileAsBytes(cacheFileName);
187+
if (existingData != null)
183188
{
184-
var existingData = _store.ReadFileAsBytes(cacheFileName);
185-
if (existingData != null)
186-
{
187189
#if !NETSTANDARD
188190
try
189191
{
@@ -194,19 +196,19 @@ private void EnsureCacheFile(string cacheFileName = null)
194196
_store.DeleteFile(cacheFileName);
195197
}
196198
#else
197-
Deserialize(existingData);
199+
Deserialize(existingData);
198200
#endif
199-
}
200201
}
202+
}
201203

202-
// Eagerly create cache file.
204+
// Eagerly create cache file.
203205
#if !NETSTANDARD
204206
var dataToWrite = ProtectedData.Protect(Serialize(), null, DataProtectionScope.CurrentUser);
205207
#else
206-
var dataToWrite = Serialize();
208+
var dataToWrite = Serialize();
207209
#endif
208-
_store.WriteFile(cacheFileName, dataToWrite);
209-
}
210+
_store.WriteFile(cacheFileName, dataToWrite);
211+
fileLock.ReleaseMutex();
210212
}
211213
}
212214
}

src/Accounts/Authentication/AzureSessionInitializer.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#if NETSTANDARD
2727
using Microsoft.Azure.Commands.Common.Authentication.Core;
2828
#endif
29+
using Hyak.Common;
2930

3031
namespace Microsoft.Azure.Commands.Common.Authentication
3132
{
@@ -73,8 +74,10 @@ static IAzureTokenCache InitializeTokenCache(IDataStore store, string cacheDirec
7374
var cachePath = Path.Combine(cacheDirectory, cacheFile);
7475
result = new ProtectedFileTokenCache(cachePath, store);
7576
}
76-
catch
77+
catch (Exception ex)
7778
{
79+
TracingAdapter.Information("[AzureSessionInitializer]: Cannot initialize token cache in 'CurrentUser' mode. Falling back to 'Process' mode.");
80+
TracingAdapter.Information($"[AzureSessionInitializer]: Message: {ex.Message}; Stacktrace: {ex.StackTrace}");
7881
}
7982
}
8083

@@ -159,10 +162,12 @@ static ContextAutosaveSettings InitializeSessionSettings(IDataStore store, strin
159162
store.WriteFile(autoSavePath, JsonConvert.SerializeObject(result));
160163
}
161164
}
162-
catch
165+
catch (Exception ex)
163166
{
164167
// ignore exceptions in reading settings from disk
165168
result.Mode = ContextSaveMode.Process;
169+
TracingAdapter.Information("[AzureSessionInitializer]: Cannot read settings from disk. Falling back to 'Process' mode.");
170+
TracingAdapter.Information($"[AzureSessionInitializer]: Message: {ex.Message}; Stacktrace: {ex.StackTrace}");
166171
}
167172

168173
return result;

0 commit comments

Comments
 (0)