Merge lp:~thisfred/u1db/add-basic-auth into lp:u1db
- add-basic-auth
- Merge into trunk
Proposed by
Eric Casteleijn
Status: | Merged |
---|---|
Approved by: | Samuele Pedroni |
Approved revision: | 398 |
Merged at revision: | 395 |
Proposed branch: | lp:~thisfred/u1db/add-basic-auth |
Merge into: | lp:u1db |
Diff against target: |
395 lines (+231/-27) 5 files modified
u1db/remote/basic_auth_middleware.py (+63/-0) u1db/remote/oauth_middleware.py (+3/-2) u1db/tests/test_auth_middleware.py (+157/-15) u1db/tests/test_https.py (+7/-9) u1db/tests/test_remote_sync_target.py (+1/-1) |
To merge this branch: | bzr merge lp:~thisfred/u1db/add-basic-auth |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Samuele Pedroni | Approve | ||
Review via email: mp+122323@code.launchpad.net |
Commit message
Added basic authentication middleware.
Description of the change
Added basic authentication middleware.
To post a comment you must log in.
lp:~thisfred/u1db/add-basic-auth
updated
- 396. By Eric Casteleijn
-
prefix configurable
- 397. By Eric Casteleijn
-
improved testing, removed copy paste detritus
- 398. By Eric Casteleijn
-
more prefix tests
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'u1db/remote/basic_auth_middleware.py' | |||
2 | --- u1db/remote/basic_auth_middleware.py 1970-01-01 00:00:00 +0000 | |||
3 | +++ u1db/remote/basic_auth_middleware.py 2012-09-05 16:09:18 +0000 | |||
4 | @@ -0,0 +1,63 @@ | |||
5 | 1 | # Copyright 2012 Canonical Ltd. | ||
6 | 2 | # | ||
7 | 3 | # This file is part of u1db. | ||
8 | 4 | # | ||
9 | 5 | # u1db is free software: you can redistribute it and/or modify | ||
10 | 6 | # it under the terms of the GNU Lesser General Public License version 3 | ||
11 | 7 | # as published by the Free Software Foundation. | ||
12 | 8 | # | ||
13 | 9 | # u1db is distributed in the hope that it will be useful, | ||
14 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | 12 | # GNU Lesser General Public License for more details. | ||
17 | 13 | # | ||
18 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
19 | 15 | # along with u1db. If not, see <http://www.gnu.org/licenses/>. | ||
20 | 16 | """U1DB Basic Auth authorisation WSGI middleware.""" | ||
21 | 17 | import httplib | ||
22 | 18 | try: | ||
23 | 19 | import simplejson as json | ||
24 | 20 | except ImportError: | ||
25 | 21 | import json # noqa | ||
26 | 22 | from wsgiref.util import shift_path_info | ||
27 | 23 | |||
28 | 24 | |||
29 | 25 | class BasicAuthMiddleware(object): | ||
30 | 26 | """U1DB Basic Auth Authorisation WSGI middleware.""" | ||
31 | 27 | |||
32 | 28 | def __init__(self, app, prefix): | ||
33 | 29 | self.app = app | ||
34 | 30 | self.prefix = prefix | ||
35 | 31 | |||
36 | 32 | def _error(self, start_response, status, description, message=None): | ||
37 | 33 | start_response("%d %s" % (status, httplib.responses[status]), | ||
38 | 34 | [('content-type', 'application/json')]) | ||
39 | 35 | err = {"error": description} | ||
40 | 36 | if message: | ||
41 | 37 | err['message'] = message | ||
42 | 38 | return [json.dumps(err)] | ||
43 | 39 | |||
44 | 40 | def __call__(self, environ, start_response): | ||
45 | 41 | if self.prefix and not environ['PATH_INFO'].startswith(self.prefix): | ||
46 | 42 | return self._error(start_response, 400, "bad request") | ||
47 | 43 | auth = environ.get('HTTP_AUTHORIZATION') | ||
48 | 44 | if not auth: | ||
49 | 45 | return self._error(start_response, 401, "unauthorized", | ||
50 | 46 | "Missing Basic Authentication.") | ||
51 | 47 | scheme, encoded = auth.split(None, 1) | ||
52 | 48 | if scheme.lower() != 'basic': | ||
53 | 49 | return self._error( | ||
54 | 50 | start_response, 401, "unauthorized", | ||
55 | 51 | "Missing Basic Authentication") | ||
56 | 52 | user, password = encoded.decode('base64').split(':', 1) | ||
57 | 53 | if not self.verify_user(user, password): | ||
58 | 54 | return self._error( | ||
59 | 55 | start_response, 401, "unauthorized", | ||
60 | 56 | "Incorrect password or login.") | ||
61 | 57 | del environ['HTTP_AUTHORIZATION'] | ||
62 | 58 | environ['user_id'] = user | ||
63 | 59 | shift_path_info(environ) | ||
64 | 60 | return self.app(environ, start_response) | ||
65 | 61 | |||
66 | 62 | def verify_user(self, username, password): | ||
67 | 63 | raise NotImplementedError(self.verify_user) | ||
68 | 0 | 64 | ||
69 | === modified file 'u1db/remote/oauth_middleware.py' | |||
70 | --- u1db/remote/oauth_middleware.py 2012-08-14 14:31:45 +0000 | |||
71 | +++ u1db/remote/oauth_middleware.py 2012-09-05 16:09:18 +0000 | |||
72 | @@ -35,9 +35,10 @@ | |||
73 | 35 | # from arrival time | 35 | # from arrival time |
74 | 36 | timestamp_threshold = 300 | 36 | timestamp_threshold = 300 |
75 | 37 | 37 | ||
77 | 38 | def __init__(self, app, base_url): | 38 | def __init__(self, app, base_url, prefix='/~/'): |
78 | 39 | self.app = app | 39 | self.app = app |
79 | 40 | self.base_url = base_url | 40 | self.base_url = base_url |
80 | 41 | self.prefix = prefix | ||
81 | 41 | 42 | ||
82 | 42 | def get_oauth_data_store(self): | 43 | def get_oauth_data_store(self): |
83 | 43 | """Provide a oauth.OAuthDataStore.""" | 44 | """Provide a oauth.OAuthDataStore.""" |
84 | @@ -52,7 +53,7 @@ | |||
85 | 52 | return [json.dumps(err)] | 53 | return [json.dumps(err)] |
86 | 53 | 54 | ||
87 | 54 | def __call__(self, environ, start_response): | 55 | def __call__(self, environ, start_response): |
89 | 55 | if not environ['PATH_INFO'].startswith('/~/'): | 56 | if self.prefix and not environ['PATH_INFO'].startswith(self.prefix): |
90 | 56 | return self._error(start_response, 400, "bad request") | 57 | return self._error(start_response, 400, "bad request") |
91 | 57 | headers = {} | 58 | headers = {} |
92 | 58 | if 'HTTP_AUTHORIZATION' in environ: | 59 | if 'HTTP_AUTHORIZATION' in environ: |
93 | 59 | 60 | ||
94 | === renamed file 'u1db/tests/test_oauth_middleware.py' => 'u1db/tests/test_auth_middleware.py' | |||
95 | --- u1db/tests/test_oauth_middleware.py 2012-08-14 14:31:45 +0000 | |||
96 | +++ u1db/tests/test_auth_middleware.py 2012-09-05 16:09:18 +0000 | |||
97 | @@ -26,15 +26,89 @@ | |||
98 | 26 | from u1db import tests | 26 | from u1db import tests |
99 | 27 | 27 | ||
100 | 28 | from u1db.remote.oauth_middleware import OAuthMiddleware | 28 | from u1db.remote.oauth_middleware import OAuthMiddleware |
110 | 29 | 29 | from u1db.remote.basic_auth_middleware import BasicAuthMiddleware | |
111 | 30 | 30 | ||
112 | 31 | BASE_URL = 'https://u1db.net' | 31 | |
113 | 32 | 32 | BASE_URL = 'https://example.net' | |
114 | 33 | 33 | ||
115 | 34 | class TestAuthMiddleware(tests.TestCase): | 34 | |
116 | 35 | 35 | class TestBasicAuthMiddleware(tests.TestCase): | |
117 | 36 | def setUp(self): | 36 | |
118 | 37 | super(TestAuthMiddleware, self).setUp() | 37 | def setUp(self): |
119 | 38 | super(TestBasicAuthMiddleware, self).setUp() | ||
120 | 39 | self.got = [] | ||
121 | 40 | |||
122 | 41 | def witness_app(environ, start_response): | ||
123 | 42 | start_response("200 OK", [("content-type", "text/plain")]) | ||
124 | 43 | self.got.append((environ['user_id'], environ['PATH_INFO'], | ||
125 | 44 | environ['QUERY_STRING'])) | ||
126 | 45 | return ["ok"] | ||
127 | 46 | |||
128 | 47 | class MyAuthMiddleware(BasicAuthMiddleware): | ||
129 | 48 | |||
130 | 49 | def verify_user(self, user, password): | ||
131 | 50 | if user != "correct_user": | ||
132 | 51 | return False | ||
133 | 52 | if password != "correct_password": | ||
134 | 53 | return False | ||
135 | 54 | return True | ||
136 | 55 | |||
137 | 56 | self.auth_midw = MyAuthMiddleware(witness_app, prefix="/pfx/") | ||
138 | 57 | self.app = paste.fixture.TestApp(self.auth_midw) | ||
139 | 58 | |||
140 | 59 | def test_expect_prefix(self): | ||
141 | 60 | url = BASE_URL + '/foo/doc/doc-id' | ||
142 | 61 | resp = self.app.delete(url, expect_errors=True) | ||
143 | 62 | self.assertEqual(400, resp.status) | ||
144 | 63 | self.assertEqual('application/json', resp.header('content-type')) | ||
145 | 64 | self.assertEqual('{"error": "bad request"}', resp.body) | ||
146 | 65 | |||
147 | 66 | def test_missing_auth(self): | ||
148 | 67 | url = BASE_URL + '/pfx/foo/doc/doc-id' | ||
149 | 68 | resp = self.app.delete(url, expect_errors=True) | ||
150 | 69 | self.assertEqual(401, resp.status) | ||
151 | 70 | self.assertEqual('application/json', resp.header('content-type')) | ||
152 | 71 | self.assertEqual( | ||
153 | 72 | {"error": "unauthorized", | ||
154 | 73 | "message": "Missing Basic Authentication."}, | ||
155 | 74 | json.loads(resp.body)) | ||
156 | 75 | |||
157 | 76 | def test_correct_auth(self): | ||
158 | 77 | user = "correct_user" | ||
159 | 78 | password = "correct_password" | ||
160 | 79 | params = {'old_rev': 'old-rev'} | ||
161 | 80 | url = BASE_URL + '/pfx/foo/doc/doc-id?%s' % ( | ||
162 | 81 | '&'.join("%s=%s" % (k, v) for k, v in params.items())) | ||
163 | 82 | auth = '%s:%s' % (user, password) | ||
164 | 83 | headers = { | ||
165 | 84 | 'Authorization': 'Basic %s' % (auth.encode('base64'),)} | ||
166 | 85 | resp = self.app.delete(url, headers=headers) | ||
167 | 86 | self.assertEqual(200, resp.status) | ||
168 | 87 | self.assertEqual( | ||
169 | 88 | [('correct_user', '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) | ||
170 | 89 | |||
171 | 90 | def test_incorrect_auth(self): | ||
172 | 91 | user = "correct_user" | ||
173 | 92 | password = "incorrect_password" | ||
174 | 93 | params = {'old_rev': 'old-rev'} | ||
175 | 94 | url = BASE_URL + '/pfx/foo/doc/doc-id?%s' % ( | ||
176 | 95 | '&'.join("%s=%s" % (k, v) for k, v in params.items())) | ||
177 | 96 | auth = '%s:%s' % (user, password) | ||
178 | 97 | headers = { | ||
179 | 98 | 'Authorization': 'Basic %s' % (auth.encode('base64'),)} | ||
180 | 99 | resp = self.app.delete(url, headers=headers, expect_errors=True) | ||
181 | 100 | self.assertEqual(401, resp.status) | ||
182 | 101 | self.assertEqual('application/json', resp.header('content-type')) | ||
183 | 102 | self.assertEqual( | ||
184 | 103 | {"error": "unauthorized", | ||
185 | 104 | "message": "Incorrect password or login."}, | ||
186 | 105 | json.loads(resp.body)) | ||
187 | 106 | |||
188 | 107 | |||
189 | 108 | class TestOAuthMiddlewareDefaultPrefix(tests.TestCase): | ||
190 | 109 | def setUp(self): | ||
191 | 110 | |||
192 | 111 | super(TestOAuthMiddlewareDefaultPrefix, self).setUp() | ||
193 | 38 | self.got = [] | 112 | self.got = [] |
194 | 39 | 113 | ||
195 | 40 | def witness_app(environ, start_response): | 114 | def witness_app(environ, start_response): |
196 | @@ -61,8 +135,76 @@ | |||
197 | 61 | self.assertEqual('application/json', resp.header('content-type')) | 135 | self.assertEqual('application/json', resp.header('content-type')) |
198 | 62 | self.assertEqual('{"error": "bad request"}', resp.body) | 136 | self.assertEqual('{"error": "bad request"}', resp.body) |
199 | 63 | 137 | ||
200 | 138 | def test_oauth_in_header(self): | ||
201 | 139 | url = BASE_URL + '/~/foo/doc/doc-id' | ||
202 | 140 | params = {'old_rev': 'old-rev'} | ||
203 | 141 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( | ||
204 | 142 | tests.consumer2, | ||
205 | 143 | tests.token2, | ||
206 | 144 | parameters=params, | ||
207 | 145 | http_url=url, | ||
208 | 146 | http_method='DELETE' | ||
209 | 147 | ) | ||
210 | 148 | url = oauth_req.get_normalized_http_url() + '?' + ( | ||
211 | 149 | '&'.join("%s=%s" % (k, v) for k, v in params.items())) | ||
212 | 150 | oauth_req.sign_request(tests.sign_meth_HMAC_SHA1, | ||
213 | 151 | tests.consumer2, tests.token2) | ||
214 | 152 | resp = self.app.delete(url, headers=oauth_req.to_header()) | ||
215 | 153 | self.assertEqual(200, resp.status) | ||
216 | 154 | self.assertEqual([(tests.token2.key, | ||
217 | 155 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) | ||
218 | 156 | |||
219 | 157 | def test_oauth_in_query_string(self): | ||
220 | 158 | url = BASE_URL + '/~/foo/doc/doc-id' | ||
221 | 159 | params = {'old_rev': 'old-rev'} | ||
222 | 160 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( | ||
223 | 161 | tests.consumer1, | ||
224 | 162 | tests.token1, | ||
225 | 163 | parameters=params, | ||
226 | 164 | http_url=url, | ||
227 | 165 | http_method='DELETE' | ||
228 | 166 | ) | ||
229 | 167 | oauth_req.sign_request(tests.sign_meth_HMAC_SHA1, | ||
230 | 168 | tests.consumer1, tests.token1) | ||
231 | 169 | resp = self.app.delete(oauth_req.to_url()) | ||
232 | 170 | self.assertEqual(200, resp.status) | ||
233 | 171 | self.assertEqual([(tests.token1.key, | ||
234 | 172 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) | ||
235 | 173 | |||
236 | 174 | |||
237 | 175 | class TestOAuthMiddleware(tests.TestCase): | ||
238 | 176 | |||
239 | 177 | def setUp(self): | ||
240 | 178 | super(TestOAuthMiddleware, self).setUp() | ||
241 | 179 | self.got = [] | ||
242 | 180 | |||
243 | 181 | def witness_app(environ, start_response): | ||
244 | 182 | start_response("200 OK", [("content-type", "text/plain")]) | ||
245 | 183 | self.got.append((environ['token_key'], environ['PATH_INFO'], | ||
246 | 184 | environ['QUERY_STRING'])) | ||
247 | 185 | return ["ok"] | ||
248 | 186 | |||
249 | 187 | class MyOAuthMiddleware(OAuthMiddleware): | ||
250 | 188 | get_oauth_data_store = lambda self: tests.testingOAuthStore | ||
251 | 189 | |||
252 | 190 | def verify(self, environ, oauth_req): | ||
253 | 191 | consumer, token = super(MyOAuthMiddleware, self).verify( | ||
254 | 192 | environ, oauth_req) | ||
255 | 193 | environ['token_key'] = token.key | ||
256 | 194 | |||
257 | 195 | self.oauth_midw = MyOAuthMiddleware( | ||
258 | 196 | witness_app, BASE_URL, prefix='/pfx/') | ||
259 | 197 | self.app = paste.fixture.TestApp(self.oauth_midw) | ||
260 | 198 | |||
261 | 199 | def test_expect_prefix(self): | ||
262 | 200 | url = BASE_URL + '/foo/doc/doc-id' | ||
263 | 201 | resp = self.app.delete(url, expect_errors=True) | ||
264 | 202 | self.assertEqual(400, resp.status) | ||
265 | 203 | self.assertEqual('application/json', resp.header('content-type')) | ||
266 | 204 | self.assertEqual('{"error": "bad request"}', resp.body) | ||
267 | 205 | |||
268 | 64 | def test_missing_oauth(self): | 206 | def test_missing_oauth(self): |
270 | 65 | url = BASE_URL + '/~/foo/doc/doc-id' | 207 | url = BASE_URL + '/pfx/foo/doc/doc-id' |
271 | 66 | resp = self.app.delete(url, expect_errors=True) | 208 | resp = self.app.delete(url, expect_errors=True) |
272 | 67 | self.assertEqual(401, resp.status) | 209 | self.assertEqual(401, resp.status) |
273 | 68 | self.assertEqual('application/json', resp.header('content-type')) | 210 | self.assertEqual('application/json', resp.header('content-type')) |
274 | @@ -71,7 +213,7 @@ | |||
275 | 71 | json.loads(resp.body)) | 213 | json.loads(resp.body)) |
276 | 72 | 214 | ||
277 | 73 | def test_oauth_in_query_string(self): | 215 | def test_oauth_in_query_string(self): |
279 | 74 | url = BASE_URL + '/~/foo/doc/doc-id' | 216 | url = BASE_URL + '/pfx/foo/doc/doc-id' |
280 | 75 | params = {'old_rev': 'old-rev'} | 217 | params = {'old_rev': 'old-rev'} |
281 | 76 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( | 218 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( |
282 | 77 | tests.consumer1, | 219 | tests.consumer1, |
283 | @@ -88,7 +230,7 @@ | |||
284 | 88 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) | 230 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) |
285 | 89 | 231 | ||
286 | 90 | def test_oauth_invalid(self): | 232 | def test_oauth_invalid(self): |
288 | 91 | url = BASE_URL + '/~/foo/doc/doc-id' | 233 | url = BASE_URL + '/pfx/foo/doc/doc-id' |
289 | 92 | params = {'old_rev': 'old-rev'} | 234 | params = {'old_rev': 'old-rev'} |
290 | 93 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( | 235 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( |
291 | 94 | tests.consumer1, | 236 | tests.consumer1, |
292 | @@ -109,7 +251,7 @@ | |||
293 | 109 | err) | 251 | err) |
294 | 110 | 252 | ||
295 | 111 | def test_oauth_in_header(self): | 253 | def test_oauth_in_header(self): |
297 | 112 | url = BASE_URL + '/~/foo/doc/doc-id' | 254 | url = BASE_URL + '/pfx/foo/doc/doc-id' |
298 | 113 | params = {'old_rev': 'old-rev'} | 255 | params = {'old_rev': 'old-rev'} |
299 | 114 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( | 256 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( |
300 | 115 | tests.consumer2, | 257 | tests.consumer2, |
301 | @@ -128,7 +270,7 @@ | |||
302 | 128 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) | 270 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) |
303 | 129 | 271 | ||
304 | 130 | def test_oauth_plain_text(self): | 272 | def test_oauth_plain_text(self): |
306 | 131 | url = BASE_URL + '/~/foo/doc/doc-id' | 273 | url = BASE_URL + '/pfx/foo/doc/doc-id' |
307 | 132 | params = {'old_rev': 'old-rev'} | 274 | params = {'old_rev': 'old-rev'} |
308 | 133 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( | 275 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( |
309 | 134 | tests.consumer1, | 276 | tests.consumer1, |
310 | @@ -145,7 +287,7 @@ | |||
311 | 145 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) | 287 | '/foo/doc/doc-id', 'old_rev=old-rev')], self.got) |
312 | 146 | 288 | ||
313 | 147 | def test_oauth_timestamp_threshold(self): | 289 | def test_oauth_timestamp_threshold(self): |
315 | 148 | url = BASE_URL + '/~/foo/doc/doc-id' | 290 | url = BASE_URL + '/pfx/foo/doc/doc-id' |
316 | 149 | params = {'old_rev': 'old-rev'} | 291 | params = {'old_rev': 'old-rev'} |
317 | 150 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( | 292 | oauth_req = oauth.OAuthRequest.from_consumer_and_token( |
318 | 151 | tests.consumer1, | 293 | tests.consumer1, |
319 | 152 | 294 | ||
320 | === modified file 'u1db/tests/test_https.py' | |||
321 | --- u1db/tests/test_https.py 2012-07-05 15:26:52 +0000 | |||
322 | +++ u1db/tests/test_https.py 2012-09-05 16:09:18 +0000 | |||
323 | @@ -7,7 +7,6 @@ | |||
324 | 7 | from paste import httpserver | 7 | from paste import httpserver |
325 | 8 | 8 | ||
326 | 9 | from u1db import ( | 9 | from u1db import ( |
327 | 10 | errors, | ||
328 | 11 | tests, | 10 | tests, |
329 | 12 | ) | 11 | ) |
330 | 13 | from u1db.remote import ( | 12 | from u1db.remote import ( |
331 | @@ -21,7 +20,7 @@ | |||
332 | 21 | def oauth_https_server_def(): | 20 | def oauth_https_server_def(): |
333 | 22 | def make_server(host_port, handler, state): | 21 | def make_server(host_port, handler, state): |
334 | 23 | app = http_app.HTTPApp(state) | 22 | app = http_app.HTTPApp(state) |
336 | 24 | application = oauth_middleware.OAuthMiddleware(app, None) | 23 | application = oauth_middleware.OAuthMiddleware(app, None, prefix='/~/') |
337 | 25 | application.get_oauth_data_store = lambda: tests.testingOAuthStore | 24 | application.get_oauth_data_store = lambda: tests.testingOAuthStore |
338 | 26 | from OpenSSL import SSL | 25 | from OpenSSL import SSL |
339 | 27 | cert_file = os.path.join(os.path.dirname(__file__), 'testing-certs', | 26 | cert_file = os.path.join(os.path.dirname(__file__), 'testing-certs', |
340 | @@ -36,8 +35,6 @@ | |||
341 | 36 | handler, | 35 | handler, |
342 | 37 | ssl_context=ssl_context | 36 | ssl_context=ssl_context |
343 | 38 | ) | 37 | ) |
344 | 39 | # workaround apparent interface mismatch | ||
345 | 40 | orig_shutdown_request = srv.shutdown_request | ||
346 | 41 | 38 | ||
347 | 42 | def shutdown_request(req): | 39 | def shutdown_request(req): |
348 | 43 | req.shutdown() | 40 | req.shutdown() |
349 | @@ -68,7 +65,7 @@ | |||
350 | 68 | 65 | ||
351 | 69 | def setUp(self): | 66 | def setUp(self): |
352 | 70 | try: | 67 | try: |
354 | 71 | import OpenSSL | 68 | import OpenSSL # noqa |
355 | 72 | except ImportError: | 69 | except ImportError: |
356 | 73 | self.skipTest("Requires pyOpenSSL") | 70 | self.skipTest("Requires pyOpenSSL") |
357 | 74 | self.cacert_pem = os.path.join(os.path.dirname(__file__), | 71 | self.cacert_pem = os.path.join(os.path.dirname(__file__), |
358 | @@ -96,7 +93,7 @@ | |||
359 | 96 | self.startServer() | 93 | self.startServer() |
360 | 97 | # don't print expected traceback server-side | 94 | # don't print expected traceback server-side |
361 | 98 | self.server.handle_error = lambda req, cli_addr: None | 95 | self.server.handle_error = lambda req, cli_addr: None |
363 | 99 | db = self.request_state._create_database('test') | 96 | self.request_state._create_database('test') |
364 | 100 | remote_target = self.getSyncTarget('localhost', 'test') | 97 | remote_target = self.getSyncTarget('localhost', 'test') |
365 | 101 | try: | 98 | try: |
366 | 102 | remote_target.record_sync_info('other-id', 2, 'T-id') | 99 | remote_target.record_sync_info('other-id', 2, 'T-id') |
367 | @@ -110,11 +107,12 @@ | |||
368 | 110 | self.skipTest( | 107 | self.skipTest( |
369 | 111 | "XXX certificate verification happens on linux only for now") | 108 | "XXX certificate verification happens on linux only for now") |
370 | 112 | self.startServer() | 109 | self.startServer() |
372 | 113 | db = self.request_state._create_database('test') | 110 | self.request_state._create_database('test') |
373 | 114 | self.patch(http_client, 'CA_CERTS', self.cacert_pem) | 111 | self.patch(http_client, 'CA_CERTS', self.cacert_pem) |
374 | 115 | remote_target = self.getSyncTarget('127.0.0.1', 'test') | 112 | remote_target = self.getSyncTarget('127.0.0.1', 'test') |
377 | 116 | self.assertRaises(http_client.CertificateError, | 113 | self.assertRaises( |
378 | 117 | remote_target.record_sync_info, 'other-id', 2, 'T-id') | 114 | http_client.CertificateError, remote_target.record_sync_info, |
379 | 115 | 'other-id', 2, 'T-id') | ||
380 | 118 | 116 | ||
381 | 119 | 117 | ||
382 | 120 | load_tests = tests.load_with_scenarios | 118 | load_tests = tests.load_with_scenarios |
383 | 121 | 119 | ||
384 | === modified file 'u1db/tests/test_remote_sync_target.py' | |||
385 | --- u1db/tests/test_remote_sync_target.py 2012-07-19 19:50:58 +0000 | |||
386 | +++ u1db/tests/test_remote_sync_target.py 2012-09-05 16:09:18 +0000 | |||
387 | @@ -130,7 +130,7 @@ | |||
388 | 130 | 130 | ||
389 | 131 | def make_server(host_port, handler, state): | 131 | def make_server(host_port, handler, state): |
390 | 132 | app = http_app.HTTPApp(state) | 132 | app = http_app.HTTPApp(state) |
392 | 133 | application = oauth_middleware.OAuthMiddleware(app, None) | 133 | application = oauth_middleware.OAuthMiddleware(app, None, prefix='/~/') |
393 | 134 | application.get_oauth_data_store = lambda: tests.testingOAuthStore | 134 | application.get_oauth_data_store = lambda: tests.testingOAuthStore |
394 | 135 | srv = simple_server.WSGIServer(host_port, handler) | 135 | srv = simple_server.WSGIServer(host_port, handler) |
395 | 136 | # patch the value in | 136 | # patch the value in |
good