##// END OF EJS Templates
factotum: use try/except/finally
Matt Mackall -
r25078:e8348f1c default
parent child Browse files
Show More
@@ -1,127 +1,126 b''
1 # factotum.py - Plan 9 factotum integration for Mercurial
1 # factotum.py - Plan 9 factotum integration for Mercurial
2 #
2 #
3 # Copyright (C) 2012 Steven Stallion <sstallion@gmail.com>
3 # Copyright (C) 2012 Steven Stallion <sstallion@gmail.com>
4 #
4 #
5 # This program is free software; you can redistribute it and/or modify it
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
8 # option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful, but
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details.
13 # Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License along
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
18
19 '''http authentication with factotum
19 '''http authentication with factotum
20
20
21 This extension allows the factotum(4) facility on Plan 9 from Bell Labs
21 This extension allows the factotum(4) facility on Plan 9 from Bell Labs
22 platforms to provide authentication information for HTTP access. Configuration
22 platforms to provide authentication information for HTTP access. Configuration
23 entries specified in the auth section as well as authentication information
23 entries specified in the auth section as well as authentication information
24 provided in the repository URL are fully supported. If no prefix is specified,
24 provided in the repository URL are fully supported. If no prefix is specified,
25 a value of "*" will be assumed.
25 a value of "*" will be assumed.
26
26
27 By default, keys are specified as::
27 By default, keys are specified as::
28
28
29 proto=pass service=hg prefix=<prefix> user=<username> !password=<password>
29 proto=pass service=hg prefix=<prefix> user=<username> !password=<password>
30
30
31 If the factotum extension is unable to read the required key, one will be
31 If the factotum extension is unable to read the required key, one will be
32 requested interactively.
32 requested interactively.
33
33
34 A configuration section is available to customize runtime behavior. By
34 A configuration section is available to customize runtime behavior. By
35 default, these entries are::
35 default, these entries are::
36
36
37 [factotum]
37 [factotum]
38 executable = /bin/auth/factotum
38 executable = /bin/auth/factotum
39 mountpoint = /mnt/factotum
39 mountpoint = /mnt/factotum
40 service = hg
40 service = hg
41
41
42 The executable entry defines the full path to the factotum binary. The
42 The executable entry defines the full path to the factotum binary. The
43 mountpoint entry defines the path to the factotum file service. Lastly, the
43 mountpoint entry defines the path to the factotum file service. Lastly, the
44 service entry controls the service name used when reading keys.
44 service entry controls the service name used when reading keys.
45
45
46 '''
46 '''
47
47
48 from mercurial.i18n import _
48 from mercurial.i18n import _
49 from mercurial.url import passwordmgr
49 from mercurial.url import passwordmgr
50 from mercurial import httpconnection, util
50 from mercurial import httpconnection, util
51 import os, urllib2
51 import os, urllib2
52
52
53 ERRMAX = 128
53 ERRMAX = 128
54
54
55 _executable = _mountpoint = _service = None
55 _executable = _mountpoint = _service = None
56
56
57 def auth_getkey(self, params):
57 def auth_getkey(self, params):
58 if not self.ui.interactive():
58 if not self.ui.interactive():
59 raise util.Abort(_('factotum not interactive'))
59 raise util.Abort(_('factotum not interactive'))
60 if 'user=' not in params:
60 if 'user=' not in params:
61 params = '%s user?' % params
61 params = '%s user?' % params
62 params = '%s !password?' % params
62 params = '%s !password?' % params
63 os.system("%s -g '%s'" % (_executable, params))
63 os.system("%s -g '%s'" % (_executable, params))
64
64
65 def auth_getuserpasswd(self, getkey, params):
65 def auth_getuserpasswd(self, getkey, params):
66 params = 'proto=pass %s' % params
66 params = 'proto=pass %s' % params
67 while True:
67 while True:
68 fd = os.open('%s/rpc' % _mountpoint, os.O_RDWR)
68 fd = os.open('%s/rpc' % _mountpoint, os.O_RDWR)
69 try:
69 try:
70 try:
70 os.write(fd, 'start %s' % params)
71 os.write(fd, 'start %s' % params)
71 l = os.read(fd, ERRMAX).split()
72 l = os.read(fd, ERRMAX).split()
72 if l[0] == 'ok':
73 if l[0] == 'ok':
73 os.write(fd, 'read')
74 os.write(fd, 'read')
74 status, user, passwd = os.read(fd, ERRMAX).split(None, 2)
75 status, user, passwd = os.read(fd, ERRMAX).split(None, 2)
75 if status == 'ok':
76 if status == 'ok':
76 if passwd.startswith("'"):
77 if passwd.startswith("'"):
77 if passwd.endswith("'"):
78 if passwd.endswith("'"):
78 passwd = passwd[1:-1].replace("''", "'")
79 passwd = passwd[1:-1].replace("''", "'")
79 else:
80 else:
80 raise util.Abort(_('malformed password string'))
81 raise util.Abort(_('malformed password string'))
81 return (user, passwd)
82 return (user, passwd)
82 except (OSError, IOError):
83 except (OSError, IOError):
83 raise util.Abort(_('factotum not responding'))
84 raise util.Abort(_('factotum not responding'))
85 finally:
84 finally:
86 os.close(fd)
85 os.close(fd)
87 getkey(self, params)
86 getkey(self, params)
88
87
89 def monkeypatch_method(cls):
88 def monkeypatch_method(cls):
90 def decorator(func):
89 def decorator(func):
91 setattr(cls, func.__name__, func)
90 setattr(cls, func.__name__, func)
92 return func
91 return func
93 return decorator
92 return decorator
94
93
95 @monkeypatch_method(passwordmgr)
94 @monkeypatch_method(passwordmgr)
96 def find_user_password(self, realm, authuri):
95 def find_user_password(self, realm, authuri):
97 user, passwd = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
96 user, passwd = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
98 self, realm, authuri)
97 self, realm, authuri)
99 if user and passwd:
98 if user and passwd:
100 self._writedebug(user, passwd)
99 self._writedebug(user, passwd)
101 return (user, passwd)
100 return (user, passwd)
102
101
103 prefix = ''
102 prefix = ''
104 res = httpconnection.readauthforuri(self.ui, authuri, user)
103 res = httpconnection.readauthforuri(self.ui, authuri, user)
105 if res:
104 if res:
106 _, auth = res
105 _, auth = res
107 prefix = auth.get('prefix')
106 prefix = auth.get('prefix')
108 user, passwd = auth.get('username'), auth.get('password')
107 user, passwd = auth.get('username'), auth.get('password')
109 if not user or not passwd:
108 if not user or not passwd:
110 if not prefix:
109 if not prefix:
111 prefix = realm.split(' ')[0].lower()
110 prefix = realm.split(' ')[0].lower()
112 params = 'service=%s prefix=%s' % (_service, prefix)
111 params = 'service=%s prefix=%s' % (_service, prefix)
113 if user:
112 if user:
114 params = '%s user=%s' % (params, user)
113 params = '%s user=%s' % (params, user)
115 user, passwd = auth_getuserpasswd(self, auth_getkey, params)
114 user, passwd = auth_getuserpasswd(self, auth_getkey, params)
116
115
117 self.add_password(realm, authuri, user, passwd)
116 self.add_password(realm, authuri, user, passwd)
118 self._writedebug(user, passwd)
117 self._writedebug(user, passwd)
119 return (user, passwd)
118 return (user, passwd)
120
119
121 def uisetup(ui):
120 def uisetup(ui):
122 global _executable
121 global _executable
123 _executable = ui.config('factotum', 'executable', '/bin/auth/factotum')
122 _executable = ui.config('factotum', 'executable', '/bin/auth/factotum')
124 global _mountpoint
123 global _mountpoint
125 _mountpoint = ui.config('factotum', 'mountpoint', '/mnt/factotum')
124 _mountpoint = ui.config('factotum', 'mountpoint', '/mnt/factotum')
126 global _service
125 global _service
127 _service = ui.config('factotum', 'service', 'hg')
126 _service = ui.config('factotum', 'service', 'hg')
General Comments 0
You need to be logged in to leave comments. Login now