Skip to content

Commit fc2dfd6

Browse files
authored
Merge pull request #138 from mjcheetham/provider-spec
Add host provider specification
2 parents df22473 + a7d810c commit fc2dfd6

File tree

2 files changed

+343
-4
lines changed

2 files changed

+343
-4
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,12 @@ Proxy support|✓|✓|
3131

3232
**Notes:**
3333

34-
(\*) Currently only supported when using Git from the terminal or command line. A platform-native UI experience is not yet available on macOS, but planned.
34+
(\*) Currently only supported when using Git from the terminal or command line. A platform-native UI experience is not yet available, but planned.
3535

3636
### Planned features
3737

38-
- [ ] 32-bit Windows support (only 64-bit Windows is supported currently)
39-
- [ ] Linux support
40-
- [ ] macOS/Linux native UI
38+
- [ ] Linux support ([#135](https://github.com/microsoft/Git-Credential-Manager-Core/issues/135))
39+
- [ ] macOS/Linux native UI ([#136](https://github.com/microsoft/Git-Credential-Manager-Core/issues/136))
4140

4241
## Download and Install
4342

@@ -113,6 +112,8 @@ See detailed information [here](https://aka.ms/gcmcore-httpproxy).
113112
- [Configuration options](docs/configuration.md)
114113
- [Environment variables](docs/environment.md)
115114
- [Network and HTTP configuration](docs/netconfig.md)
115+
- [Architectural overview](docs/architecture.md)
116+
- [Host provider specification](docs/hostprovider.md)
116117

117118
## Contributing
118119

docs/hostprovider.md

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
# Git Credential Manager Core Host Provider
2+
3+
Property|Value
4+
-|-
5+
Author(s)|Matthew John Cheetham ([@mjcheetham](https://github.com/mjcheetham))
6+
Revision|1.0
7+
Last updated|2020-06-22
8+
9+
## Abstract
10+
11+
Git Credential Manger Core, the cross-platform and cross-host Git credential
12+
helper, can be extended to support any Git hosting service allowing seemless
13+
authentication to secured Git repositories by implementing and registering a
14+
"host provider".
15+
16+
## Table of Contents
17+
18+
- [1. Introduction](#1-introduction)
19+
- [1.1. Notational Conventions](#11-notational-conventions)
20+
- [1.2. Abbreviations](#12-abbreviations)
21+
- [2. Implementation](#2-implementation)
22+
- [2.1. Registration](#21-registration)
23+
- [2.1.2. Ordering](#212-ordering)
24+
- [2.2. Handling Requests](#22-handling-requests)
25+
- [2.2.1. Rejecting Requests](#221-rejecting-requests)
26+
- [2.3. Retrieving Credentials](#23-retrieving-credentials)
27+
- [2.3.1 Authentication Prompts](#231-authentication-prompts)
28+
- [2.4. Storing Credentials](#24-storing-credentials)
29+
- [2.5. Erasing Credentials](#25-erasing-credentials)
30+
- [2.6 `HostProvider` base class](#26-hostprovider-base-class)
31+
- [2.6.1 `GetCredentialKey`](#261-getcredentialkey)
32+
- [2.6.2 `GenerateCredentialAsync`](#262-generatecredentialasync)
33+
- [2.7. External Metadata](#27-external-metadata)
34+
- [3. Helpers](#3-helpers)
35+
- [3.1. Discovery](#31-discovery)
36+
- [4. Error Handling](#4-error-handling)
37+
38+
## 1. Introduction
39+
40+
Git Credential Manager Core (GCM Core) is a host and platform agnostic Git
41+
credential helper application. Support for authenticating to any Git hosting
42+
service can be added to GCM Core by creating a custom "host provider" and
43+
registering it within the product. Host providers can be submitted via a pull
44+
request on GitHub at <https://github.com/microsoft/Git-Credential-Manager-Core>.
45+
46+
This document outlines the required and expected behaviour of a host provider,
47+
and what is required to implement and register one.
48+
49+
### 1.1. Notational Conventions
50+
51+
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
52+
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
53+
specification are to be interpreted as described in
54+
[[RFC2119](https://tools.ietf.org/html/rfc2119)].
55+
56+
### 1.2. Abbreviations
57+
58+
Throughout this document you may see multiple abbreviations of product names and
59+
security or credential objects.
60+
61+
"Git Credential Manager Core" is abbreviated to "GCM Core". "Git Credential
62+
Manager for Windows" is abbreviated to "GCM for Windows" or "GCM Windows".
63+
"Git Credential Manager for Mac & Linux" is abbreviated to "GCM for
64+
Mac/Linux" or "GCM Mac/Linux".
65+
66+
OAuth2 [[RFC6749](https://tools.ietf.org/html/rfc6749)] "access tokens" are
67+
abbreviated to "ATs" and "refresh tokens" to "RTs". "Personal Access Tokens" are
68+
abbreivated to "PATs".
69+
70+
## 2. Implementation
71+
72+
Writing and adding a host provider to GCM Core requires two main actions:
73+
implementing the `IHostProvider` interface, and registering an instance of the
74+
provider with the application via the host provider registry.
75+
76+
Host providers MUST implement the `IHostProvider` interface. They can choose to
77+
directly implement the interface they MAY derive from the `HostProvider`
78+
abstract class (which itself implements the `IHostProvider` interface) - see
79+
[§2.6](#26-hostprovider-base-class).
80+
81+
Implementors MUST implement all interface properties and abstract methods.
82+
83+
The `Id` and `Name` properties MUST be implemented and MUST NOT return default
84+
or empty values.
85+
86+
The `Id` field MUST be unique over the set of all providers, or
87+
else an error will be thrown at registration time. The `Id` field MAY be a
88+
unique random string of characters and digits such as a UUID, but it is
89+
RECOMMENDED to use a human-readable value consisting of letter characters in the
90+
range \[a-z\] only.
91+
92+
The `Name` property MUST be a human readable string and MUST identify the Git
93+
hosting service this provider supports.
94+
95+
The `SupportedAuthorityIds` property MUST return an instance of an object and
96+
NOT a `null` reference. Populating this collection with values is OPTIONAL but
97+
highly RECOMMENDED. You should return a set of stable identifiers of all
98+
authorities that the provider supports authentication against.
99+
100+
### 2.1. Registration
101+
102+
Host providers must provide an instance of their `IHostProvider` type to the
103+
GCM Core application host provider registry to be considered for handling
104+
requests.
105+
106+
The main GCM Core `Application` object has one principal registry which you can
107+
register providers with by calling the `RegisterProvider` method.
108+
109+
#### 2.1.2. Ordering
110+
111+
The default host provider registry in GCM Core will call each host provider in
112+
the order they were registered in, unless the user has overriden the provider
113+
selection process.
114+
115+
There are no rules or restrictions on the ordering of host providers, except
116+
that the `GenericHostProvider` MUST be registered last. The generic provider is
117+
a catch-all provider implementation that will handle any request in a standard
118+
way.
119+
120+
### 2.2. Handling Requests
121+
122+
The `IsSupported` method will be called on all registered host providers in-turn
123+
on the invokation of a `get`, `store`, or `erase` request. The first host
124+
provider to return `true` will be called upon to handle the specific request.
125+
If the user has overriden the host provider selection process, a specific host
126+
provider may be selected instead, and the `IsSupported` method will NOT be
127+
called.
128+
129+
This method MUST return `true` if and only if the provider understands the
130+
request and can serve or handle the request. If the provider does not know how
131+
to handle the request it MUST return `false` instead.
132+
133+
#### 2.2.1. Rejecting Requests
134+
135+
The `IsSupported` method MUST return `true` if the host provider would like to
136+
cancel the authentication operation based on the current context or input.
137+
For example, if provider requires a secure protocol but the requested protocol
138+
for a supported hostname is `http` and not `https`.
139+
140+
Host providers MUST instead cancel the request from the `GetCredentialAsync`
141+
method by throwing an `Exception`. Implementors MUST provide detailed
142+
information regarding the reason why the authentication cannot continue, for
143+
example "HTTP is not secure, please use HTTPS".
144+
145+
### 2.3. Retrieving Credentials
146+
147+
The `GetCredentialAsync` method will be called when a `get` request is made.
148+
The method MUST return an instance of an `ICredential` capable of fufilling the
149+
specific access request. The argument passed to `GetCredentialAsync` contains
150+
properties indicating the required `protocol` and `host` for this request. The
151+
`username` and `path` properties are OPTIONAL, however if they are present, they
152+
MUST be considered and used to direct the authentication.
153+
154+
The host provider MAY attempt to locate any existing credential, stored by the
155+
`StoreCredentialAsync` method, before resorting to the creation a new one.
156+
157+
The host provider MAY choose to check if a stored credential is still valid
158+
by inspecting any stored metadata associated with the value. A host provider MAY
159+
also choose to further validate a retrieved stored credential by making a web
160+
request. However, it is NOT RECOMMENDED to make any request that is known to be
161+
slow or that typically produces inconclusive valudation results.
162+
163+
If a provider chooses to make a validation web request and that request fails or
164+
is inconclusive, it SHOULD assume the credential is still valid and return it
165+
anyway, letting Git (the caller) attempt to use it and validate it itself.
166+
167+
The returned `ICredential` MAY leave both the username and password values as
168+
the empty string or `null`. This signals to Git (or rather cURL) that it should
169+
negotiate the authentication mechanism with the remote itself. This is typically
170+
used for Windows Integrated Authentication.
171+
172+
#### 2.3.1 Authentication Prompts
173+
174+
When it is not possible to locate an existing credential suitable for the
175+
current request, a host provider SHOULD prompt the user to complete an
176+
authentication flow.
177+
178+
The method, modes, and interactions for performing authentication will vary
179+
widely between Git hosting services and their supported authentication
180+
authorities. A host provider SHOULD attempt to detect the best authentication
181+
experience given the current environment or context, and select that one to
182+
attempt first.
183+
184+
Host providers are RECOMMENDED to attempt authentication mechanisms that do not
185+
require user interaction if possible. If there are multiple authentication
186+
mechanisms that could be equally considered "best" they MAY prompt the user
187+
to make a selection. Host providers MAY wish to rememeber such a selection for
188+
future use, however they MUST make it clear how to clear this stored selection
189+
to the user.
190+
191+
If interaction is required to complete authentication a host provider MUST first
192+
check if interaction has been disabled (`ISettings.IsInteractionAllowed`), and
193+
an exception MUST be thrown if interaction has been disallowed.
194+
195+
Authentication prompts that display a graphical user interface such as a window
196+
are MUST be preferred when an interactive "desktop" session is available.
197+
198+
If an authentication prompt is required when an interactive session is not
199+
available and a terminal/TTY is attached then a provider MUST first check if
200+
terminal prompts are enabled (`ISettings.IsTerminalPromptsEnabled`), and an
201+
exception MUST be thrown if interaction has been disallowed.
202+
203+
### 2.4. Storing Credentials
204+
205+
Host providers MAY store credentials at various stages of a typical
206+
authentication flow, or when explicitly requested to do so in a call to
207+
`StoreCredentialAsync`.
208+
209+
Providers SHOULD use the credential store (exposed as `ICredentialStore`) to
210+
persist secret values and credential entities such as passwords, PATs and OAuth
211+
tokens.
212+
213+
The typical Git credential helper call pattern is one call to `get`, followed by
214+
either a `store` request in case of a HTTP 200 (OK) response, or `erase` in case
215+
of HTTP 401 (Unauthorized) response. In some cases there is additional context
216+
that is present as part of the `get` request or during the generation of a new
217+
credential that is not present during the subsequent call to `store` (or
218+
`erase`). In these cases providers MAY store the credential during the `get`
219+
rather than, or as well as during the `store`.
220+
221+
Host providers MAY store multiple credentials or tokens in the same request if
222+
it is required. One example where multiple credential storage is needed is with
223+
OAuth2 access tokens (AT) and refresh tokens (RT). Both the AT and RT SHOULD be
224+
stored in the same location using the credential store with complementary
225+
credential keys.
226+
227+
### 2.5. Erasing Credentials
228+
229+
If host providers have stored credentials in the credential store, they MUST
230+
respond to requests to erase them in calls to `EraseCredentialAsync`.
231+
232+
If a host provider cannot locate a credential to erase it MUST NOT raise an
233+
error and MUST exit successfully. A warning message MAY be emitted to the
234+
tracing system.
235+
236+
Host providers MUST NOT perform their own repeated validation of credentials
237+
for the purposes of ignoring the request to erase them. The ultimate authority
238+
on the validity of a credential is the caller (Git).
239+
240+
Providers MAY validate any additional or ancillary credentials (such as OAuth
241+
RTs) are still valid when a request to erase the primary credential (such as an
242+
OAuth AT) is made, and choose not to delete those additional credentials. The
243+
primary credential MUST still always be erased in all cases.
244+
245+
### 2.6 `HostProvider` base class
246+
247+
The `HostProvider` abstract base class is provided for the convenience of host
248+
provider implementors. This base class implements most required methods of the
249+
`IHostProvider` interface with common credential recall and storage behaviour.
250+
251+
The `GetCredentialAsync`, `StoreCredentialAsync`, and `EraseCredentialAsync`
252+
methods are implemented as `virtual` meaning they MAY be overriden by derived
253+
classes to customise the behaviour of those operations. It is NOT RECOMMENDED
254+
to derive from the `HostProvider` base class if the implementor must override
255+
most of the methods as implemented - implementors SHOULD implement the
256+
`IHostProvider` interface directly instead.
257+
258+
Implementors that choose to derive from this base class MUST implement all
259+
abstract methods and properties. The two primary abstract methods to implement
260+
are `GetCredentialKey` and `GenerateCredentialAsync`.
261+
262+
#### 2.6.1 `GetCredentialKey`
263+
264+
The `GetCredentialKey` method MUST return a string that forms a key for storing
265+
credentials for this provider and request. The key returned MUST be stable -
266+
i.e, it MUST return the same value given the same or equivalent input arguments.
267+
268+
This key is used by the `GetCredentialAsync` method to first check for any
269+
existing credential stored in the credential store, returning it if found.
270+
271+
The key is also similarly used by the `StoreCredentialAsync` and
272+
`EraseCredentialAsync` methods to store and erase, respectively, credentials
273+
passed as arguments by Git.
274+
275+
#### 2.6.2 `GenerateCredentialAsync`
276+
277+
The `GenerateCredentialAsync` method will be called if an existing credential
278+
with a matching credential key is not found in the credential store.
279+
280+
This method MUST return a freshly created/generated credential and not any
281+
existing or stored one. It MAY use existing or stored ancillary data or tokens,
282+
such as OAuth refresh tokens, to generate the new token (such as an OAuth AT).
283+
284+
### 2.7. External Metadata
285+
286+
Host providers MAY wish to store extra data about authentications or users
287+
collected or produced during authentication operations. These SHOULD be stored
288+
in a per-user, local location such as the user's home or profile directory.
289+
290+
Secrets, credentials or other sensitive data SHOULD be stored in the credential
291+
store, or otherwise protected by some form of per-user, local encryption.
292+
293+
In the case of stored data caches, providers SHOULD invalidate relevant parts
294+
of, or the entire cache, when a call to `EraseCredentialAsync` is made.
295+
296+
## 3. Helpers
297+
298+
Host providers MAY wish to make use of platform or operating system specific
299+
features such as native APIs and native graphical user interfaces, in order to
300+
offer a better authentication experience.
301+
302+
Host providers MUST function without the presence of a helper, even if that
303+
function is to fail gracefully with a user friendly error message, including
304+
a remedy to correct their installation. Host providers SHOULD always offer a
305+
terminal/TTY or text-based authentication mechanism alongside any graphical
306+
interface provided by a helper.
307+
308+
In order to achieve this host providers MUST introduce an out-of-process
309+
"helper" executable that can be invoked from the main GCM Core process. This
310+
allows the "helper" executable full implementation freedom of runtime, language,
311+
etc.
312+
313+
Communications between the main and helper processes MAY use any IPC mechanism
314+
available. It is RECOMMENDED implementors use standard input/output streams or
315+
file descriptors to send and recieve data as this is consistent with how Git and
316+
GCM Core communicate. UNIX sockets or Windows Named Pipes MAY also be used when
317+
an ongoing back-and-forth communication is required.
318+
319+
### 3.1. Discovery
320+
321+
It is RECOMMENDED that helper discovery is achieved by simply checking for the
322+
presence of the expected executable file. The name and path of the helper
323+
executable SHOULD be configurable by the user via Git's configuration files.
324+
325+
## 4. Error Handling
326+
327+
If an unrecoverable error occurs a host provider MUST throw an exception and
328+
MUST include detailed failure information in the error message. If the reason
329+
for failure can be fixed by the user the error message MUST include instructions
330+
to fix the problem, or a link to online documentation.
331+
332+
In the case of a recoverable error, host providers SHOULD print a warning
333+
message to the standard error stream, and MUST include the error information and
334+
the recovery steps take in the trace log.
335+
336+
In the case of an authentication error, providers SHOULD attempt to prompt the
337+
user again with a message indicating the incorrect authentication details have
338+
been entered.

0 commit comments

Comments
 (0)