Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for GitHub enterprise-managed user accounts (#1190)
Add support for GitHub [enterprise-manage users (EMU)](https://docs.github.com/en/enterprise-cloud@latest/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/about-enterprise-managed-users) to the GitHub host provider. Accounts in an 'EMU' enterprise/business are siloed from the regular, public GitHub.com accounts. EMU accounts are identified by the `_shortcode` suffix, where the `shortcode` is a moniker for the enterprise/business, for example `alice_contoso`. When asked to recall credentials for the GitHub.com host we now attempt to filter stored accounts by the `shortcode`, given information provided in `WWW-Authenticate` headers from upcoming versions of Git that support these headers (as of gitgitgadget/git@92c56da). The format of the header is: ``` WWW-Authenticate: Basic realm="GitHub" [domain_hint="X"] [enterprise_hint="Y"] ``` ..where `X` is the shortcode, and `Y` is the enterprise name. If multiple accounts are available for the given 'domain' then we present an account selection prompt. Users can avoid this prompt in the case of multiple user accounts by specifying the desired account in the remote URL (e.g. `https://alice@github.com/mona/test` to always use the `alice` account). Note that GitHub.com does not yet return such `WWW-Authenticate` headers, except always `Basic realm="GitHub"`, so this may be subject to fixes later. In the case of `realm="GitHub"`, i.e., public accounts, there is no change. ### Testing To test the new behaviour before GitHub.com returns such headers, it's possible to fake the server response using [`mitmproxy`](https://mitmproxy.org) and the following script: ```python """Add an HTTP header to each response.""" class AddHeader: # initialize a dict with shortcodes and paths def __init__(self): org1 = ("domain1", "enterprise1") org2 = ("domain2", "enterprise2") self.orgMap = { "org1" : enterprise1, "org2" : enterprise1, "org3" : enterprise2, } def response(self, flow): if flow.response.status_code == 401: # lookup the correct shortcode based on the org org = flow.request.path.split("/")[1] if org not in self.orgMap: return domain_hint = self.orgMap[org][0] enterprise_hint = self.orgMap[org][1] # build the header header = "Basic realm=\"GitHub\" enterprise_hint=\"" + enterprise_hint + "\" domain_hint=\"" + domain_hint + "\"" # set the header flow.response.headers["WWW-Authenticate"] = header addons = [ AddHeader() ] ``` Replace `orgN` with the org names that are backed by an EMU Enterprise, and fill `domainN` for the shortcode, and `enterpriseN` for the enterprise slug/name. Configure Git to use the proxy and run `mitmproxy` with the `--scripts` argument: ```shell git config --global http.proxy 'http://127.0.0.1:8080' mitmproxy --scripts <SCRIPT> ``` Now all Git interactions that touch `orgN` will include the `domain_hint` and `enterprise_hint`s as defined. I use these two helpful aliases to quickly add and remove the local proxy from Git's config: ```shell [alias] mitm = "!f(){ git config --global http.proxy 'http://127.0.0.1:8080'; }; f" unmitm = "!f(){ git config --global --unset http.proxy; }; f" ```
- Loading branch information