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