|
| 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