From: "Lukas Sandström" <luksan@gmail.com>
To: Jeff King <peff@peff.net>
Cc: "Lukas Sandström" <luksan@gmail.com>,
"Git Mailing List" <git@vger.kernel.org>
Subject: [PATCH v2] Add a credential-helper for KDE
Date: Sun, 18 Sep 2011 16:52:58 +0200 [thread overview]
Message-ID: <4E7605CA.7020204@gmail.com> (raw)
In-Reply-To: <20110831014237.GA2519@sigill.intra.peff.net>
This Python script plugs into the credentials API
of Git to ask the user for passwords with a nice
KDE password dialog.
The password is saved in the KWallet.
Signed-off-by: Lukas Sandström <luksan@gmail.com>
---
On 2011-08-31 03:42, Jeff King wrote:
> Can we call it git-credential-kdewallet or similar? Then users can just
> do:
>
> git config credential.helper kdewallet
>
> (where "kdewallet" can be whatever you think is most appropriate; the
> key is naming it git-credential-*).
Done.
[...]
> If I am reading this correctly, you look up based purely on the context
> token. Which means that if I do something like this:
>
> $ git push https://host.com/repo.git
> [enter username: user1, password: foo]
> $ git push https://user2@host.com/other-repo.git
>
> We will invoke the helper as:
>
> git credential-kdewallet --unique=https:host.com --username=user2
>
> but the helper will ignore the "user2" bit, and return "user1 / foo".
>
> The "cache" helper I wrote handles this situation better, by indexing
> both on the token and the username. I wonder if the username should
> become part of the token. Or if the token should really just become a
> canonicalized URL, minus the actual path. So the first one would get:
>
> --unique=https://host.com
>
> and the second would get:
>
> --unique=https://user2@host.com
>
> Then helpers wouldn't need to worry about doing anything special.
>
> What do you think? Also, any comments in general on writing a helper?
> You are the first one besides me to do so. Did you find anything in the
> interface or the documentation confusing? Suggestions are very welcome,
> as nothing has been released yet and we're free to tweak as much as we
> want.
>
> -Peff
Right. Multiple usernames per "unique" context is supported in this version.
I looked at the git-credential-storage helper when I wrote the first patch,
which didn't have obvious support for multiple usernames per unique context.
Keeping the username outside the token is probably a good thing, but perhaps it
should be clarified in the api-docs that multiple usernames has to be supported.
Also; what about rejecting credentials. This code currently deletes just a
username/password pair if a username is specified, and all credentials associated
with the token if only --unique and --reject is specified. Is this correct/expected
behavior?
When I first wrote the helper I tried to immediately ask for a new password if a
credential was rejected, but this didn't work with the HTTP auth code, since it
doesn't retry the auth with the new credentials after a reject. I think it would
be better if we asked for a new password instead of just saying "auth failed" and
having the user retry the fetch/pull when the stored credentials are incorrect.
/Lkas
.../git-credential-kdewallet.py | 137 ++++++++++++++++++++
1 files changed, 137 insertions(+), 0 deletions(-)
create mode 100755 contrib/git-credential-kdewallet/git-credential-kdewallet.py
diff --git a/contrib/git-credential-kdewallet/git-credential-kdewallet.py b/contrib/git-credential-kdewallet/git-credential-kdewallet.py
new file mode 100755
index 0000000..29c4ae1
--- /dev/null
+++ b/contrib/git-credential-kdewallet/git-credential-kdewallet.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+# encoding=utf-8
+#
+# Copyright 2011, Lukas Sandström
+#
+# Licensed under the GPL version 2.
+
+import sys
+from PyQt4.QtCore import QString
+from PyKDE4.kdecore import i18n, ki18n, KAboutData, KCmdLineArgs, KCmdLineOptions
+from PyKDE4.kdeui import KApplication, KWallet, KPasswordDialog
+
+appName = "git-credential-kdewallet"
+catalog = ""
+programName = ki18n ("Git KDE credentials helper")
+version = "0.1"
+description = ki18n ("Credentials storage helper for Git")
+license = KAboutData.License_GPL_V2
+copyright = ki18n ("(c) 2011 Lukas Sandström")
+text = ki18n ("none")
+homePage = "http://www.git-scm.com"
+bugEmail = "luksan@gmail.com"
+
+aboutData = KAboutData (appName, catalog, programName, version, description,
+ license, copyright, text, homePage, bugEmail)
+
+class CredentialHelper(KApplication):
+ def __init__(self, token, username = None, desc = None, reject = False):
+ super(CredentialHelper, self).__init__()
+ self.password = None
+ self.username = username
+ self.save_password = False
+ self.token = token
+ self.desc = desc
+
+ if not self.token:
+ return
+
+ self.open_wallet()
+
+ if reject:
+ self.reject_credential()
+ return
+
+ if not self.check_wallet():
+ self.ask_password_dialog()
+
+ if self.save_password:
+ self.store_password()
+
+ self.output_credentials()
+
+ def output_credentials(self):
+ if self.username:
+ print "username=" + self.username
+ if self.password:
+ print "password=" + self.password
+
+ def reject_credential(self):
+ (res, data) = self.wallet.readMap(self.token)
+ if self.username:
+ try:
+ del data[QString(self.username)]
+ except KeyError:
+ pass
+ self.wallet.writeMap(self.token, data)
+ else:
+ self.wallet.removeEntry(self.token)
+
+ def store_password(self):
+ (res, data) = self.wallet.readMap(self.token)
+ data[QString(self.username)] = QString(self.password)
+ self.wallet.writeMap(QString(self.token), data)
+
+ def open_wallet(self):
+ self.wallet = KWallet.Wallet.openWallet(
+ KWallet.Wallet.LocalWallet(), 0, KWallet.Wallet.Synchronous)
+ if not self.wallet.isOpen():
+ return None
+ if not self.wallet.hasFolder("GitCredentials"):
+ self.wallet.createFolder("GitCredentials")
+ self.wallet.setFolder("GitCredentials")
+
+ def check_wallet(self):
+ (res, data) = self.wallet.readMap(self.token)
+ if res != 0:
+ return None
+ for u, p in data.iteritems():
+ # Pick the first complete credential if no username is specified
+ if not self.username and u and p:
+ self.username = u
+ self.password = p
+ return True
+ if self.username == u:
+ self.password = p
+ return True
+ return None
+
+ def ask_password_dialog(self):
+ dlg = KPasswordDialog(None,
+ KPasswordDialog.KPasswordDialogFlag(
+ KPasswordDialog.ShowKeepPassword |
+ KPasswordDialog.ShowUsernameLine))
+ if self.desc:
+ desc = self.desc
+ else:
+ desc = self.token
+ dlg.setPrompt(i18n("Please enter username and password for %s" % (desc)))
+ dlg.setUsername(self.username)
+ dlg.setKeepPassword(True)
+ if not dlg.exec_():
+ return
+ self.username = dlg.username()
+ self.password = dlg.password()
+ self.save_password = dlg.keepPassword()
+
+def main():
+ KCmdLineArgs.init(sys.argv, aboutData)
+
+ options = KCmdLineOptions()
+ options.add("unique <token>", ki18n("Unique token identifying the credential"))
+ options.add("description <desc>", ki18n("Human readable description of the credential"))
+ options.add("username <username>", ki18n("Requested username"))
+ options.add("reject", ki18n("Purge credential"))
+
+ KCmdLineArgs.addCmdLineOptions(options)
+ args = KCmdLineArgs.parsedArgs();
+
+ username = args.getOption("username")
+ token = args.getOption("unique")
+ desc = args.getOption("description")
+ reject = args.isSet("reject")
+
+ app = CredentialHelper(token, username, desc, reject)
+
+if __name__ == "__main__":
+ main()
--
1.7.6.1
next prev parent reply other threads:[~2011-09-18 14:53 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-27 19:54 [PATCH] Add a credential-helper for KDE Lukas Sandström
2011-08-31 1:42 ` Jeff King
2011-09-18 14:52 ` Lukas Sandström [this message]
2011-09-18 18:49 ` [PATCH v2] " Jeff King
2011-09-30 10:21 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4E7605CA.7020204@gmail.com \
--to=luksan@gmail.com \
--cc=git@vger.kernel.org \
--cc=peff@peff.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.