Merge branch 'jk/credentials'

* jk/credentials:
  t: add test harness for external credential helpers
  credentials: add "store" helper
  strbuf: add strbuf_add*_urlencode
  Makefile: unix sockets may not available on some platforms
  credentials: add "cache" helper
  docs: end-user documentation for the credential subsystem
  credential: make relevance of http path configurable
  credential: add credential.*.username
  credential: apply helper config
  http: use credential API to get passwords
  credential: add function for parsing url components
  introduce credentials API
  t5550: fix typo
  test-lib: add test_config_global variant

Conflicts:
	strbuf.c
This commit is contained in:
Junio C Hamano
2011-12-19 16:05:16 -08:00
28 changed files with 2426 additions and 99 deletions

View File

@ -7,6 +7,7 @@ MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt \
MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \
gitcvs-migration.txt gitcore-tutorial.txt gitglossary.txt \
gitdiffcore.txt gitnamespaces.txt gitrevisions.txt gitworkflows.txt
MAN7_TXT += gitcredentials.txt
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))

View File

@ -834,6 +834,29 @@ commit.template::
"{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
specified user's home directory.
credential.helper::
Specify an external helper to be called when a username or
password credential is needed; the helper may consult external
storage to avoid prompting the user for the credentials. See
linkgit:gitcredentials[7] for details.
credential.useHttpPath::
When acquiring credentials, consider the "path" component of an http
or https URL to be important. Defaults to false. See
linkgit:gitcredentials[7] for more information.
credential.username::
If no username is set for a network authentication, use this username
by default. See credential.<context>.* below, and
linkgit:gitcredentials[7].
credential.<url>.*::
Any of the credential.* options above can be applied selectively to
some credentials. For example "credential.https://example.com.username"
would set the default username only for https connections to
example.com. See linkgit:gitcredentials[7] for details on how URLs are
matched.
include::diff-config.txt[]
difftool.<tool>.path::

View File

@ -0,0 +1,26 @@
git-credential-cache--daemon(1)
===============================
NAME
----
git-credential-cache--daemon - temporarily store user credentials in memory
SYNOPSIS
--------
[verse]
git credential-cache--daemon <socket>
DESCRIPTION
-----------
NOTE: You probably don't want to invoke this command yourself; it is
started automatically when you use linkgit:git-credential-cache[1].
This command listens on the Unix domain socket specified by `<socket>`
for `git-credential-cache` clients. Clients may store and retrieve
credentials. Each credential is held for a timeout specified by the
client; once no credentials are held, the daemon exits.
GIT
---
Part of the linkgit:git[1] suite

View File

@ -0,0 +1,77 @@
git-credential-cache(1)
=======================
NAME
----
git-credential-cache - helper to temporarily store passwords in memory
SYNOPSIS
--------
-----------------------------
git config credential.helper 'cache [options]'
-----------------------------
DESCRIPTION
-----------
This command caches credentials in memory for use by future git
programs. The stored credentials never touch the disk, and are forgotten
after a configurable timeout. The cache is accessible over a Unix
domain socket, restricted to the current user by filesystem permissions.
You probably don't want to invoke this command directly; it is meant to
be used as a credential helper by other parts of git. See
linkgit:gitcredentials[7] or `EXAMPLES` below.
OPTIONS
-------
--timeout <seconds>::
Number of seconds to cache credentials (default: 900).
--socket <path>::
Use `<path>` to contact a running cache daemon (or start a new
cache daemon if one is not started). Defaults to
`~/.git-credential-cache/socket`. If your home directory is on a
network-mounted filesystem, you may need to change this to a
local filesystem.
CONTROLLING THE DAEMON
----------------------
If you would like the daemon to exit early, forgetting all cached
credentials before their timeout, you can issue an `exit` action:
--------------------------------------
git credential-cache exit
--------------------------------------
EXAMPLES
--------
The point of this helper is to reduce the number of times you must type
your username or password. For example:
------------------------------------
$ git config credential.helper cache
$ git push http://example.com/repo.git
Username: <type your username>
Password: <type your password>
[work for 5 more minutes]
$ git push http://example.com/repo.git
[your credentials are used automatically]
------------------------------------
You can provide options via the credential.helper configuration
variable (this example drops the cache time to 5 minutes):
-------------------------------------------------------
$ git config credential.helper 'cache --timeout=300'
-------------------------------------------------------
GIT
---
Part of the linkgit:git[1] suite

View File

@ -0,0 +1,75 @@
git-credential-store(1)
=======================
NAME
----
git-credential-store - helper to store credentials on disk
SYNOPSIS
--------
-------------------
git config credential.helper 'store [options]'
-------------------
DESCRIPTION
-----------
NOTE: Using this helper will store your passwords unencrypted on disk,
protected only by filesystem permissions. If this is not an acceptable
security tradeoff, try linkgit:git-credential-cache[1], or find a helper
that integrates with secure storage provided by your operating system.
This command stores credentials indefinitely on disk for use by future
git programs.
You probably don't want to invoke this command directly; it is meant to
be used as a credential helper by other parts of git. See
linkgit:gitcredentials[7] or `EXAMPLES` below.
OPTIONS
-------
--store=<path>::
Use `<path>` to store credentials. The file will have its
filesystem permissions set to prevent other users on the system
from reading it, but will not be encrypted or otherwise
protected. Defaults to `~/.git-credentials`.
EXAMPLES
--------
The point of this helper is to reduce the number of times you must type
your username or password. For example:
------------------------------------------
$ git config credential.helper store
$ git push http://example.com/repo.git
Username: <type your username>
Password: <type your password>
[several days later]
$ git push http://example.com/repo.git
[your credentials are used automatically]
------------------------------------------
STORAGE FORMAT
--------------
The `.git-credentials` file is stored in plaintext. Each credential is
stored on its own line as a URL like:
------------------------------
https://user:pass@example.com
------------------------------
When git needs authentication for a particular URL context,
credential-store will consider that context a pattern to match against
each entry in the credentials file. If the protocol, hostname, and
username (if we already have one) match, then the password is returned
to git. See the discussion of configuration in linkgit:gitcredentials[7]
for more information.
GIT
---
Part of the linkgit:git[1] suite

View File

@ -0,0 +1,183 @@
gitcredentials(7)
=================
NAME
----
gitcredentials - providing usernames and passwords to git
SYNOPSIS
--------
------------------
git config credential.https://example.com.username myusername
git config credential.helper "$helper $options"
------------------
DESCRIPTION
-----------
Git will sometimes need credentials from the user in order to perform
operations; for example, it may need to ask for a username and password
in order to access a remote repository over HTTP. This manual describes
the mechanisms git uses to request these credentials, as well as some
features to avoid inputting these credentials repeatedly.
REQUESTING CREDENTIALS
----------------------
Without any credential helpers defined, git will try the following
strategies to ask the user for usernames and passwords:
1. If the `GIT_ASKPASS` environment variable is set, the program
specified by the variable is invoked. A suitable prompt is provided
to the program on the command line, and the user's input is read
from its standard output.
2. Otherwise, if the `core.askpass` configuration variable is set, its
value is used as above.
3. Otherwise, if the `SSH_ASKPASS` environment variable is set, its
value is used as above.
4. Otherwise, the user is prompted on the terminal.
AVOIDING REPETITION
-------------------
It can be cumbersome to input the same credentials over and over. Git
provides two methods to reduce this annoyance:
1. Static configuration of usernames for a given authentication context.
2. Credential helpers to cache or store passwords, or to interact with
a system password wallet or keychain.
The first is simple and appropriate if you do not have secure storage available
for a password. It is generally configured by adding this to your config:
---------------------------------------
[credential "https://example.com"]
username = me
---------------------------------------
Credential helpers, on the other hand, are external programs from which git can
request both usernames and passwords; they typically interface with secure
storage provided by the OS or other programs.
To use a helper, you must first select one to use. Git currently
includes the following helpers:
cache::
Cache credentials in memory for a short period of time. See
linkgit:git-credential-cache[1] for details.
store::
Store credentials indefinitely on disk. See
linkgit:git-credential-store[1] for details.
You may also have third-party helpers installed; search for
`credential-*` in the output of `git help -a`, and consult the
documentation of individual helpers. Once you have selected a helper,
you can tell git to use it by putting its name into the
credential.helper variable.
1. Find a helper.
+
-------------------------------------------
$ git help -a | grep credential-
credential-foo
-------------------------------------------
2. Read its description.
+
-------------------------------------------
$ git help credential-foo
-------------------------------------------
3. Tell git to use it.
+
-------------------------------------------
$ git config --global credential.helper foo
-------------------------------------------
If there are multiple instances of the `credential.helper` configuration
variable, each helper will be tried in turn, and may provide a username,
password, or nothing. Once git has acquired both a username and a
password, no more helpers will be tried.
CREDENTIAL CONTEXTS
-------------------
Git considers each credential to have a context defined by a URL. This context
is used to look up context-specific configuration, and is passed to any
helpers, which may use it as an index into secure storage.
For instance, imagine we are accessing `https://example.com/foo.git`. When git
looks into a config file to see if a section matches this context, it will
consider the two a match if the context is a more-specific subset of the
pattern in the config file. For example, if you have this in your config file:
--------------------------------------
[credential "https://example.com"]
username = foo
--------------------------------------
then we will match: both protocols are the same, both hosts are the same, and
the "pattern" URL does not care about the path component at all. However, this
context would not match:
--------------------------------------
[credential "https://kernel.org"]
username = foo
--------------------------------------
because the hostnames differ. Nor would it match `foo.example.com`; git
compares hostnames exactly, without considering whether two hosts are part of
the same domain. Likewise, a config entry for `http://example.com` would not
match: git compares the protocols exactly.
CONFIGURATION OPTIONS
---------------------
Options for a credential context can be configured either in
`credential.\*` (which applies to all credentials), or
`credential.<url>.\*`, where <url> matches the context as described
above.
The following options are available in either location:
helper::
The name of an external credential helper, and any associated options.
If the helper name is not an absolute path, then the string `git
credential-` is prepended. The resulting string is executed by the
shell (so, for example, setting this to `foo --option=bar` will execute
`git credential-foo --option=bar` via the shell. See the manual of
specific helpers for examples of their use.
username::
A default username, if one is not provided in the URL.
useHttpPath::
By default, git does not consider the "path" component of an http URL
to be worth matching via external helpers. This means that a credential
stored for `https://example.com/foo.git` will also be used for
`https://example.com/bar.git`. If you do want to distinguish these
cases, set this option to `true`.
CUSTOM HELPERS
--------------
You can write your own custom helpers to interface with any system in
which you keep credentials. See the documentation for git's
link:technical/api-credentials.html[credentials API] for details.
GIT
---
Part of the linkgit:git[1] suite

View File

@ -0,0 +1,245 @@
credentials API
===============
The credentials API provides an abstracted way of gathering username and
password credentials from the user (even though credentials in the wider
world can take many forms, in this document the word "credential" always
refers to a username and password pair).
Data Structures
---------------
`struct credential`::
This struct represents a single username/password combination
along with any associated context. All string fields should be
heap-allocated (or NULL if they are not known or not applicable).
The meaning of the individual context fields is the same as
their counterparts in the helper protocol; see the section below
for a description of each field.
+
The `helpers` member of the struct is a `string_list` of helpers. Each
string specifies an external helper which will be run, in order, to
either acquire or store credentials. See the section on credential
helpers below.
+
This struct should always be initialized with `CREDENTIAL_INIT` or
`credential_init`.
Functions
---------
`credential_init`::
Initialize a credential structure, setting all fields to empty.
`credential_clear`::
Free any resources associated with the credential structure,
returning it to a pristine initialized state.
`credential_fill`::
Instruct the credential subsystem to fill the username and
password fields of the passed credential struct by first
consulting helpers, then asking the user. After this function
returns, the username and password fields of the credential are
guaranteed to be non-NULL. If an error occurs, the function will
die().
`credential_reject`::
Inform the credential subsystem that the provided credentials
have been rejected. This will cause the credential subsystem to
notify any helpers of the rejection (which allows them, for
example, to purge the invalid credentials from storage). It
will also free() the username and password fields of the
credential and set them to NULL (readying the credential for
another call to `credential_fill`). Any errors from helpers are
ignored.
`credential_approve`::
Inform the credential subsystem that the provided credentials
were successfully used for authentication. This will cause the
credential subsystem to notify any helpers of the approval, so
that they may store the result to be used again. Any errors
from helpers are ignored.
`credential_from_url`::
Parse a URL into broken-down credential fields.
Example
-------
The example below shows how the functions of the credential API could be
used to login to a fictitious "foo" service on a remote host:
-----------------------------------------------------------------------
int foo_login(struct foo_connection *f)
{
int status;
/*
* Create a credential with some context; we don't yet know the
* username or password.
*/
struct credential c = CREDENTIAL_INIT;
c.protocol = xstrdup("foo");
c.host = xstrdup(f->hostname);
/*
* Fill in the username and password fields by contacting
* helpers and/or asking the user. The function will die if it
* fails.
*/
credential_fill(&c);
/*
* Otherwise, we have a username and password. Try to use it.
*/
status = send_foo_login(f, c.username, c.password);
switch (status) {
case FOO_OK:
/* It worked. Store the credential for later use. */
credential_accept(&c);
break;
case FOO_BAD_LOGIN:
/* Erase the credential from storage so we don't try it
* again. */
credential_reject(&c);
break;
default:
/*
* Some other error occured. We don't know if the
* credential is good or bad, so report nothing to the
* credential subsystem.
*/
}
/* Free any associated resources. */
credential_clear(&c);
return status;
}
-----------------------------------------------------------------------
Credential Helpers
------------------
Credential helpers are programs executed by git to fetch or save
credentials from and to long-term storage (where "long-term" is simply
longer than a single git process; e.g., credentials may be stored
in-memory for a few minutes, or indefinitely on disk).
Each helper is specified by a single string. The string is transformed
by git into a command to be executed using these rules:
1. If the helper string begins with "!", it is considered a shell
snippet, and everything after the "!" becomes the command.
2. Otherwise, if the helper string begins with an absolute path, the
verbatim helper string becomes the command.
3. Otherwise, the string "git credential-" is prepended to the helper
string, and the result becomes the command.
The resulting command then has an "operation" argument appended to it
(see below for details), and the result is executed by the shell.
Here are some example specifications:
----------------------------------------------------
# run "git credential-foo"
foo
# same as above, but pass an argument to the helper
foo --bar=baz
# the arguments are parsed by the shell, so use shell
# quoting if necessary
foo --bar="whitespace arg"
# you can also use an absolute path, which will not use the git wrapper
/path/to/my/helper --with-arguments
# or you can specify your own shell snippet
!f() { echo "password=`cat $HOME/.secret`"; }; f
----------------------------------------------------
Generally speaking, rule (3) above is the simplest for users to specify.
Authors of credential helpers should make an effort to assist their
users by naming their program "git-credential-$NAME", and putting it in
the $PATH or $GIT_EXEC_PATH during installation, which will allow a user
to enable it with `git config credential.helper $NAME`.
When a helper is executed, it will have one "operation" argument
appended to its command line, which is one of:
`get`::
Return a matching credential, if any exists.
`store`::
Store the credential, if applicable to the helper.
`erase`::
Remove a matching credential, if any, from the helper's storage.
The details of the credential will be provided on the helper's stdin
stream. The credential is split into a set of named attributes.
Attributes are provided to the helper, one per line. Each attribute is
specified by a key-value pair, separated by an `=` (equals) sign,
followed by a newline. The key may contain any bytes except `=`,
newline, or NUL. The value may contain any bytes except newline or NUL.
In both cases, all bytes are treated as-is (i.e., there is no quoting,
and one cannot transmit a value with newline or NUL in it). The list of
attributes is terminated by a blank line or end-of-file.
Git will send the following attributes (but may not send all of
them for a given credential; for example, a `host` attribute makes no
sense when dealing with a non-network protocol):
`protocol`::
The protocol over which the credential will be used (e.g.,
`https`).
`host`::
The remote hostname for a network credential.
`path`::
The path with which the credential will be used. E.g., for
accessing a remote https repository, this will be the
repository's path on the server.
`username`::
The credential's username, if we already have one (e.g., from a
URL, from the user, or from a previously run helper).
`password`::
The credential's password, if we are asking it to be stored.
For a `get` operation, the helper should produce a list of attributes
on stdout in the same format. A helper is free to produce a subset, or
even no values at all if it has nothing useful to provide. Any provided
attributes will overwrite those already known about by git.
For a `store` or `erase` operation, the helper's output is ignored.
If it fails to perform the requested operation, it may complain to
stderr to inform the user. If it does not support the requested
operation (e.g., a read-only store), it should silently ignore the
request.
If a helper receives any other operation, it should silently ignore the
request. This leaves room for future operations to be added (older
helpers will just ignore the new requests).