##// END OF EJS Templates
url: support client certificate files over HTTPS (issue643)...
Henrik Stuart -
r8847:7951f385 default
parent child Browse files
Show More
@@ -142,6 +142,11 b' Example:'
142 foo.password = bar
142 foo.password = bar
143 foo.schemes = http https
143 foo.schemes = http https
144
144
145 bar.prefix = secure.example.org
146 bar.key = path/to/file.key
147 bar.cert = path/to/file.cert
148 bar.schemes = https
149
145 Supported arguments:
150 Supported arguments:
146
151
147 prefix;;
152 prefix;;
@@ -152,10 +157,17 b' Supported arguments:'
152 against the URI with its scheme stripped as well, and the schemes
157 against the URI with its scheme stripped as well, and the schemes
153 argument, q.v., is then subsequently consulted.
158 argument, q.v., is then subsequently consulted.
154 username;;
159 username;;
155 Username to authenticate with.
160 Optional. Username to authenticate with. If not given, and the
161 remote site requires basic or digest authentication, the user
162 will be prompted for it.
156 password;;
163 password;;
157 Optional. Password to authenticate with. If not given the user
164 Optional. Password to authenticate with. If not given, and the
165 remote site requires basic or digest authentication, the user
158 will be prompted for it.
166 will be prompted for it.
167 key;;
168 Optional. PEM encoded client certificate key file.
169 cert;;
170 Optional. PEM encoded client certificate chain file.
159 schemes;;
171 schemes;;
160 Optional. Space separated list of URI schemes to use this
172 Optional. Space separated list of URI schemes to use this
161 authentication entry with. Only used if the prefix doesn't include
173 authentication entry with. Only used if the prefix doesn't include
@@ -109,7 +109,9 b' class passwordmgr(urllib2.HTTPPasswordMg'
109 return (user, passwd)
109 return (user, passwd)
110
110
111 if not user:
111 if not user:
112 user, passwd = self._readauthtoken(authuri)
112 auth = self.readauthtoken(authuri)
113 if auth:
114 user, passwd = auth.get('username'), auth.get('password')
113 if not user or not passwd:
115 if not user or not passwd:
114 if not self.ui.interactive():
116 if not self.ui.interactive():
115 raise util.Abort(_('http authorization required'))
117 raise util.Abort(_('http authorization required'))
@@ -132,7 +134,7 b' class passwordmgr(urllib2.HTTPPasswordMg'
132 msg = _('http auth: user %s, password %s\n')
134 msg = _('http auth: user %s, password %s\n')
133 self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
135 self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
134
136
135 def _readauthtoken(self, uri):
137 def readauthtoken(self, uri):
136 # Read configuration
138 # Read configuration
137 config = dict()
139 config = dict()
138 for key, val in self.ui.configitems('auth'):
140 for key, val in self.ui.configitems('auth'):
@@ -143,7 +145,7 b' class passwordmgr(urllib2.HTTPPasswordMg'
143 # Find the best match
145 # Find the best match
144 scheme, hostpath = uri.split('://', 1)
146 scheme, hostpath = uri.split('://', 1)
145 bestlen = 0
147 bestlen = 0
146 bestauth = None, None
148 bestauth = None
147 for auth in config.itervalues():
149 for auth in config.itervalues():
148 prefix = auth.get('prefix')
150 prefix = auth.get('prefix')
149 if not prefix: continue
151 if not prefix: continue
@@ -155,7 +157,7 b' class passwordmgr(urllib2.HTTPPasswordMg'
155 if (prefix == '*' or hostpath.startswith(prefix)) and \
157 if (prefix == '*' or hostpath.startswith(prefix)) and \
156 len(prefix) > bestlen and scheme in schemes:
158 len(prefix) > bestlen and scheme in schemes:
157 bestlen = len(prefix)
159 bestlen = len(prefix)
158 bestauth = auth.get('username'), auth.get('password')
160 bestauth = auth
159 return bestauth
161 return bestauth
160
162
161 class proxyhandler(urllib2.ProxyHandler):
163 class proxyhandler(urllib2.ProxyHandler):
@@ -411,8 +413,32 b' if has_https:'
411 send = _gen_sendfile(httplib.HTTPSConnection)
413 send = _gen_sendfile(httplib.HTTPSConnection)
412
414
413 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
415 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
416 def __init__(self, ui):
417 keepalive.KeepAliveHandler.__init__(self)
418 urllib2.HTTPSHandler.__init__(self)
419 self.ui = ui
420 self.pwmgr = passwordmgr(self.ui)
421
414 def https_open(self, req):
422 def https_open(self, req):
415 return self.do_open(httpsconnection, req)
423 self.auth = self.pwmgr.readauthtoken(req.get_full_url())
424 return self.do_open(self._makeconnection, req)
425
426 def _makeconnection(self, host, port=443, *args, **kwargs):
427 keyfile = None
428 certfile = None
429
430 if args: # key_file
431 keyfile = args.pop(0)
432 if args: # cert_file
433 certfile = args.pop(0)
434
435 # if the user has specified different key/cert files in
436 # hgrc, we prefer these
437 if self.auth and 'key' in self.auth and 'cert' in self.auth:
438 keyfile = self.auth['key']
439 certfile = self.auth['cert']
440
441 return httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
416
442
417 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
443 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
418 # it doesn't know about the auth type requested. This can happen if
444 # it doesn't know about the auth type requested. This can happen if
@@ -460,7 +486,7 b' def opener(ui, authinfo=None):'
460 '''
486 '''
461 handlers = [httphandler()]
487 handlers = [httphandler()]
462 if has_https:
488 if has_https:
463 handlers.append(httpshandler())
489 handlers.append(httpshandler(ui))
464
490
465 handlers.append(proxyhandler(ui))
491 handlers.append(proxyhandler(ui))
466
492
General Comments 0
You need to be logged in to leave comments. Login now