git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] credential: new attribute password_expiry_utc
@ 2023-01-28 14:04 M Hickford via GitGitGadget
  2023-01-29 20:17 ` Junio C Hamano
                   ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: M Hickford via GitGitGadget @ 2023-01-28 14:04 UTC (permalink / raw)
  To: git; +Cc: M Hickford, M Hickford

From: M Hickford <mirth.hickford@gmail.com>

If password has expired, credential fill no longer returns early,
so later helpers can generate a fresh credential. This is backwards
compatible -- no change in behaviour with helpers that discard the
expiry attribute. The expiry logic is entirely in the git credential
layer; compatible helpers simply store and return the expiry
attribute verbatim.

Store new attribute in cache.

Signed-off-by: M Hickford <mirth.hickford@gmail.com>
---
    credential: new attribute password_expiry_utc
    
    Some passwords, such as a personal access token or OAuth access token,
    may have an expiry date (as long as years for PATs or as short as hours
    for an OAuth access token). Add a new credential attribute
    password_expiry_utc.
    
    If password has expired, credential fill no longer returns early, so
    later helpers have opportunity to generate a fresh credential. This is
    backwards compatible -- no change in behaviour with helpers that discard
    the expiry attribute. The expiry logic is entirely in the git credential
    layer. Credential-generating helpers need only output the expiry
    attribute. Storage helpers should store the expiry if they can.
    
    Store expiry attribute in cache.
    
    This is particularly useful when a storage helper and a
    credential-generating helper are configured together, eg.
    
    [credential]
        helper = storage  # eg. cache or osxkeychain
        helper = generate  # eg. oauth
    
    
    Without this patch, credential fill may return an expired credential
    from storage, causing authentication to fail. With this patch: a fresh
    credential is generated if and only if the credential is expired.
    
    Example usage in a credential-generating helper
    https://github.com/hickford/git-credential-oauth/pull/16/files
    
    Signed-off-by: M Hickford mirth.hickford@gmail.com

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1443%2Fhickford%2Fpassword-expiry-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1443/hickford/password-expiry-v1
Pull-Request: https://github.com/git/git/pull/1443

 Documentation/git-credential.txt   |  4 ++++
 builtin/credential-cache--daemon.c |  3 +++
 credential.c                       | 21 +++++++++++++++++++++
 credential.h                       |  1 +
 4 files changed, 29 insertions(+)

diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index ac2818b9f66..15ace648bdd 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -144,6 +144,10 @@ Git understands the following attributes:
 
 	The credential's password, if we are asking it to be stored.
 
+`password_expiry_utc`::
+
+	If password is a personal access token or OAuth access token, it may have an expiry date. When getting credentials from a helper, `git credential fill` ignores the password attribute if the expiry date has passed. Storage helpers should store this attribute if possible. Helpers should not implement expiry logic themselves. Represented as Unix time UTC, seconds since 1970.
+
 `url`::
 
 	When this special attribute is read by `git credential`, the
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index f3c89831d4a..5cb8a186b45 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -127,6 +127,9 @@ static void serve_one_client(FILE *in, FILE *out)
 		if (e) {
 			fprintf(out, "username=%s\n", e->item.username);
 			fprintf(out, "password=%s\n", e->item.password);
+			if (e->item.password_expiry_utc != 0) {
+				fprintf(out, "password_expiry_utc=%ld\n", e->item.password_expiry_utc);
+			}
 		}
 	}
 	else if (!strcmp(action.buf, "exit")) {
diff --git a/credential.c b/credential.c
index f6389a50684..0a3a9cbf0a2 100644
--- a/credential.c
+++ b/credential.c
@@ -7,6 +7,7 @@
 #include "prompt.h"
 #include "sigchain.h"
 #include "urlmatch.h"
+#include <time.h>
 
 void credential_init(struct credential *c)
 {
@@ -21,6 +22,7 @@ void credential_clear(struct credential *c)
 	free(c->path);
 	free(c->username);
 	free(c->password);
+	c->password_expiry_utc = 0;
 	string_list_clear(&c->helpers, 0);
 
 	credential_init(c);
@@ -234,11 +236,23 @@ int credential_read(struct credential *c, FILE *fp)
 		} else if (!strcmp(key, "path")) {
 			free(c->path);
 			c->path = xstrdup(value);
+		} else if (!strcmp(key, "password_expiry_utc")) {
+			// TODO: ignore if can't parse integer
+			c->password_expiry_utc = atoi(value);
 		} else if (!strcmp(key, "url")) {
 			credential_from_url(c, value);
 		} else if (!strcmp(key, "quit")) {
 			c->quit = !!git_config_bool("quit", value);
 		}
+
+		// if expiry date has passed, ignore password and expiry fields
+		if (c->password_expiry_utc != 0 && time(NULL) > c->password_expiry_utc) {
+			trace_printf(_("Password has expired.\n"));
+			FREE_AND_NULL(c->username);
+			FREE_AND_NULL(c->password);
+			c->password_expiry_utc = 0;
+		}
+
 		/*
 		 * Ignore other lines; we don't know what they mean, but
 		 * this future-proofs us when later versions of git do
@@ -269,6 +283,13 @@ void credential_write(const struct credential *c, FILE *fp)
 	credential_write_item(fp, "path", c->path, 0);
 	credential_write_item(fp, "username", c->username, 0);
 	credential_write_item(fp, "password", c->password, 0);
+	if (c->password_expiry_utc != 0) {
+		int length = snprintf( NULL, 0, "%ld", c->password_expiry_utc);
+		char* str = malloc( length + 1 );
+		snprintf( str, length + 1, "%ld", c->password_expiry_utc );
+		credential_write_item(fp, "password_expiry_utc", str, 0);
+		free(str);
+	}
 }
 
 static int run_credential_helper(struct credential *c,
diff --git a/credential.h b/credential.h
index f430e77fea4..e10f7c2b313 100644
--- a/credential.h
+++ b/credential.h
@@ -126,6 +126,7 @@ struct credential {
 	char *protocol;
 	char *host;
 	char *path;
+	time_t password_expiry_utc;
 };
 
 #define CREDENTIAL_INIT { \

base-commit: 5cc9858f1b470844dea5c5d3e936af183fdf2c68
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2023-02-22 19:22 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-28 14:04 [PATCH] credential: new attribute password_expiry_utc M Hickford via GitGitGadget
2023-01-29 20:17 ` Junio C Hamano
2023-02-01  8:29   ` M Hickford
2023-02-01 18:50     ` Junio C Hamano
2023-01-30  0:59 ` Eric Sunshine
2023-02-05  6:49   ` M Hickford
2023-02-01  9:39 ` [PATCH v2] " M Hickford via GitGitGadget
2023-02-01 12:10   ` Jeff King
2023-02-01 17:12     ` Junio C Hamano
2023-02-02  0:12       ` Jeff King
2023-02-01 20:02     ` Matthew John Cheetham
2023-02-02  0:23       ` Jeff King
2023-02-05  6:45       ` M Hickford
2023-02-06 18:59         ` Matthew John Cheetham
2023-02-05  6:34     ` M Hickford
2023-02-04 21:16   ` [PATCH v3] " M Hickford via GitGitGadget
2023-02-14  1:59     ` Junio C Hamano
2023-02-14 22:36       ` M Hickford
2023-02-17 21:44         ` Lessley Dennington
2023-02-17 21:59           ` Junio C Hamano
2023-02-18  8:00             ` M Hickford
2023-02-14  8:03     ` Martin Ågren
2023-02-16 19:16     ` Calvin Wan
2023-02-18  8:00       ` M Hickford
2023-02-18  6:32     ` [PATCH v4] " M Hickford via GitGitGadget
2023-02-22 19:22       ` Calvin Wan

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).