Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Commit 8264777

Browse files
Adding functionality in Keychain to ensure the username loaded by the credentialManager matches the cached username
1 parent 83e5677 commit 8264777

File tree

3 files changed

+91
-6
lines changed

3 files changed

+91
-6
lines changed

src/GitHub.Api/Authentication/Keychain.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,26 @@ public IKeychainAdapter Connect(UriString host)
5252

5353
public async Task<IKeychainAdapter> Load(UriString host)
5454
{
55-
var keychainAdapter = FindOrCreateAdapter(host);
55+
KeychainAdapter keychainAdapter = FindOrCreateAdapter(host);
56+
var cachedConnection = connectionCache[host];
57+
58+
logger.Trace($@"Loading KeychainAdapter Host:""{host}"" Cached Username:""{cachedConnection.Username}""");
5659

57-
logger.Trace("Load KeychainAdapter Host:\"{0}\"", host);
5860
var keychainItem = await credentialManager.Load(host);
5961

6062
if (keychainItem == null)
6163
{
62-
logger.Warning("Cannot load host from credential manager; removing from cache");
64+
logger.Warning("Cannot load host from Credential Manager; removing from cache");
65+
await Clear(host, false);
66+
}
67+
else if (keychainItem.Username != cachedConnection.Username)
68+
{
69+
logger.Warning("Item loaded from credential manager does not match connection cache ; removing from cache");
6370
await Clear(host, false);
6471
}
6572
else
6673
{
67-
logger.Trace("Loading KeychainItem:{0}", keychainItem.ToString());
74+
logger.Trace($@"Loaded from Credential Manager Host:""{keychainItem.Host}"" Username:""{keychainItem.Username}""");
6875
keychainAdapter.Set(keychainItem);
6976
}
7077

@@ -113,7 +120,10 @@ private void ReadCacheFromDisk()
113120
if (connections != null)
114121
{
115122
connectionCache =
116-
connections.Select(item => new Connection { Host = new UriString(item.Host), Username = item.Username })
123+
connections.Select(item => {
124+
logger.Trace("ReadCacheFromDisk Item Host:{0} Username:{1}", item.Host, item.Username);
125+
return new Connection { Host = new UriString(item.Host), Username = item.Username };
126+
})
117127
.ToDictionary(connection => connection.Host);
118128
}
119129
else

src/tests/UnitTests/Authentication/KeychainTests.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,81 @@ public void Should_Delete_From_Cache_When_Load_Returns_Null_From_ConnectionManag
247247
credentialManager.DidNotReceive().Save(Arg.Any<ICredential>());
248248
}
249249

250+
[Test]
251+
public void Should_Delete_From_Cache_When_Load_Returns_Null_From_ConnectionManager_Due_To_User_Mismatch()
252+
{
253+
const string connectionsCachePath = @"c:\UserCachePath\";
254+
const string connectionsCacheFile = @"c:\UserCachePath\connections.json";
255+
256+
const string cachedUsername = "SomeCachedUser";
257+
const string credentialedUsername = "SomeCredentialedUser";
258+
259+
const string token = "SomeToken";
260+
261+
var hostUri = new UriString("https://github.com/");
262+
263+
var fileSystem = SubstituteFactory.CreateFileSystem(new CreateFileSystemOptions
264+
{
265+
FilesThatExist = new List<string> { connectionsCacheFile },
266+
FileContents = new Dictionary<string, IList<string>> {
267+
{connectionsCacheFile, new List<string> {$@"[{{""Host"":""https://github.com/"",""Username"":""{cachedUsername}""}}]"
268+
}}
269+
}
270+
});
271+
272+
NPath.FileSystem = fileSystem;
273+
274+
var environment = SubstituteFactory.CreateEnvironment();
275+
environment.UserCachePath.Returns(info => connectionsCachePath.ToNPath());
276+
environment.FileSystem.Returns(fileSystem);
277+
278+
var credentialManager = Substitute.For<ICredentialManager>();
279+
credentialManager.Load(hostUri).Returns(info =>
280+
{
281+
var credential = Substitute.For<ICredential>();
282+
credential.Username.Returns(credentialedUsername);
283+
credential.Token.Returns(token);
284+
credential.Host.Returns(hostUri);
285+
return TaskEx.FromResult(credential);
286+
});
287+
288+
var keychain = new Keychain(environment, credentialManager);
289+
keychain.Initialize();
290+
291+
fileSystem.Received(1).FileExists(connectionsCacheFile);
292+
fileSystem.DidNotReceive().FileDelete(Args.String);
293+
fileSystem.Received(1).ReadAllText(connectionsCacheFile);
294+
fileSystem.DidNotReceive().ReadAllLines(Args.String);
295+
fileSystem.DidNotReceive().WriteAllText(Args.String, Args.String);
296+
fileSystem.DidNotReceive().WriteAllLines(Args.String, Arg.Any<string[]>());
297+
298+
credentialManager.DidNotReceive().Load(Args.UriString);
299+
credentialManager.DidNotReceive().HasCredentials();
300+
credentialManager.DidNotReceive().Delete(Args.UriString);
301+
credentialManager.DidNotReceive().Save(Arg.Any<ICredential>());
302+
303+
fileSystem.ClearReceivedCalls();
304+
305+
var uriString = keychain.Connections.FirstOrDefault();
306+
var keychainAdapter = keychain.Load(uriString).Result;
307+
keychainAdapter.Credential.Should().BeNull();
308+
309+
keychainAdapter.OctokitCredentials.AuthenticationType.Should().Be(AuthenticationType.Anonymous);
310+
keychainAdapter.OctokitCredentials.Login.Should().BeNull();
311+
keychainAdapter.OctokitCredentials.Password.Should().BeNull();
312+
313+
fileSystem.DidNotReceive().FileExists(Args.String);
314+
fileSystem.DidNotReceive().ReadAllText(Args.String);
315+
fileSystem.DidNotReceive().FileDelete(Args.String);
316+
fileSystem.Received(1).WriteAllText(connectionsCacheFile, "[]");
317+
fileSystem.DidNotReceive().WriteAllLines(Args.String, Arg.Any<string[]>());
318+
319+
credentialManager.Received(1).Load(hostUri);
320+
credentialManager.DidNotReceive().HasCredentials();
321+
credentialManager.DidNotReceive().Delete(Args.UriString);
322+
credentialManager.DidNotReceive().Save(Arg.Any<ICredential>());
323+
}
324+
250325
[Test]
251326
public void Should_Connect_Set_Credentials_Token_And_Save()
252327
{

src/tests/UnitTests/SetUpFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class SetUpFixture
1010
[SetUp]
1111
public void SetUp()
1212
{
13-
//Logging.TracingEnabled = true;
13+
Logging.TracingEnabled = true;
1414

1515
Logging.LogAdapter = new MultipleLogAdapter(new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-unit-tests.log"));
1616
}

0 commit comments

Comments
 (0)