-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Refactor to allow HostProvider
s to override store and erase
#49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
} | ||
|
||
return url; | ||
return $"git:{url}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The providers are now in direct control over how they store (or not) their credentials in the OS credential stores, meaning the common "git:" prefix is being pushed into the providers themselves. The fact they start with "git:" is now a convention, rather than something that is enforced.
/// <summary> | ||
/// Represents a Git hosting provider where credentials can be stored and recalled in/from the Operating System's | ||
/// secure credential store. | ||
/// </summary> | ||
public abstract class HostProvider : IHostProvider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The base HostProvider
class assumes that inheriting providers do want to use the ICredentialStore
for the operating system, but providers can either override the various virtual
methods, or directly implement IHostProvider
instead.
Refactor the core commands and host provider types to permit providers to customise how they store and erase credentials. This would allow for providers that do not want to use the OS credential store for example.
I think the code changes look good. I had more of a question around how other credential systems are going to work (e.g. ADAL/MSAL or Azure Access Tokens). How will the flow for these be different than with OS credential storage? How will the credential manager choose the appropriate HostProvider? Will GitHub be able to use MSAL? I assume that AzDevOps end points will need to be able to choose between ADAL/MSAL, OS provided storage, and Azure Access Tokens? Will the ADAL/MSAL flavor only be able to “get” a credential, and not update / erase an entry? |
@jamill, perhaps an overview of the current flow, and the flow as proposed by this PR would be useful. Command invocationWhen Git invokes GCM it gives us a 'verb' and a dictionary of information as input. The available verbs are "get", "store", and "erase". Each command ultimately inherits from
The Current designThe
Each of the verb commands inherit from the
// GetCommand
ICredential cred = credStore.Get(credKey);
if (cred is null)
{
cred = await hostProvider.CreateCredentialAsync(...);
}
return cred;
// StoreCommand
var cred = new Credential(input.UserName, input.Password);
credStore.AddOrUpdate(credKey, cred);
// EraseCommand
credStore.Remove(credKey); Motivation for changeThe assumption here is that all host providers are called for two things:
The GCM infrastructure is responsible for retrieving, storing and erasing these credentials using the provided keys. In order to support scenarios such as using the AAD Access Token (AT) directly (rather than an Azure DevOps PAT), we need to delegate storage, lookup, and deletion to the ADAL/MSAL authentication library. It does not use the Change overviewThe primary goal in the PR is to remove the assumption above, and instead allow the host providers to do what they want want when called with "get", "store", or "erase". The // GetCommand
var cred = await provider.GetCredentialAsync(input);
output["protocol"] = input.Protocol;
output["host"] = input.Host;
output["username"] = cred.UserName;
output["password"] = cred.Password;
// StoreCommand
provider.StoreCredentialAsync(input);
// EraseCommand
provider.EraseCredentialAsync(input); The shared input parsing, and the selection of the correct Keeping it easy to implement a host providerSince most of the current providers do want to use the OS credential store to lookup/store credentials, rather than make each provider have to reimplement the
override Task EraseCredentialAsync(..)
{
// Erase our special cache
contosoOrgCache.EraseEntry(...);
// Call the shared logic to erase the actual credential from the OS store
base.EraseCredentialAsync();
}
To answer your question @Jamil:
The design of GCM Core is such that the authentication methods are more orthogonal to the host provider than GCM Windows. If GitHub wished to provide a "sign in with Microsoft" option in the future, the Such a feature (depending on how implemented) might look like this: // GitHubHostProvider
override Task GetCredentialAsync(..)
{
bool msAuthSupported = gitHubApi.CheckIfMicrosoftAuthIsSupported();
bool userSelectedMsAuth = ShowSelectAuthTypePrompt();
if (msAuthSupported && userSelectedMsAuth)
{
// Use existing MS auth flows
IMicrosoftAuthentication msAuth = ..;
var accessToken = msAuth.GetAccessToken(..);
// ..
}
else
{
// Use existing GitHub auth flows
IGitHubAuthentication ghAuth = ..;
var cred = ghAuth.PromptForCredentials(..);
// ..
}
} |
Thank you for the detailed comments! |
Refactor the core commands and host provider types to permit providers to customise how they store and erase credentials. This would allow for providers that do not want to use the OS credential store for example.
This change is required to enable non-PAT-based authentication, such as delegating to ADAL/MSAL and using Azure access tokens directly (where we don't lookup, store, or erase from the system credential store).