Si usa protocolo SSH para conectar a los remotos, es posible tener una llave sin clave, lo que permite tranferir la data sin tener que escribir el nombre de usuario y la clave cada vez. Sin embargo, esto no es posible por el protocolo HTTP - cada conexión necesita usuario y contraseña. Esto se vuelve incluso más complicado para sistemas con autenticación de dos pasos, donde el token que se usa para la clave es generado al azar y no puede ser utilizado.
Afortunadamente, Git tiene un sistema de credenciales que lo ayuda con esto. Git tiene las siguientes funciones disponibles:
-
El default es no guardar cache para nada. Cada conexión solicitará el usuario y contraseña.
-
El modo ``cache'' mantiene las credenciales en memoria por un cierto periodo de tiempo. Ninguna de las claves es guardada en disco, y son borradas del cache tras 15 minutos.
-
El modo ``store'' guarda las credenciales en un archivo de texto plano en disco, y nunca expiran. Esto quiere decir que hasta que se cambie la contraseña en el host Git, no se necesitarán escribir credenciales de nuevo. La desventaja de este método es que sus claves son guardadas en texto plano en un archivo dentro de su máquina.
-
Si está usando Mac, Git viene con el modo ``osxkeychain'', el cual guarda en cache las credenciales en el llavero que está conectado a su cuenta de sistema. Este método guarda las claves en disco, y nunca expiran, pero están encriptadas con el mismo sistema que guarda los certificados HTTPS y los auto-completar de Safari.
-
Si está en Windows, puede installer un ayudante llamado
winstore.'' Este es similar al ayudante de
osxkeychain'' descrito arriba, pero usa Windows Credential Store para controlar la información sensible. Se puede encontrar en https://gitcredentialstore.codeplex.com.
Se puede elegir cualquiera de estos métodos mediante el valor de configuración de Git:
$ git config --global credential.helper cache
Algunos de estos ayudantes tienen opciones.
El modo `store'' puede tomar un argumento `--file <ruta>', el cual personaliza la ubicación final del archivo en texto plano (el default es `~/.git-credentials
).
El modo cache'' acepta la opción
900'', o 15 minutos).
Aquí hay un ejemplo de cómo configurar el modo ``store'' con un nombre de archivo personalizado:--timeout <segundos>
, la cual cambia la cantidad de tiempo que el demonio se mantiene en ejecución (el default es
$ git config --global credential.helper store --file ~/.my-credentials
Git incluso permite configurar varios modos.
Cuando se buscan por credenciales para un host en particular, Git las mostrará en orden, y se detendrá después que la primer respuesta sea entregada.
Cuando se guardan credenciales, Git mandará el usuario y contraseña a todos los modos en la lista, y se podrá elegir qué hacer con ellos.
Aquí se muestra cómo se vería un archivo .gitconfig
si tuviera un archivo de credenciales en una memoria, pero quisiera usar lo almacenado en cache cuando la memoria no esté conectada:
[credential]
helper = store --file /mnt/thumbdrive/.git-credentials
helper = cache --timeout 30000
¿Cómo funciona todo esto?
El comando raíz de Git para el asistente de credenciales es git credential
, el cual toma un comando como argumento, y luego más inputs por medio de stdin.
Esto podría ser más fácil de entender con un ejemplo.
Supongamos que un modo de credenciales ha sido configurado, y que el asistente a guardado credenciales para mygithost
.
Aquí hay una sesión que usa el comando ``fill'', el cual es invocado cuando Git está intentando encontrar credenciales para el host:
$ git credential fill (1)
protocol=https (2)
host=mygithost
(3)
protocol=https (4)
host=mygithost
username=bob
password=s3cre7
$ git credential fill (5)
protocol=https
host=unknownhost
Username for 'https://unknownhost': bob
Password for 'https://bob@unknownhost':
protocol=https
host=unknownhost
username=bob
password=s3cre7
-
Esta es el comando que inicia la interacción.
-
Git-credential entonces espera por un input en stdin. Nosotros lo proveemos con lo que conocemos: el protocolo y el nombre de host.
-
Una línea en blanco indica que el input está completo, y el sistema de credencial debería responder con lo que conoce.
-
Git-credential entonces entra en acción, y escribe en stdout los bits de información que encontró.
-
Si no se encuentran credenciales, Git pregunta al usuario por el usuario y la contraseña, y lo entrega de vuelta a stdout (aquí ya están conectados a la misma consola).
El sistema de credenciales en realidad está invocando un programa que está separado de Git; el que figura en el valor de configuración credential.helper
.
Hay varias formas que puede tomar:
Configuration Value | Behavior |
---|---|
|
Runs |
|
Runs |
|
Runs |
|
Code after |
Así, los modos descritos arriba en realidad se llaman git-credential-cache
, git-credential-store
, y en adelante, y los podemos configurar para que tomen argumentos de línea de comando.
La forma general para conseguirlo es ``git-credential-foo [args] <acción>.''
El protocolo stdin/stdout es el mismo que git-credential, pero usan un conjunto ligeramente distinto de acciones:
-
get
es una petición para un par usuario/contraseña. -
store
es una petición para guardar un grupo de credenciales en la memoria del modo. -
erase
purga las credenciales para las propiedades entregadas de la memoria del modo.
Para las acciones store
y erase
, no es necesaria una respuesta (Git la ignora de todos modos).
Para la acción get
, sin embargo, Git está muy interesado en lo que el modo tiene que decir.
Si el modo no sabe nada útil, puede simplemente salir sin mostrar inforamción, pero si sabe algo, debería aumentar la información provista con la información que ha almacenado.
El output es tratado como una serie de declaraciones de assignación; nada provista remplazará lo que Git ya conoce.
Aquí hay un ejemplo de lo explicado, pero saltando git-credential y yendo directo a git-credential-store:
$ git credential-store --file ~/git.store store (1)
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential-store --file ~/git.store get (2)
protocol=https
host=mygithost
username=bob (3)
password=s3cre7
-
Aquí decimos con
git-credential-store
que guarde las credenciales: usernamebob'' y la clave
s3cre7'' serán usadas cuando se accese ahttps://mygithost
. -
Ahora vamos a recibir las credenciales. Ahora proveemos las partes de la conexión que ya conocemos (
https://mygithost
), y una línea en blanco. -
git-credential-store
responde con el usuario y la contraseña que guardamos al comienzo.
Aquí se muestra cómo se vería ~/git.store
:
https://bob:s3cre7@mygithost
Es solamente una serie de líneas, cada una conteniendo una URL con credenciales.
Los modos osxkeychain
y winsoter
usan el formato nativo de sus almacenamientos, mientras cache
usa su propio formato en memoria (el cual no puede ser leído por ningún proceso).
Dado que git-credential-store
y amigos son programas separados de Git, no es difícil de notar que cualquier programa puede ser un asistente de credenciales de Git.
Los modos provistos por Git cubren muchos de los casos de uso, pero no todos.
Por ejemplo, supongamos que tu equipo tiene credenciales que son compartidas con el equipo entero, tal vez para despliegue.
Estas están guardadas en un directorio compartido, pero no deseas copiarlas a tu almacén de credenciales, porque cambian de manera seguida.
Ninguno de los modos existentes cubre este caso; veamos lo que tomaría para escribir tu propio modo.
Existen muchas funcionalidades clave que necesita tener este programa:
-
La única acción que necesitamos vigilar es
get
;store
yerase
son operaciones de escritura, así que solo saldremos limpiamente cuando sean recibidas. -
El formato de archivo de la credencial compartida es el mismo que se usa por
git-credential-store
. -
La ubicación de ese archivo es relativamente estándar, pero deberías permitir al usuario entregar una ruta alterna por si acaso.
Una vez más, vamos a escribir esta extensión en Ruby, pero cualquier lenguaje funcionará siempre y cuando Git pueda ejecutar el producto final. Aquí está el código de nuestro nuevo asistente de credenciales:
link:../git-credential-read-only[role=include]
-
Aquí analizamos las opciones de la línea de comando, permitiendo al usuario especificar un archivo. El default es
~/.git-credentials
. -
Este programa solo responde si la acción es
get
y el archivo de almacenamiento existe. -
Este bucle lee de stdin hasta que se encuentre la primer línea en blanco. Los input son guardadoes en el hash
known
para una posterior referencia. -
Este bucle lee el contenido del archivo de almacenamiento, buscando por concordancias. Si el protocolo y el host de
known
concuerdan con la línea, el programa imprime el resultado a stdout y sale.
Guardaremos nuestro modo como git-credential-read-only
, ponlo en algún lugar en nuestro PATH
y lo marcamos como ejecutable.
Aquí se muestra cómo se vería una sessión interactiva:
$ git credential-read-only --file=/mnt/shared/creds get
protocol=https
host=mygithost
protocol=https
host=mygithost
username=bob
password=s3cre7
Dado que su nombre comienza con ``git-'', podemos usar la sintaxis simple para el valor de configuración:
$ git config --global credential.helper read-only --file /mnt/shared/creds
Como se puede apreciar, extender este sistema es bastante sencillo, y puede resolver algunos problemas comunes para usted y su equipo.