Show More
@@ -357,6 +357,15 b' def addaliases(ui, cmdtable):' | |||||
357 | # but only if they have been defined prior to the current definition. |
|
357 | # but only if they have been defined prior to the current definition. | |
358 | for alias, definition in ui.configitems('alias'): |
|
358 | for alias, definition in ui.configitems('alias'): | |
359 | aliasdef = cmdalias(alias, definition, cmdtable) |
|
359 | aliasdef = cmdalias(alias, definition, cmdtable) | |
|
360 | ||||
|
361 | try: | |||
|
362 | olddef = cmdtable[aliasdef.cmd][0] | |||
|
363 | if olddef.definition == aliasdef.definition: | |||
|
364 | continue | |||
|
365 | except (KeyError, AttributeError): | |||
|
366 | # definition might not exist or it might not be a cmdalias | |||
|
367 | pass | |||
|
368 | ||||
360 | cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help) |
|
369 | cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help) | |
361 | if aliasdef.norepo: |
|
370 | if aliasdef.norepo: | |
362 | commands.norepo += ' %s' % alias |
|
371 | commands.norepo += ' %s' % alias |
@@ -58,7 +58,7 b' class httpsendfile(object):' | |||||
58 | return self._len |
|
58 | return self._len | |
59 |
|
59 | |||
60 | # moved here from url.py to avoid a cycle |
|
60 | # moved here from url.py to avoid a cycle | |
61 | def readauthforuri(ui, uri): |
|
61 | def readauthforuri(ui, uri, user): | |
62 | # Read configuration |
|
62 | # Read configuration | |
63 | config = dict() |
|
63 | config = dict() | |
64 | for key, val in ui.configitems('auth'): |
|
64 | for key, val in ui.configitems('auth'): | |
@@ -72,10 +72,6 b' def readauthforuri(ui, uri):' | |||||
72 | gdict[setting] = val |
|
72 | gdict[setting] = val | |
73 |
|
73 | |||
74 | # Find the best match |
|
74 | # Find the best match | |
75 | uri = util.url(uri) |
|
|||
76 | user = uri.user |
|
|||
77 | uri.user = uri.password = None |
|
|||
78 | uri = str(uri) |
|
|||
79 | scheme, hostpath = uri.split('://', 1) |
|
75 | scheme, hostpath = uri.split('://', 1) | |
80 | bestuser = None |
|
76 | bestuser = None | |
81 | bestlen = 0 |
|
77 | bestlen = 0 | |
@@ -238,7 +234,11 b' class http2handler(urllib2.HTTPHandler, ' | |||||
238 | return self.do_open(HTTPConnection, req, False) |
|
234 | return self.do_open(HTTPConnection, req, False) | |
239 |
|
235 | |||
240 | def https_open(self, req): |
|
236 | def https_open(self, req): | |
241 | res = readauthforuri(self.ui, req.get_full_url()) |
|
237 | # req.get_full_url() does not contain credentials and we may | |
|
238 | # need them to match the certificates. | |||
|
239 | url = req.get_full_url() | |||
|
240 | user, password = self.pwmgr.find_stored_password(url) | |||
|
241 | res = readauthforuri(self.ui, url, user) | |||
242 | if res: |
|
242 | if res: | |
243 | group, auth = res |
|
243 | group, auth = res | |
244 | self.auth = auth |
|
244 | self.auth = auth |
@@ -26,7 +26,7 b' class passwordmgr(urllib2.HTTPPasswordMg' | |||||
26 | return (user, passwd) |
|
26 | return (user, passwd) | |
27 |
|
27 | |||
28 | if not user or not passwd: |
|
28 | if not user or not passwd: | |
29 | res = httpconnectionmod.readauthforuri(self.ui, authuri) |
|
29 | res = httpconnectionmod.readauthforuri(self.ui, authuri, user) | |
30 | if res: |
|
30 | if res: | |
31 | group, auth = res |
|
31 | group, auth = res | |
32 | user, passwd = auth.get('username'), auth.get('password') |
|
32 | user, passwd = auth.get('username'), auth.get('password') | |
@@ -53,6 +53,10 b' class passwordmgr(urllib2.HTTPPasswordMg' | |||||
53 | msg = _('http auth: user %s, password %s\n') |
|
53 | msg = _('http auth: user %s, password %s\n') | |
54 | self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set')) |
|
54 | self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set')) | |
55 |
|
55 | |||
|
56 | def find_stored_password(self, authuri): | |||
|
57 | return urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password( | |||
|
58 | self, None, authuri) | |||
|
59 | ||||
56 | class proxyhandler(urllib2.ProxyHandler): |
|
60 | class proxyhandler(urllib2.ProxyHandler): | |
57 | def __init__(self, ui): |
|
61 | def __init__(self, ui): | |
58 | proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') |
|
62 | proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') | |
@@ -342,7 +346,11 b' if has_https:' | |||||
342 | return keepalive.KeepAliveHandler._start_transaction(self, h, req) |
|
346 | return keepalive.KeepAliveHandler._start_transaction(self, h, req) | |
343 |
|
347 | |||
344 | def https_open(self, req): |
|
348 | def https_open(self, req): | |
345 | res = httpconnectionmod.readauthforuri(self.ui, req.get_full_url()) |
|
349 | # req.get_full_url() does not contain credentials and we may | |
|
350 | # need them to match the certificates. | |||
|
351 | url = req.get_full_url() | |||
|
352 | user, password = self.pwmgr.find_stored_password(url) | |||
|
353 | res = httpconnectionmod.readauthforuri(self.ui, url, user) | |||
346 | if res: |
|
354 | if res: | |
347 | group, auth = res |
|
355 | group, auth = res | |
348 | self.auth = auth |
|
356 | self.auth = auth |
@@ -1468,6 +1468,8 b' class url(object):' | |||||
1468 | path = None |
|
1468 | path = None | |
1469 | if not self.host: |
|
1469 | if not self.host: | |
1470 | self.host = None |
|
1470 | self.host = None | |
|
1471 | # path of file:///d is /d | |||
|
1472 | # path of file:///d:/ is d:/, not /d:/ | |||
1471 | if path and not hasdriveletter(path): |
|
1473 | if path and not hasdriveletter(path): | |
1472 | path = '/' + path |
|
1474 | path = '/' + path | |
1473 |
|
1475 | |||
@@ -1587,7 +1589,9 b' class url(object):' | |||||
1587 | self.user, self.passwd = user, passwd |
|
1589 | self.user, self.passwd = user, passwd | |
1588 | if not self.user: |
|
1590 | if not self.user: | |
1589 | return (s, None) |
|
1591 | return (s, None) | |
1590 | return (s, (None, (str(self), self.host), |
|
1592 | # authinfo[1] is passed to urllib2 password manager, and its URIs | |
|
1593 | # must not contain credentials. | |||
|
1594 | return (s, (None, (s, self.host), | |||
1591 | self.user, self.passwd or '')) |
|
1595 | self.user, self.passwd or '')) | |
1592 |
|
1596 | |||
1593 | def isabs(self): |
|
1597 | def isabs(self): | |
@@ -1610,11 +1614,6 b' class url(object):' | |||||
1610 | path = self._hostport + '/' + self.path |
|
1614 | path = self._hostport + '/' + self.path | |
1611 | elif self.host is not None and self.path: |
|
1615 | elif self.host is not None and self.path: | |
1612 | path = '/' + path |
|
1616 | path = '/' + path | |
1613 | # We also need to handle the case of file:///C:/, which |
|
|||
1614 | # should return C:/, not /C:/. |
|
|||
1615 | elif hasdriveletter(path): |
|
|||
1616 | # Strip leading slash from paths with drive names |
|
|||
1617 | return path[1:] |
|
|||
1618 | return path |
|
1617 | return path | |
1619 | return self._origpath |
|
1618 | return self._origpath | |
1620 |
|
1619 |
@@ -1,4 +1,5 b'' | |||||
1 | from mercurial import demandimport; demandimport.enable() |
|
1 | from mercurial import demandimport; demandimport.enable() | |
|
2 | import urllib2 | |||
2 | from mercurial import ui, util |
|
3 | from mercurial import ui, util | |
3 | from mercurial import url |
|
4 | from mercurial import url | |
4 | from mercurial.error import Abort |
|
5 | from mercurial.error import Abort | |
@@ -36,10 +37,10 b' def test(auth, urls=None):' | |||||
36 | print 'URI:', uri |
|
37 | print 'URI:', uri | |
37 | try: |
|
38 | try: | |
38 | pm = url.passwordmgr(ui) |
|
39 | pm = url.passwordmgr(ui) | |
39 |
authinfo = util.url(uri).authinfo() |
|
40 | u, authinfo = util.url(uri).authinfo() | |
40 | if authinfo is not None: |
|
41 | if authinfo is not None: | |
41 | pm.add_password(*authinfo) |
|
42 | pm.add_password(*authinfo) | |
42 |
print ' ', pm.find_user_password('test', u |
|
43 | print ' ', pm.find_user_password('test', u) | |
43 | except Abort, e: |
|
44 | except Abort, e: | |
44 | print 'abort' |
|
45 | print 'abort' | |
45 |
|
46 | |||
@@ -95,3 +96,12 b" test({'x.prefix': 'http://example.org/fo" | |||||
95 | 'y.username': 'y', |
|
96 | 'y.username': 'y', | |
96 | 'y.password': 'ypassword'}, |
|
97 | 'y.password': 'ypassword'}, | |
97 | urls=['http://y@example.org/foo/bar']) |
|
98 | urls=['http://y@example.org/foo/bar']) | |
|
99 | ||||
|
100 | def testauthinfo(fullurl, authurl): | |||
|
101 | print 'URIs:', fullurl, authurl | |||
|
102 | pm = urllib2.HTTPPasswordMgrWithDefaultRealm() | |||
|
103 | pm.add_password(*util.url(fullurl).authinfo()[1]) | |||
|
104 | print pm.find_user_password('test', authurl) | |||
|
105 | ||||
|
106 | print '\n*** Test urllib2 and util.url\n' | |||
|
107 | testauthinfo('http://user@example.com:8080/foo', 'http://example.com:8080/foo') |
@@ -189,3 +189,8 b' URI: http://y@example.org/foo' | |||||
189 | CFG: {x.password: xpassword, x.prefix: http://example.org/foo/bar, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y} |
|
189 | CFG: {x.password: xpassword, x.prefix: http://example.org/foo/bar, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y} | |
190 | URI: http://y@example.org/foo/bar |
|
190 | URI: http://y@example.org/foo/bar | |
191 | ('y', 'xpassword') |
|
191 | ('y', 'xpassword') | |
|
192 | ||||
|
193 | *** Test urllib2 and util.url | |||
|
194 | ||||
|
195 | URIs: http://user@example.com:8080/foo http://example.com:8080/foo | |||
|
196 | ('user', '') |
@@ -110,6 +110,55 b' clone from invalid URL' | |||||
110 | abort: HTTP Error 404: Not Found |
|
110 | abort: HTTP Error 404: Not Found | |
111 | [255] |
|
111 | [255] | |
112 |
|
112 | |||
|
113 | test http authentication | |||
|
114 | ||||
|
115 | $ cd test | |||
|
116 | $ cat << EOT > userpass.py | |||
|
117 | > import base64 | |||
|
118 | > from mercurial.hgweb import common | |||
|
119 | > def perform_authentication(hgweb, req, op): | |||
|
120 | > auth = req.env.get('HTTP_AUTHORIZATION') | |||
|
121 | > if not auth: | |||
|
122 | > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who', | |||
|
123 | > [('WWW-Authenticate', 'Basic Realm="mercurial"')]) | |||
|
124 | > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']: | |||
|
125 | > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no') | |||
|
126 | > def extsetup(): | |||
|
127 | > common.permhooks.insert(0, perform_authentication) | |||
|
128 | > EOT | |||
|
129 | $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid | |||
|
130 | $ cat pid >> $DAEMON_PIDS | |||
|
131 | ||||
|
132 | $ hg id http://localhost:$HGPORT2/ | |||
|
133 | abort: http authorization required | |||
|
134 | [255] | |||
|
135 | $ hg id http://user@localhost:$HGPORT2/ | |||
|
136 | abort: http authorization required | |||
|
137 | [255] | |||
|
138 | $ hg id http://user:pass@localhost:$HGPORT2/ | |||
|
139 | 5fed3813f7f5 | |||
|
140 | $ echo '[auth]' >> .hg/hgrc | |||
|
141 | $ echo 'l.schemes=http' >> .hg/hgrc | |||
|
142 | $ echo 'l.prefix=lo' >> .hg/hgrc | |||
|
143 | $ echo 'l.username=user' >> .hg/hgrc | |||
|
144 | $ echo 'l.password=pass' >> .hg/hgrc | |||
|
145 | $ hg id http://localhost:$HGPORT2/ | |||
|
146 | 5fed3813f7f5 | |||
|
147 | $ hg id http://localhost:$HGPORT2/ | |||
|
148 | 5fed3813f7f5 | |||
|
149 | $ hg id http://user@localhost:$HGPORT2/ | |||
|
150 | 5fed3813f7f5 | |||
|
151 | $ hg id http://user:pass@localhost:$HGPORT2/ | |||
|
152 | 5fed3813f7f5 | |||
|
153 | $ hg id http://user2@localhost:$HGPORT2/ | |||
|
154 | abort: http authorization required | |||
|
155 | [255] | |||
|
156 | $ hg id http://user:pass2@localhost:$HGPORT2/ | |||
|
157 | abort: HTTP Error 403: no | |||
|
158 | [255] | |||
|
159 | ||||
|
160 | $ cd .. | |||
|
161 | ||||
113 | check error log |
|
162 | check error log | |
114 |
|
163 | |||
115 | $ cat error.log |
|
164 | $ cat error.log |
@@ -204,18 +204,32 b' def test_url():' | |||||
204 | <url scheme: 'file', path: '/foo/bar/baz'> |
|
204 | <url scheme: 'file', path: '/foo/bar/baz'> | |
205 | >>> str(u) |
|
205 | >>> str(u) | |
206 | 'file:///foo/bar/baz' |
|
206 | 'file:///foo/bar/baz' | |
|
207 | >>> u.localpath() | |||
|
208 | '/foo/bar/baz' | |||
207 |
|
209 | |||
208 | >>> u = url('file:///foo/bar/baz') |
|
210 | >>> u = url('file:///foo/bar/baz') | |
209 | >>> u |
|
211 | >>> u | |
210 | <url scheme: 'file', path: '/foo/bar/baz'> |
|
212 | <url scheme: 'file', path: '/foo/bar/baz'> | |
211 | >>> str(u) |
|
213 | >>> str(u) | |
212 | 'file:///foo/bar/baz' |
|
214 | 'file:///foo/bar/baz' | |
|
215 | >>> u.localpath() | |||
|
216 | '/foo/bar/baz' | |||
|
217 | ||||
|
218 | >>> u = url('file:///f:oo/bar/baz') | |||
|
219 | >>> u | |||
|
220 | <url scheme: 'file', path: 'f:oo/bar/baz'> | |||
|
221 | >>> str(u) | |||
|
222 | 'file:f%3Aoo/bar/baz' | |||
|
223 | >>> u.localpath() | |||
|
224 | 'f:oo/bar/baz' | |||
213 |
|
225 | |||
214 | >>> u = url('file:foo/bar/baz') |
|
226 | >>> u = url('file:foo/bar/baz') | |
215 | >>> u |
|
227 | >>> u | |
216 | <url scheme: 'file', path: 'foo/bar/baz'> |
|
228 | <url scheme: 'file', path: 'foo/bar/baz'> | |
217 | >>> str(u) |
|
229 | >>> str(u) | |
218 | 'file:foo/bar/baz' |
|
230 | 'file:foo/bar/baz' | |
|
231 | >>> u.localpath() | |||
|
232 | 'foo/bar/baz' | |||
219 | """ |
|
233 | """ | |
220 |
|
234 | |||
221 | doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE) |
|
235 | doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE) |
General Comments 0
You need to be logged in to leave comments.
Login now