##// END OF EJS Templates
Proofs
Marcin Kasperski -
r5:4a547d17 default
parent child Browse files
Show More
@@ -1,126 +1,137 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 """
3 """
4 Storing HTTP authentication passwords in keyring database.
4 Storing HTTP authentication passwords in keyring database.
5
5
6 Installation method(s):
6 Installation method(s):
7
7
8 1) in ~/.hgrc (or /etc/hgext/...)
8 1) in ~/.hgrc (or /etc/hgext/...)
9
9
10 [extensions]
10 [extensions]
11 ...
11 ...
12 hgext.mercurial_keyring = /path/to/mercurial_keyring.py
12 hgext.mercurial_keyring = /path/to/mercurial_keyring.py
13
13
14
14
15 2) Drop this file to hgext directory and in ~/.hgrc
15 2) Drop this file to hgext directory and in ~/.hgrc
16
16
17 [extensions]
17 [extensions]
18 hgext.mercurial_keyring =
18 hgext.mercurial_keyring =
19
19
20 """
20 """
21
21
22 #import mercurial.demandimport
22 #import mercurial.demandimport
23 #mercurial.demandimport.disable()
23 #mercurial.demandimport.disable()
24
24
25 from mercurial import hg, repo, util
25 from mercurial import hg, repo, util
26 from mercurial.i18n import _
26 from mercurial.i18n import _
27 try:
27 try:
28 from mercurial.url import passwordmgr
28 from mercurial.url import passwordmgr
29 except:
29 except:
30 from mercurial.httprepo import passwordmgr
30 from mercurial.httprepo import passwordmgr
31
31
32 import keyring
32 import keyring
33 import getpass
33 import getpass
34 from urlparse import urlparse
34 from urlparse import urlparse
35 import urllib2
35 import urllib2
36
36
37 KEYRING_SERVICE = "Mercurial"
37 KEYRING_SERVICE = "Mercurial"
38
38
39 ############################################################
39 ############################################################
40
40
41 def monkeypatch_class(name, bases, namespace):
41 def monkeypatch_class(name, bases, namespace):
42 """http://mail.python.org/pipermail/python-dev/2008-January/076194.html"""
42 """http://mail.python.org/pipermail/python-dev/2008-January/076194.html"""
43 assert len(bases) == 1, "Exactly one base class required"
43 assert len(bases) == 1, "Exactly one base class required"
44 base = bases[0]
44 base = bases[0]
45 for name, value in namespace.iteritems():
45 for name, value in namespace.iteritems():
46 if name != "__metaclass__":
46 if name != "__metaclass__":
47 setattr(base, name, value)
47 setattr(base, name, value)
48 return base
48 return base
49
49
50 def monkeypatch_method(cls):
50 def monkeypatch_method(cls):
51 def decorator(func):
51 def decorator(func):
52 setattr(cls, func.__name__, func)
52 setattr(cls, func.__name__, func)
53 return func
53 return func
54 return decorator
54 return decorator
55
55
56 ############################################################
56 ############################################################
57
57
58 class PasswordStore(object):
58 class PasswordStore(object):
59 """
59 """
60 Helper object handling password save&restore. Passwords
60 Helper object handling password save&restore. Passwords
61 are saved both in local memory cache, and keyring, and are
61 are saved both in local memory cache, and keyring, and are
62 restored from those.
62 restored from those.
63 """
63 """
64 def __init__(self):
64 def __init__(self):
65 self.cache = dict()
65 self.cache = dict()
66 def save_password(self, url, username, password):
66 def save_password(self, url, username, password):
67 self.cache[url] = (username, password)
67 self.cache[url] = (username, password)
68 # TODO: keyring save
68 # TODO: keyring save
69 def get_password(self, url):
69 def get_password(self, url):
70 r = self.cache.get(url)
70 r = self.cache.get(url)
71 if r:
71 if r:
72 return r
72 return r
73 # TODO: keyring restore
73 # TODO: keyring restore
74 return None, None
74 return None, None
75
75
76 password_store = PasswordStore()
76 password_store = PasswordStore()
77
77
78 ############################################################
78 ############################################################
79
79
80 @monkeypatch_method(passwordmgr)
80 @monkeypatch_method(passwordmgr)
81 def find_user_password(self, realm, authuri):
81 def find_user_password(self, realm, authuri):
82 """
82 """
83 keyring-based implementation of username/password query
83 keyring-based implementation of username/password query
84
84
85 Passwords are saved in gnome keyring, OSX/Chain or other platform
85 Passwords are saved in gnome keyring, OSX/Chain or other platform
86 specific storage and keyed by the repository url
86 specific storage and keyed by the repository url
87 """
87 """
88 # Calculate the true url. authuri happens to contain things like
88 # Calculate the true url. authuri happens to contain things like
89 # https://repo.machine.com/repos/apps/module?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between
89 # https://repo.machine.com/repos/apps/module?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between
90 parsed_url = urlparse(authuri)
90 parsed_url = urlparse(authuri)
91 base_url = "%s://%s%s" % (parsed_url.scheme, parsed_url.netloc, parsed_url.path)
91 base_url = "%s://%s%s" % (parsed_url.scheme, parsed_url.netloc, parsed_url.path)
92
92
93 # Problem: self.ui describes the *remote* repository, therefore
94 # does *not* contain options from local .hg/hgrc. No way
95 # to read options from [auth] (username!) using self.ui.
96
97
93 #from mercurial import commands, hg
98 #from mercurial import commands, hg
94 #commands.showconfig(self.ui, hg.repository(self.ui, '.'))
99 #commands.showconfig(self.ui, hg.repository(self.ui, '.'))
100 #for section, name, value in self.ui.walkconfig():
101 # if not section in [ "merge-tools", "extensions" ]:
102 # print "cfg", section, name, value
95
103
96 for section, name, value in self.ui.walkconfig():
104 print "self", self.__dict__
97 print "cfg", section, name, value
105 print "self.ui", self.ui.__dict__
106 print "self.ui._tcfg", self.ui._tcfg.__dict__
107 print "self.ui._ocfg", self.ui._ocfg.__dict__
108 print "self.ui._ucfg", self.ui._ucfg.__dict__
98
109
99 # Extracting possible username/password stored in repository url
110 # Extracting possible username/password stored in repository url
100 user, pwd = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(self, realm, authuri)
111 user, pwd = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(self, realm, authuri)
101
112
102 auth_token = self.readauthtoken(base_url)
113 auth_token = self.readauthtoken(base_url)
103 print "token", auth_token
114 print "token", auth_token
104 print "configitems", list(self.ui.configitems('auth'))
115 print "configitems", list(self.ui.configitems('auth'))
105 print "configitems", list(self.ui.configitems('auth', untrusted=True))
116 print "configitems", list(self.ui.configitems('auth', untrusted=True))
106 print "configitems", list(self.ui.configitems('paths'))
117 print "configitems", list(self.ui.configitems('paths'))
107 print self.ui
118 print self.ui
108
119
109 print "find_user_password", realm, base_url, user, pwd, auth_token
120 print "find_user_password", realm, base_url, user, pwd, auth_token
110
121
111 user, pwd = password_store.get_password(base_url)
122 user, pwd = password_store.get_password(base_url)
112 if user and pwd:
123 if user and pwd:
113 return user, pwd
124 return user, pwd
114
125
115 if not self.ui.interactive():
126 if not self.ui.interactive():
116 raise util.Abort(_('mercurial_keyring: http authorization required'))
127 raise util.Abort(_('mercurial_keyring: http authorization required'))
117 self.ui.write(_("http authorization required\n"))
128 self.ui.write(_("http authorization required\n"))
118 self.ui.status(_("realm: %s, url: %s\n" % (realm, base_url)))
129 self.ui.status(_("realm: %s, url: %s\n" % (realm, base_url)))
119 user = self.ui.prompt(_("user:"), default = user)
130 user = self.ui.prompt(_("user:"), default = user)
120 pwd = self.ui.getpass(_("password: "))
131 pwd = self.ui.getpass(_("password: "))
121
132
122 password_store.save_password(base_url, user, pwd)
133 password_store.save_password(base_url, user, pwd)
123
134
124 return user, pwd
135 return user, pwd
125 #return None, None
136 #return None, None
126
137
General Comments 0
You need to be logged in to leave comments. Login now