comparison mercurial/hgweb/hgweb_mod.py @ 9910:6f92997dbdca

hgweb: add support for extension-provided permission hooks This allows extensions to hook into permission checking, providing both authentication and authorization as needed. The existing authorization function has been changed to a hook, which is added by default.
author Sune Foldager <cryo@cyanite.org>
date Mon, 23 Nov 2009 11:03:55 +0100
parents 510122bb3c7f
children 97c75ad3b1a0
comparison
equal deleted inserted replaced
9905:95517eb3c9a7 9910:6f92997dbdca
6 # This software may be used and distributed according to the terms of the 6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2, incorporated herein by reference. 7 # GNU General Public License version 2, incorporated herein by reference.
8 8
9 import os 9 import os
10 from mercurial import ui, hg, hook, error, encoding, templater 10 from mercurial import ui, hg, hook, error, encoding, templater
11 from common import get_mtime, ErrorResponse 11 from common import get_mtime, ErrorResponse, permhooks
12 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR 12 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
13 from common import HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED 13 from common import HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED
14 from request import wsgirequest 14 from request import wsgirequest
15 import webcommands, protocol, webutil 15 import webcommands, protocol, webutil
16 16
281 'gz': ('application/x-tar', 'tgz', '.tar.gz', None), 281 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
282 'zip': ('application/zip', 'zip', '.zip', None), 282 'zip': ('application/zip', 'zip', '.zip', None),
283 } 283 }
284 284
285 def check_perm(self, req, op): 285 def check_perm(self, req, op):
286 '''Check permission for operation based on request data (including 286 for hook in permhooks:
287 authentication info). Return if op allowed, else raise an ErrorResponse 287 hook(self, req, op)
288 exception.'''
289
290 user = req.env.get('REMOTE_USER')
291
292 deny_read = self.configlist('web', 'deny_read')
293 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
294 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
295
296 allow_read = self.configlist('web', 'allow_read')
297 result = (not allow_read) or (allow_read == ['*'])
298 if not (result or user in allow_read):
299 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
300
301 if op == 'pull' and not self.allowpull:
302 raise ErrorResponse(HTTP_UNAUTHORIZED, 'pull not authorized')
303 elif op == 'pull' or op is None: # op is None for interface requests
304 return
305
306 # enforce that you can only push using POST requests
307 if req.env['REQUEST_METHOD'] != 'POST':
308 msg = 'push requires POST request'
309 raise ErrorResponse(HTTP_METHOD_NOT_ALLOWED, msg)
310
311 # require ssl by default for pushing, auth info cannot be sniffed
312 # and replayed
313 scheme = req.env.get('wsgi.url_scheme')
314 if self.configbool('web', 'push_ssl', True) and scheme != 'https':
315 raise ErrorResponse(HTTP_OK, 'ssl required')
316
317 deny = self.configlist('web', 'deny_push')
318 if deny and (not user or deny == ['*'] or user in deny):
319 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
320
321 allow = self.configlist('web', 'allow_push')
322 result = allow and (allow == ['*'] or user in allow)
323 if not result:
324 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')