##// END OF EJS Templates
allow http authentication information to be specified in the configuration
Sune Foldager -
r8333:89c80c3d default
parent child Browse files
Show More
@@ -0,0 +1,61 b''
1 from mercurial import demandimport; demandimport.enable()
2 from mercurial import ui
3 from mercurial import url
4 from mercurial.error import Abort
5
6 class myui(ui.ui):
7 def interactive(self):
8 return False
9
10 origui = myui()
11
12 def writeauth(items):
13 ui = origui.copy()
14 for name, value in items.iteritems():
15 ui.setconfig('auth', name, value)
16 return ui
17
18 def dumpdict(dict):
19 return '{' + ', '.join(['%s: %s' % (k, dict[k]) for k in sorted(dict.iterkeys())]) + '}'
20
21 def test(auth):
22 print 'CFG:', dumpdict(auth)
23 prefixes = set()
24 for k in auth:
25 prefixes.add(k.split('.', 1)[0])
26 for p in prefixes:
27 auth.update({p + '.username': p, p + '.password': p})
28
29 ui = writeauth(auth)
30
31 def _test(uri):
32 print 'URI:', uri
33 try:
34 pm = url.passwordmgr(ui)
35 print ' ', pm.find_user_password('test', uri)
36 except Abort, e:
37 print 'abort'
38
39 _test('http://example.org/foo')
40 _test('http://example.org/foo/bar')
41 _test('http://example.org/bar')
42 _test('https://example.org/foo')
43 _test('https://example.org/foo/bar')
44 _test('https://example.org/bar')
45
46
47 print '\n*** Test in-uri schemes\n'
48 test({'x.prefix': 'http://example.org'})
49 test({'x.prefix': 'https://example.org'})
50 test({'x.prefix': 'http://example.org', 'x.schemes': 'https'})
51 test({'x.prefix': 'https://example.org', 'x.schemes': 'http'})
52
53 print '\n*** Test separately configured schemes\n'
54 test({'x.prefix': 'example.org', 'x.schemes': 'http'})
55 test({'x.prefix': 'example.org', 'x.schemes': 'https'})
56 test({'x.prefix': 'example.org', 'x.schemes': 'http https'})
57
58 print '\n*** Test prefix matching\n'
59 test({'x.prefix': 'http://example.org/foo', 'y.prefix': 'http://example.org/bar'})
60 test({'x.prefix': 'http://example.org/foo', 'y.prefix': 'http://example.org/foo/bar'})
61 test({'x.prefix': '*', 'y.prefix': 'https://example.org/bar'})
@@ -0,0 +1,139 b''
1
2 *** Test in-uri schemes
3
4 CFG: {x.prefix: http://example.org}
5 URI: http://example.org/foo
6 ('x', 'x')
7 URI: http://example.org/foo/bar
8 ('x', 'x')
9 URI: http://example.org/bar
10 ('x', 'x')
11 URI: https://example.org/foo
12 abort
13 URI: https://example.org/foo/bar
14 abort
15 URI: https://example.org/bar
16 abort
17 CFG: {x.prefix: https://example.org}
18 URI: http://example.org/foo
19 abort
20 URI: http://example.org/foo/bar
21 abort
22 URI: http://example.org/bar
23 abort
24 URI: https://example.org/foo
25 ('x', 'x')
26 URI: https://example.org/foo/bar
27 ('x', 'x')
28 URI: https://example.org/bar
29 ('x', 'x')
30 CFG: {x.prefix: http://example.org, x.schemes: https}
31 URI: http://example.org/foo
32 ('x', 'x')
33 URI: http://example.org/foo/bar
34 ('x', 'x')
35 URI: http://example.org/bar
36 ('x', 'x')
37 URI: https://example.org/foo
38 abort
39 URI: https://example.org/foo/bar
40 abort
41 URI: https://example.org/bar
42 abort
43 CFG: {x.prefix: https://example.org, x.schemes: http}
44 URI: http://example.org/foo
45 abort
46 URI: http://example.org/foo/bar
47 abort
48 URI: http://example.org/bar
49 abort
50 URI: https://example.org/foo
51 ('x', 'x')
52 URI: https://example.org/foo/bar
53 ('x', 'x')
54 URI: https://example.org/bar
55 ('x', 'x')
56
57 *** Test separately configured schemes
58
59 CFG: {x.prefix: example.org, x.schemes: http}
60 URI: http://example.org/foo
61 ('x', 'x')
62 URI: http://example.org/foo/bar
63 ('x', 'x')
64 URI: http://example.org/bar
65 ('x', 'x')
66 URI: https://example.org/foo
67 abort
68 URI: https://example.org/foo/bar
69 abort
70 URI: https://example.org/bar
71 abort
72 CFG: {x.prefix: example.org, x.schemes: https}
73 URI: http://example.org/foo
74 abort
75 URI: http://example.org/foo/bar
76 abort
77 URI: http://example.org/bar
78 abort
79 URI: https://example.org/foo
80 ('x', 'x')
81 URI: https://example.org/foo/bar
82 ('x', 'x')
83 URI: https://example.org/bar
84 ('x', 'x')
85 CFG: {x.prefix: example.org, x.schemes: http https}
86 URI: http://example.org/foo
87 ('x', 'x')
88 URI: http://example.org/foo/bar
89 ('x', 'x')
90 URI: http://example.org/bar
91 ('x', 'x')
92 URI: https://example.org/foo
93 ('x', 'x')
94 URI: https://example.org/foo/bar
95 ('x', 'x')
96 URI: https://example.org/bar
97 ('x', 'x')
98
99 *** Test prefix matching
100
101 CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/bar}
102 URI: http://example.org/foo
103 ('x', 'x')
104 URI: http://example.org/foo/bar
105 ('x', 'x')
106 URI: http://example.org/bar
107 ('y', 'y')
108 URI: https://example.org/foo
109 abort
110 URI: https://example.org/foo/bar
111 abort
112 URI: https://example.org/bar
113 abort
114 CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/foo/bar}
115 URI: http://example.org/foo
116 ('x', 'x')
117 URI: http://example.org/foo/bar
118 ('y', 'y')
119 URI: http://example.org/bar
120 abort
121 URI: https://example.org/foo
122 abort
123 URI: https://example.org/foo/bar
124 abort
125 URI: https://example.org/bar
126 abort
127 CFG: {x.prefix: *, y.prefix: https://example.org/bar}
128 URI: http://example.org/foo
129 abort
130 URI: http://example.org/foo/bar
131 abort
132 URI: http://example.org/bar
133 abort
134 URI: https://example.org/foo
135 ('x', 'x')
136 URI: https://example.org/foo/bar
137 ('x', 'x')
138 URI: https://example.org/bar
139 ('y', 'y')
@@ -100,6 +100,45 b' This section describes the different sec'
100 Mercurial "hgrc" file, the purpose of each section, its possible
100 Mercurial "hgrc" file, the purpose of each section, its possible
101 keys, and their possible values.
101 keys, and their possible values.
102
102
103 [[auth]]
104 auth:
105 Authentication credentials for HTTP authentication.
106 Each line has the following format:
107
108 <name>.<argument> = <value>
109
110 where <name> is used to group arguments into authentication entries.
111 Example:
112
113 foo.prefix = hg.intevation.org/mercurial
114 foo.username = foo
115 foo.password = bar
116 foo.schemes = http https
117
118 Supported arguments:
119
120 prefix;;
121 Either '*' or a URI prefix with or without the scheme part. The
122 authentication entry with the longest matching prefix is used
123 (where '*' matches everything and counts as a match of length 1).
124 If the prefix doesn't include a scheme, the match is performed against
125 the URI with its scheme stripped as well, and the schemes argument,
126 q.v., is then subsequently consulted.
127 username;;
128 Username to authenticate with.
129 password;;
130 Optional. Password to authenticate with. If not given the user will be
131 prompted for it.
132 schemes;;
133 Optional. Space separated list of URI schemes to use this authentication
134 entry with. Only used if the prefix doesn't include a scheme. Supported
135 schemes are http and https. They will match static-http and static-https
136 respectively, as well.
137 Default: https.
138
139 If no suitable authentication entry is found, the user is prompted for
140 credentials as usual if required by the remote.
141
103 [[decode]]
142 [[decode]]
104 decode/encode::
143 decode/encode::
105 Filters for transforming files on checkout/checkin. This would
144 Filters for transforming files on checkout/checkin. This would
@@ -105,24 +105,58 b' class passwordmgr(urllib2.HTTPPasswordMg'
105 self, realm, authuri)
105 self, realm, authuri)
106 user, passwd = authinfo
106 user, passwd = authinfo
107 if user and passwd:
107 if user and passwd:
108 self._writedebug(user, passwd)
108 return (user, passwd)
109 return (user, passwd)
109
110
110 if not self.ui.interactive():
111 user, passwd = self._readauthtoken(authuri)
111 raise util.Abort(_('http authorization required'))
112 if not user or not passwd:
113 if not self.ui.interactive():
114 raise util.Abort(_('http authorization required'))
112
115
113 self.ui.write(_("http authorization required\n"))
116 self.ui.write(_("http authorization required\n"))
114 self.ui.status(_("realm: %s\n") % realm)
117 self.ui.status(_("realm: %s\n") % realm)
115 if user:
118 if user:
116 self.ui.status(_("user: %s\n") % user)
119 self.ui.status(_("user: %s\n") % user)
117 else:
120 else:
118 user = self.ui.prompt(_("user:"), default=None)
121 user = self.ui.prompt(_("user:"), default=None)
119
122
120 if not passwd:
123 if not passwd:
121 passwd = self.ui.getpass()
124 passwd = self.ui.getpass()
122
125
123 self.add_password(realm, authuri, user, passwd)
126 self.add_password(realm, authuri, user, passwd)
127 self._writedebug(user, passwd)
124 return (user, passwd)
128 return (user, passwd)
125
129
130 def _writedebug(self, user, passwd):
131 msg = _('http auth: user %s, password %s\n')
132 self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
133
134 def _readauthtoken(self, uri):
135 # Read configuration
136 config = dict()
137 for key, val in self.ui.configitems('auth'):
138 group, setting = key.split('.', 1)
139 gdict = config.setdefault(group, dict())
140 gdict[setting] = val
141
142 # Find the best match
143 scheme, hostpath = uri.split('://', 1)
144 bestlen = 0
145 bestauth = None, None
146 for auth in config.itervalues():
147 prefix = auth.get('prefix')
148 if not prefix: continue
149 p = prefix.split('://', 1)
150 if len(p) > 1:
151 schemes, prefix = [p[0]], p[1]
152 else:
153 schemes = (auth.get('schemes') or 'https').split()
154 if (prefix == '*' or hostpath.startswith(prefix)) and \
155 len(prefix) > bestlen and scheme in schemes:
156 bestlen = len(prefix)
157 bestauth = auth.get('username'), auth.get('password')
158 return bestauth
159
126 class proxyhandler(urllib2.ProxyHandler):
160 class proxyhandler(urllib2.ProxyHandler):
127 def __init__(self, ui):
161 def __init__(self, ui):
128 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
162 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
General Comments 0
You need to be logged in to leave comments. Login now