Show More
@@ -0,0 +1,61 | |||
|
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 | |||
|
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 This section describes the different sec | |||
|
100 | 100 | Mercurial "hgrc" file, the purpose of each section, its possible |
|
101 | 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 | 142 | [[decode]] |
|
104 | 143 | decode/encode:: |
|
105 | 144 | Filters for transforming files on checkout/checkin. This would |
@@ -105,24 +105,58 class passwordmgr(urllib2.HTTPPasswordMg | |||
|
105 | 105 | self, realm, authuri) |
|
106 | 106 | user, passwd = authinfo |
|
107 | 107 | if user and passwd: |
|
108 | self._writedebug(user, passwd) | |
|
108 | 109 | return (user, passwd) |
|
109 | 110 | |
|
110 | if not self.ui.interactive(): | |
|
111 | raise util.Abort(_('http authorization required')) | |
|
111 | user, passwd = self._readauthtoken(authuri) | |
|
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")) | |
|
114 | self.ui.status(_("realm: %s\n") % realm) | |
|
115 | if user: | |
|
116 | self.ui.status(_("user: %s\n") % user) | |
|
117 | else: | |
|
118 | user = self.ui.prompt(_("user:"), default=None) | |
|
116 | self.ui.write(_("http authorization required\n")) | |
|
117 | self.ui.status(_("realm: %s\n") % realm) | |
|
118 | if user: | |
|
119 | self.ui.status(_("user: %s\n") % user) | |
|
120 | else: | |
|
121 | user = self.ui.prompt(_("user:"), default=None) | |
|
119 | 122 | |
|
120 | if not passwd: | |
|
121 | passwd = self.ui.getpass() | |
|
123 | if not passwd: | |
|
124 | passwd = self.ui.getpass() | |
|
122 | 125 | |
|
123 | 126 | self.add_password(realm, authuri, user, passwd) |
|
127 | self._writedebug(user, passwd) | |
|
124 | 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 | 160 | class proxyhandler(urllib2.ProxyHandler): |
|
127 | 161 | def __init__(self, ui): |
|
128 | 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