##// END OF EJS Templates
configitems: register the 'factotum.mountpoint' config
marmoute -
r33239:037c5c93 default
parent child Browse files
Show More
@@ -1,142 +1,145
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 __future__ import absolute_import
48 from __future__ import absolute_import
49
49
50 import os
50 import os
51 from mercurial.i18n import _
51 from mercurial.i18n import _
52 from mercurial import (
52 from mercurial import (
53 error,
53 error,
54 httpconnection,
54 httpconnection,
55 registrar,
55 registrar,
56 url,
56 url,
57 util,
57 util,
58 )
58 )
59
59
60 urlreq = util.urlreq
60 urlreq = util.urlreq
61 passwordmgr = url.passwordmgr
61 passwordmgr = url.passwordmgr
62
62
63 ERRMAX = 128
63 ERRMAX = 128
64
64
65 _executable = _mountpoint = _service = None
65 _executable = _mountpoint = _service = None
66
66
67 configtable = {}
67 configtable = {}
68 configitem = registrar.configitem(configtable)
68 configitem = registrar.configitem(configtable)
69
69
70 configitem('factotum', 'executable',
70 configitem('factotum', 'executable',
71 default='/bin/auth/factotum',
71 default='/bin/auth/factotum',
72 )
72 )
73 configitem('factotum', 'mountpoint',
74 default='/mnt/factotum',
75 )
73
76
74 def auth_getkey(self, params):
77 def auth_getkey(self, params):
75 if not self.ui.interactive():
78 if not self.ui.interactive():
76 raise error.Abort(_('factotum not interactive'))
79 raise error.Abort(_('factotum not interactive'))
77 if 'user=' not in params:
80 if 'user=' not in params:
78 params = '%s user?' % params
81 params = '%s user?' % params
79 params = '%s !password?' % params
82 params = '%s !password?' % params
80 os.system("%s -g '%s'" % (_executable, params))
83 os.system("%s -g '%s'" % (_executable, params))
81
84
82 def auth_getuserpasswd(self, getkey, params):
85 def auth_getuserpasswd(self, getkey, params):
83 params = 'proto=pass %s' % params
86 params = 'proto=pass %s' % params
84 while True:
87 while True:
85 fd = os.open('%s/rpc' % _mountpoint, os.O_RDWR)
88 fd = os.open('%s/rpc' % _mountpoint, os.O_RDWR)
86 try:
89 try:
87 os.write(fd, 'start %s' % params)
90 os.write(fd, 'start %s' % params)
88 l = os.read(fd, ERRMAX).split()
91 l = os.read(fd, ERRMAX).split()
89 if l[0] == 'ok':
92 if l[0] == 'ok':
90 os.write(fd, 'read')
93 os.write(fd, 'read')
91 status, user, passwd = os.read(fd, ERRMAX).split(None, 2)
94 status, user, passwd = os.read(fd, ERRMAX).split(None, 2)
92 if status == 'ok':
95 if status == 'ok':
93 if passwd.startswith("'"):
96 if passwd.startswith("'"):
94 if passwd.endswith("'"):
97 if passwd.endswith("'"):
95 passwd = passwd[1:-1].replace("''", "'")
98 passwd = passwd[1:-1].replace("''", "'")
96 else:
99 else:
97 raise error.Abort(_('malformed password string'))
100 raise error.Abort(_('malformed password string'))
98 return (user, passwd)
101 return (user, passwd)
99 except (OSError, IOError):
102 except (OSError, IOError):
100 raise error.Abort(_('factotum not responding'))
103 raise error.Abort(_('factotum not responding'))
101 finally:
104 finally:
102 os.close(fd)
105 os.close(fd)
103 getkey(self, params)
106 getkey(self, params)
104
107
105 def monkeypatch_method(cls):
108 def monkeypatch_method(cls):
106 def decorator(func):
109 def decorator(func):
107 setattr(cls, func.__name__, func)
110 setattr(cls, func.__name__, func)
108 return func
111 return func
109 return decorator
112 return decorator
110
113
111 @monkeypatch_method(passwordmgr)
114 @monkeypatch_method(passwordmgr)
112 def find_user_password(self, realm, authuri):
115 def find_user_password(self, realm, authuri):
113 user, passwd = self.passwddb.find_user_password(realm, authuri)
116 user, passwd = self.passwddb.find_user_password(realm, authuri)
114 if user and passwd:
117 if user and passwd:
115 self._writedebug(user, passwd)
118 self._writedebug(user, passwd)
116 return (user, passwd)
119 return (user, passwd)
117
120
118 prefix = ''
121 prefix = ''
119 res = httpconnection.readauthforuri(self.ui, authuri, user)
122 res = httpconnection.readauthforuri(self.ui, authuri, user)
120 if res:
123 if res:
121 _, auth = res
124 _, auth = res
122 prefix = auth.get('prefix')
125 prefix = auth.get('prefix')
123 user, passwd = auth.get('username'), auth.get('password')
126 user, passwd = auth.get('username'), auth.get('password')
124 if not user or not passwd:
127 if not user or not passwd:
125 if not prefix:
128 if not prefix:
126 prefix = realm.split(' ')[0].lower()
129 prefix = realm.split(' ')[0].lower()
127 params = 'service=%s prefix=%s' % (_service, prefix)
130 params = 'service=%s prefix=%s' % (_service, prefix)
128 if user:
131 if user:
129 params = '%s user=%s' % (params, user)
132 params = '%s user=%s' % (params, user)
130 user, passwd = auth_getuserpasswd(self, auth_getkey, params)
133 user, passwd = auth_getuserpasswd(self, auth_getkey, params)
131
134
132 self.add_password(realm, authuri, user, passwd)
135 self.add_password(realm, authuri, user, passwd)
133 self._writedebug(user, passwd)
136 self._writedebug(user, passwd)
134 return (user, passwd)
137 return (user, passwd)
135
138
136 def uisetup(ui):
139 def uisetup(ui):
137 global _executable
140 global _executable
138 _executable = ui.config('factotum', 'executable')
141 _executable = ui.config('factotum', 'executable')
139 global _mountpoint
142 global _mountpoint
140 _mountpoint = ui.config('factotum', 'mountpoint', '/mnt/factotum')
143 _mountpoint = ui.config('factotum', 'mountpoint')
141 global _service
144 global _service
142 _service = ui.config('factotum', 'service', 'hg')
145 _service = ui.config('factotum', 'service', 'hg')
General Comments 0
You need to be logged in to leave comments. Login now