<feed xmlns='http://www.w3.org/2005/Atom'>
<title>git/t/lib-credential.sh, branch jch</title>
<subtitle>Mirror of https://git.kernel.org/pub/scm/git/git.git/
</subtitle>
<id>https://git.shady.money/git/atom?h=jch</id>
<link rel='self' href='https://git.shady.money/git/atom?h=jch'/>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/'/>
<updated>2025-01-09T23:04:15Z</updated>
<entry>
<title>credential-cache: respect authtype capability</title>
<updated>2025-01-09T23:04:15Z</updated>
<author>
<name>M Hickford</name>
<email>mirth.hickford@gmail.com</email>
</author>
<published>2025-01-09T22:45:20Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=0b432748507a12b92677653104b18834d83cfb10'/>
<id>urn:sha1:0b432748507a12b92677653104b18834d83cfb10</id>
<content type='text'>
Previously, credential-cache populated authtype regardless whether
"get" request had authtype capability. As documented in
git-credential.txt, authtype "should not be sent unless the appropriate
capability ... is provided".

Add test. Without this change, the test failed because "credential fill"
printed an incomplete credential with only protocol and host attributes
(the unexpected authtype attribute was discarded by credential.c).

Signed-off-by: M Hickford &lt;mirth.hickford@gmail.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
<entry>
<title>t: add credential tests for authtype</title>
<updated>2024-04-17T05:39:08Z</updated>
<author>
<name>brian m. carlson</name>
<email>sandals@crustytoothpaste.net</email>
</author>
<published>2024-04-17T00:02:38Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=30c0a3036fc5ac8e49f570675950bb3a133ce34d'/>
<id>urn:sha1:30c0a3036fc5ac8e49f570675950bb3a133ce34d</id>
<content type='text'>
It's helpful to have some basic tests for credential helpers supporting
the authtype and credential fields.  Let's add some tests for this case
so that we can make sure newly supported helpers work correctly.

Note that we explicitly check that credential helpers can produce
different sets of authtype and credential values based on the username.
While the username is not used in the HTTP protocol with authtype and
credential, it can still be specified in the URL and thus may be part of
the protocol.  Additionally, because it is common for users to have
multiple accounts on one service (say, both personal and professional
accounts), it's very helpful to be able to store different credentials
for different accounts in the same helper, and that doesn't become less
useful if one is using, say, Bearer authentication instead of Basic.
Thus, credential helpers should be expected to support this
functionality as basic functionality, so verify here that they do so.

Signed-off-by: brian m. carlson &lt;sandals@crustytoothpaste.net&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
<entry>
<title>t/lib-credential: clean additional credential</title>
<updated>2024-02-15T22:16:38Z</updated>
<author>
<name>Bo Anderson</name>
<email>mail@boanderson.me</email>
</author>
<published>2024-02-15T01:03:56Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=83e6eb7d7a8e9e2b6673638e9219b67659a969d3'/>
<id>urn:sha1:83e6eb7d7a8e9e2b6673638e9219b67659a969d3</id>
<content type='text'>
71201ab0e5 (t/lib-credential.sh: ensure credential helpers handle long
headers, 2023-05-01) added a test which stores credentials with the host
victim.example.com but this was never cleaned up, leaving residual data
in the credential store after running the tests.

Add a cleanup call for this credential to resolve this issue.

Signed-off-by: Bo Anderson &lt;mail@boanderson.me&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
<entry>
<title>Merge branch 'mh/credential-libsecret-attrs'</title>
<updated>2023-08-28T16:51:16Z</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2023-08-28T16:51:15Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=e839608295c0b6abd2a1f609916cba4ca1810241'/>
<id>urn:sha1:e839608295c0b6abd2a1f609916cba4ca1810241</id>
<content type='text'>
The way authentication related data other than passwords (e.g.
oath token and password expiration data) are stored in libsecret
keyrings has been rethought.

* mh/credential-libsecret-attrs:
  credential/libsecret: store new attributes
</content>
</entry>
<entry>
<title>credential/libsecret: store new attributes</title>
<updated>2023-06-16T20:06:57Z</updated>
<author>
<name>M Hickford</name>
<email>mirth.hickford@gmail.com</email>
</author>
<published>2023-06-16T19:55:06Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=0ce02e2feca6b0a7b09c71cf890d116de4e09f36'/>
<id>urn:sha1:0ce02e2feca6b0a7b09c71cf890d116de4e09f36</id>
<content type='text'>
d208bfd (credential: new attribute password_expiry_utc, 2023-02-18)
and a5c76569e7 (credential: new attribute oauth_refresh_token)
introduced new credential attributes.

libsecret assumes attribute values are non-confidential and
unchanging, so we encode the new attributes in the secret, separated by
newline:

    hunter2
    password_expiry_utc=1684189401
    oauth_refresh_token=xyzzy

This is extensible and backwards compatible. The credential protocol
already assumes that attribute values do not contain newlines.

Alternatives considered: store password_expiry_utc in a libsecret
attribute. This has the problem that libsecret creates new items
rather than overwrites when attribute values change.

Signed-off-by: M Hickford &lt;mirth.hickford@gmail.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
<entry>
<title>credential: erase all matching credentials</title>
<updated>2023-06-15T20:26:41Z</updated>
<author>
<name>M Hickford</name>
<email>mirth.hickford@gmail.com</email>
</author>
<published>2023-06-15T19:19:33Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=6c26da8404c8acfed62fa4775b7b591f099bcd33'/>
<id>urn:sha1:6c26da8404c8acfed62fa4775b7b591f099bcd33</id>
<content type='text'>
`credential reject` sends the erase action to each helper, but the
exact behaviour of erase isn't specified in documentation or tests.
Some helpers (such as credential-store and credential-libsecret) delete
all matching credentials, others (such as credential-cache) delete at
most one matching credential.

Test that helpers erase all matching credentials. This behaviour is
easiest to reason about. Users expect that `echo
"url=https://example.com" | git credential reject` or `echo
"url=https://example.com\nusername=tim" | git credential reject` erase
all matching credentials.

Fix credential-cache.

Signed-off-by: M Hickford &lt;mirth.hickford@gmail.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
<entry>
<title>credential: avoid erasing distinct password</title>
<updated>2023-06-15T20:26:39Z</updated>
<author>
<name>M Hickford</name>
<email>mirth.hickford@gmail.com</email>
</author>
<published>2023-06-15T19:19:32Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=aeb21ce22eec112b37975443a160cb5418c6ec22'/>
<id>urn:sha1:aeb21ce22eec112b37975443a160cb5418c6ec22</id>
<content type='text'>
Test that credential helpers do not erase a password distinct from the
input. Such calls can happen when multiple credential helpers are
configured.

Fixes for credential-cache and credential-store.

Signed-off-by: M Hickford &lt;mirth.hickford@gmail.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
<entry>
<title>Merge branch 'mh/credential-oauth-refresh-token'</title>
<updated>2023-05-10T17:23:29Z</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2023-05-10T17:23:28Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=2ca91d1ee07f934fa7f57ba34c397b150eef023f'/>
<id>urn:sha1:2ca91d1ee07f934fa7f57ba34c397b150eef023f</id>
<content type='text'>
The credential subsystem learns to help OAuth framework.

* mh/credential-oauth-refresh-token:
  credential: new attribute oauth_refresh_token
</content>
</entry>
<entry>
<title>t/lib-credential.sh: ensure credential helpers handle long headers</title>
<updated>2023-05-01T16:27:01Z</updated>
<author>
<name>Taylor Blau</name>
<email>me@ttaylorr.com</email>
</author>
<published>2023-05-01T15:53:51Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=71201ab0e53d61f3908a63078265e4e0742ef10d'/>
<id>urn:sha1:71201ab0e53d61f3908a63078265e4e0742ef10d</id>
<content type='text'>
Add a test ensuring that the "wwwauth[]" field cannot be used to
inject malicious data into the credential helper stream.

Many of the credential helpers in contrib/credential read the
newline-delimited protocol stream one line at a time by repeatedly
calling fgets() into a fixed-size buffer.

This assumes that each line is no more than 1024 characters long, since
each iteration of the loop assumes that it is parsing starting at the
beginning of a new line in the stream. However, similar to a5bb10fd5e
(config: avoid fixed-sized buffer when renaming/deleting a section,
2023-04-06), if a line is longer than 1024 characters, a malicious actor
can embed another command within an existing line, bypassing the usual
checks introduced in 9a6bbee800 (credential: avoid writing values with
newlines, 2020-03-11).

As with the problem fixed in that commit, specially crafted input can
cause the helper to return the credential for the wrong host, letting an
attacker trick the victim into sending credentials for one host to
another.

Luckily, all parts of the credential helper protocol that are available
in a tagged release of Git are immune to this attack:

  - "protocol" is restricted to known values, and is thus immune.

  - "host" is immune because curl will reject hostnames that have a '='
    character in them, which would be required to carry out this attack.

  - "username" is immune, because the buffer characters to fill out the
    first `fgets()` call would pollute the `username` field, causing the
    credential helper to return nothing (because it would match a
    username if present, and the username of the credential to be stolen
    is likely not 1024 characters).

  - "password" is immune because providing a password instructs
    credential helpers to avoid filling credentials in the first place.

  - "path" is similar to username; if present, it is not likely to match
    any credential the victim is storing. It's also not enabled by
    default; the victim would have to set credential.useHTTPPath
    explicitly.

However, the new "wwwauth[]" field introduced via 5f2117b24f
(credential: add WWW-Authenticate header to cred requests, 2023-02-27)
can be used to inject data into the credential helper stream. For
example, running:

    {
      printf 'HTTP/1.1 401\r\n'
      printf 'WWW-Authenticate: basic realm='
      perl -e 'print "a" x 1024'
      printf 'host=victim.com\r\n'
    } | nc -Nlp 8080

in one terminal, and then:

    git clone http://localhost:8080

in another would result in a line like:

    wwwauth[]=basic realm=aaa[...]aaahost=victim.com

being sent to the credential helper. If we tweak that "1024" to align
our output with the helper's buffer size and the rest of the data on the
line, it can cause the helper to see "host=victim.com" on its own line,
allowing motivated attackers to exfiltrate credentials belonging to
"victim.com".

The below test demonstrates these failures and provides us with a test
to ensure that our fix is correct. That said, it has a couple of
shortcomings:

  - it's in t0303, since that's the only mechanism we have for testing
    random helpers. But that means nobody is going to run it under
    normal circumstances.

  - to get the attack right, it has to line up the stuffed name with the
    buffer size, so we depend on the exact buffer size. I parameterized
    it so it could be used to test other helpers, but in practice it's
    not likely for anybody to do that.

Still, it's the best we can do, and will help us confirm the presence of
the problem (and our fixes) in the new few patches.

Co-authored-by: Jeff King &lt;peff@peff.net&gt;
Signed-off-by: Jeff King &lt;peff@peff.net&gt;
Signed-off-by: Taylor Blau &lt;me@ttaylorr.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
<entry>
<title>credential: new attribute oauth_refresh_token</title>
<updated>2023-04-21T16:38:30Z</updated>
<author>
<name>M Hickford</name>
<email>mirth.hickford@gmail.com</email>
</author>
<published>2023-04-21T09:47:59Z</published>
<link rel='alternate' type='text/html' href='https://git.shady.money/git/commit/?id=a5c76569e798ad3656afe6b67f37cbbb2e47f28c'/>
<id>urn:sha1:a5c76569e798ad3656afe6b67f37cbbb2e47f28c</id>
<content type='text'>
Git authentication with OAuth access token is supported by every popular
Git host including GitHub, GitLab and BitBucket [1][2][3]. Credential
helpers Git Credential Manager (GCM) and git-credential-oauth generate
OAuth credentials [4][5]. Following RFC 6749, the application prints a
link for the user to authorize access in browser. A loopback redirect
communicates the response including access token to the application.

For security, RFC 6749 recommends that OAuth response also includes
expiry date and refresh token [6]. After expiry, applications can use
the refresh token to generate a new access token without user
reauthorization in browser. GitLab and BitBucket set the expiry at two
hours [2][3]. (GitHub doesn't populate expiry or refresh token.)

However the Git credential protocol has no attribute to store the OAuth
refresh token (unrecognised attributes are silently discarded). This
means that the user has to regularly reauthorize the helper in browser.
On a browserless system, this is particularly intrusive, requiring a
second device.

Introduce a new attribute oauth_refresh_token. This is especially
useful when a storage helper and a read-only OAuth helper are configured
together. Recall that `credential fill` calls each helper until it has a
non-expired password.

```
[credential]
	helper = storage  # eg. cache or osxkeychain
	helper = oauth
```

The OAuth helper can use the stored refresh token forwarded by
`credential fill` to generate a fresh access token without opening the
browser. See
https://github.com/hickford/git-credential-oauth/pull/3/files
for an implementation tested with this patch.

Add support for the new attribute to credential-cache. Eventually, I
hope to see support in other popular storage helpers.

Alternatives considered: ask helpers to store all unrecognised
attributes. This seems excessively complex for no obvious gain.
Helpers would also need extra information to distinguish between
confidential and non-confidential attributes.

Workarounds: GCM abuses the helper get/store/erase contract to store the
refresh token during credential *get* as the password for a fictitious
host [7] (I wrote this hack). This workaround is only feasible for a
monolithic helper with its own storage.

[1] https://github.blog/2012-09-21-easier-builds-and-deployments-using-git-over-https-and-oauth/
[2] https://docs.gitlab.com/ee/api/oauth2.html#access-git-over-https-with-access-token
[3] https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/#Cloning-a-repository-with-an-access-token
[4] https://github.com/GitCredentialManager/git-credential-manager
[5] https://github.com/hickford/git-credential-oauth
[6] https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
[7] https://github.com/GitCredentialManager/git-credential-manager/blob/66b94e489ad8cc1982836355493e369770b30211/src/shared/GitLab/GitLabHostProvider.cs#L207

Signed-off-by: M Hickford &lt;mirth.hickford@gmail.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
</entry>
</feed>
