Mercurial > hg
comparison hgext/factotum.py @ 16383:f5dd179bfa4a
plan9: initial support for plan 9 from bell labs
This patch contains support for Plan 9 from Bell Labs. A README is
provided in contrib/plan9 which describes the port in greater detail.
A new extension is also provided named factotum which permits the
factotum(4) authentication agent to provide credentials for HTTP
repositories. This extension is also applicable to other POSIX
platforms which make use of Plan 9 from User Space (aka plan9ports).
author | Steven Stallion <sstallion@gmail.com> |
---|---|
date | Sun, 08 Apr 2012 12:43:41 -0700 |
parents | |
children | cef755f86d5c |
comparison
equal
deleted
inserted
replaced
16382:f542d291c4f2 | 16383:f5dd179bfa4a |
---|---|
1 # factotum.py - Plan 9 factotum integration for Mercurial | |
2 # | |
3 # Copyright (C) 2012 Steven Stallion <sstallion@gmail.com> | |
4 # | |
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 | |
7 # Free Software Foundation; either version 2 of the License, or (at your | |
8 # option) any later version. | |
9 # | |
10 # This program is distributed in the hope that it will be useful, but | |
11 # WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | |
13 # Public License for more details. | |
14 # | |
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., | |
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | |
19 '''http authentication with factotum | |
20 | |
21 This extension allows the factotum facility on Plan 9 from Bell Labs platforms | |
22 to provide authentication information for HTTP access. Configuration entries | |
23 specified in the auth section as well as authentication information provided | |
24 in the repository URL are fully supported. If no prefix is specified, a value | |
25 of ``*`` will be assumed. | |
26 | |
27 By default, keys are specified as:: | |
28 | |
29 proto=pass service=hg prefix=<prefix> user=<username> !password=<password> | |
30 | |
31 If the factotum extension is unable to read the required key, one will be | |
32 requested interactively. | |
33 | |
34 A configuration section is available to customize runtime behavior. By | |
35 default, these entries are:: | |
36 | |
37 [factotum] | |
38 mount = /mnt/factotum | |
39 path = /bin/auth/factotum | |
40 service = hg | |
41 | |
42 The mount entry defines the mount point for the factotum file service. The | |
43 path entry defines the full path to the factotum binary. Lastly, the service | |
44 entry controls the service name used when reading keys. | |
45 | |
46 ''' | |
47 | |
48 from mercurial.i18n import _ | |
49 from mercurial.url import passwordmgr | |
50 from mercurial import httpconnection, urllib2, util | |
51 import os | |
52 | |
53 ERRMAX = 128 | |
54 | |
55 def auth_getkey(self, params): | |
56 if not self.ui.interactive(): | |
57 raise util.Abort(_('factotum not interactive')) | |
58 if 'user=' not in params: | |
59 params = '%s user?' % params | |
60 params = '%s !password?' % params | |
61 os.system("%s -g '%s'" % (_path, params)) | |
62 | |
63 def auth_getuserpasswd(self, getkey, params): | |
64 params = 'proto=pass %s' % params | |
65 while True: | |
66 fd = os.open('%s/rpc' % _mount, os.O_RDWR) | |
67 try: | |
68 try: | |
69 os.write(fd, 'start %s' % params) | |
70 l = os.read(fd, ERRMAX).split() | |
71 if l[0] == 'ok': | |
72 os.write(fd, 'read') | |
73 l = os.read(fd, ERRMAX).split() | |
74 if l[0] == 'ok': | |
75 return l[1:] | |
76 except (OSError, IOError): | |
77 raise util.Abort(_('factotum not responding')) | |
78 finally: | |
79 os.close(fd) | |
80 getkey(self, params) | |
81 | |
82 def monkeypatch_method(cls): | |
83 def decorator(func): | |
84 setattr(cls, func.__name__, func) | |
85 return func | |
86 return decorator | |
87 | |
88 @monkeypatch_method(passwordmgr) | |
89 def find_user_password(self, realm, authuri): | |
90 user, passwd = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password( | |
91 self, realm, authuri) | |
92 if user and passwd: | |
93 self._writedebug(user, passwd) | |
94 return (user, passwd) | |
95 | |
96 prefix = '' | |
97 res = httpconnection.readauthforuri(self.ui, authuri, user) | |
98 if res: | |
99 _, auth = res | |
100 prefix = auth.get('prefix') | |
101 user, passwd = auth.get('username'), auth.get('password') | |
102 if not user or not passwd: | |
103 if not prefix: | |
104 prefix = '*' | |
105 params = 'service=%s prefix=%s' % (_service, prefix) | |
106 if user: | |
107 params = '%s user=%s' % (params, user) | |
108 user, passwd = auth_getuserpasswd(self, auth_getkey, params) | |
109 | |
110 self.add_password(realm, authuri, user, passwd) | |
111 self._writedebug(user, passwd) | |
112 return (user, passwd) | |
113 | |
114 def uisetup(ui): | |
115 global _mount | |
116 _mount = ui.config('factotum', 'mount', '/mnt/factotum') | |
117 global _path | |
118 _path = ui.config('factotum', 'path', '/bin/auth/factotum') | |
119 global _service | |
120 _service = ui.config('factotum', 'service', 'hg') |