Mercurial > public > src > rhodecode
comparison pylons_app/lib/middleware/simplehg.py @ 330:c961b78ff0a0
rewritten simplehg middleware. Now permissions are checked for each repository/request/user
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Tue, 29 Jun 2010 20:43:01 +0200 |
parents | 66f617f162f8 |
children | 4c9a295d80a4 |
comparison
equal
deleted
inserted
replaced
329:d6e2817734d2 | 330:c961b78ff0a0 |
---|---|
24 @author: marcink | 24 @author: marcink |
25 SimpleHG middleware for handling mercurial protocol request (push/clone etc.) | 25 SimpleHG middleware for handling mercurial protocol request (push/clone etc.) |
26 It's implemented with basic auth function | 26 It's implemented with basic auth function |
27 """ | 27 """ |
28 from datetime import datetime | 28 from datetime import datetime |
29 from itertools import chain | |
29 from mercurial.hgweb import hgweb | 30 from mercurial.hgweb import hgweb |
30 from mercurial.hgweb.request import wsgiapplication | 31 from mercurial.hgweb.request import wsgiapplication |
31 from paste.auth.basic import AuthBasicAuthenticator | 32 from paste.auth.basic import AuthBasicAuthenticator |
32 from paste.httpheaders import REMOTE_USER, AUTH_TYPE | 33 from paste.httpheaders import REMOTE_USER, AUTH_TYPE |
33 from pylons_app.lib.auth import authfunc | 34 from pylons_app.lib.auth import authfunc, HasPermissionAnyMiddleware |
34 from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache | 35 from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache |
35 from pylons_app.model import meta | 36 from pylons_app.model import meta |
36 from pylons_app.model.db import UserLog, User | 37 from pylons_app.model.db import UserLog, User |
37 from webob.exc import HTTPNotFound | 38 from webob.exc import HTTPNotFound, HTTPForbidden |
38 import logging | 39 import logging |
39 import os | 40 import os |
40 from itertools import chain | 41 import traceback |
41 log = logging.getLogger(__name__) | 42 log = logging.getLogger(__name__) |
42 | 43 |
43 class SimpleHg(object): | 44 class SimpleHg(object): |
44 | 45 |
45 def __init__(self, application, config): | 46 def __init__(self, application, config): |
46 self.application = application | 47 self.application = application |
47 self.config = config | 48 self.config = config |
48 #authenticate this mercurial request using | 49 #authenticate this mercurial request using |
49 realm = '%s %s' % (config['hg_app_name'], 'mercurial repository') | 50 realm = '%s %s' % (self.config['hg_app_name'], 'mercurial repository') |
50 self.authenticate = AuthBasicAuthenticator(realm, authfunc) | 51 self.authenticate = AuthBasicAuthenticator(realm, authfunc) |
51 | 52 |
52 def __call__(self, environ, start_response): | 53 def __call__(self, environ, start_response): |
53 if not is_mercurial(environ): | 54 if not is_mercurial(environ): |
54 return self.application(environ, start_response) | 55 return self.application(environ, start_response) |
66 return result.wsgi_application(environ, start_response) | 67 return result.wsgi_application(environ, start_response) |
67 | 68 |
68 try: | 69 try: |
69 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:]) | 70 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:]) |
70 except Exception as e: | 71 except Exception as e: |
71 log.error(e) | 72 log.error(traceback.format_exc()) |
72 return HTTPNotFound()(environ, start_response) | 73 return HTTPNotFound()(environ, start_response) |
73 | 74 |
74 #since we wrap into hgweb, just reset the path | 75 #=================================================================== |
75 environ['PATH_INFO'] = '/' | 76 # CHECK PERMISSIONS FOR THIS REQUEST |
77 #=================================================================== | |
78 action = self.__get_action(environ) | |
79 if action: | |
80 username = self.__get_environ_user(environ) | |
81 try: | |
82 sa = meta.Session | |
83 user = sa.query(User)\ | |
84 .filter(User.username == username).one() | |
85 except: | |
86 return HTTPNotFound()(environ, start_response) | |
87 #check permissions for this repository | |
88 if action == 'pull': | |
89 if not HasPermissionAnyMiddleware('repository.read', | |
90 'repository.write', | |
91 'repository.admin')\ | |
92 (user, repo_name): | |
93 return HTTPForbidden()(environ, start_response) | |
94 if action == 'push': | |
95 if not HasPermissionAnyMiddleware('repository.write', | |
96 'repository.admin')\ | |
97 (user, repo_name): | |
98 return HTTPForbidden()(environ, start_response) | |
99 | |
100 #log action | |
101 self.__log_user_action(user, action, repo_name) | |
102 | |
103 #=================================================================== | |
104 # MERCURIAL REQUEST HANDLING | |
105 #=================================================================== | |
106 environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path | |
76 self.baseui = make_ui(self.config['hg_app_repo_conf']) | 107 self.baseui = make_ui(self.config['hg_app_repo_conf']) |
77 self.basepath = self.baseui.configitems('paths')[0][1]\ | 108 self.basepath = self.config['base_path'] |
78 .replace('*', '') | |
79 self.repo_path = os.path.join(self.basepath, repo_name) | 109 self.repo_path = os.path.join(self.basepath, repo_name) |
80 try: | 110 try: |
81 app = wsgiapplication(self.__make_app) | 111 app = wsgiapplication(self.__make_app) |
82 except Exception as e: | 112 except Exception: |
83 log.error(e) | 113 log.error(traceback.format_exc()) |
84 return HTTPNotFound()(environ, start_response) | 114 return HTTPNotFound()(environ, start_response) |
85 action = self.__get_action(environ) | 115 |
116 | |
86 #invalidate cache on push | 117 #invalidate cache on push |
87 if action == 'push': | 118 if action == 'push': |
88 self.__invalidate_cache(repo_name) | 119 self.__invalidate_cache(repo_name) |
89 | 120 |
90 if action: | |
91 username = self.__get_environ_user(environ) | |
92 self.__log_user_action(username, action, repo_name) | |
93 messages = ['thanks for using hg app !'] | 121 messages = ['thanks for using hg app !'] |
94 return self.msg_wrapper(app, environ, start_response, messages) | 122 return self.msg_wrapper(app, environ, start_response, messages) |
95 | 123 |
96 | 124 |
97 def msg_wrapper(self, app, environ, start_response, messages): | 125 def msg_wrapper(self, app, environ, start_response, messages): |
98 """ | 126 """ |
99 Wrapper for custom messages that come out of mercurial respond messages | 127 Wrapper for custom messages that come out of mercurial respond messages |
100 is a list of messages that the user will see at the end of response from | 128 is a list of messages that the user will see at the end of response |
101 merurial protocol actions that involves remote answers | 129 from merurial protocol actions that involves remote answers |
102 @param app: | 130 @param app: |
103 @param environ: | 131 @param environ: |
104 @param start_response: | 132 @param start_response: |
105 """ | 133 """ |
106 def custom_messages(msg_list): | 134 def custom_messages(msg_list): |
131 if qry.startswith('cmd'): | 159 if qry.startswith('cmd'): |
132 cmd = qry.split('=')[-1] | 160 cmd = qry.split('=')[-1] |
133 if mapping.has_key(cmd): | 161 if mapping.has_key(cmd): |
134 return mapping[cmd] | 162 return mapping[cmd] |
135 | 163 |
136 def __log_user_action(self, username, action, repo): | 164 def __log_user_action(self, user, action, repo): |
137 sa = meta.Session | 165 sa = meta.Session |
138 try: | 166 try: |
139 user = sa.query(User).filter(User.username == username).one() | |
140 user_log = UserLog() | 167 user_log = UserLog() |
141 user_log.user_id = user.user_id | 168 user_log.user_id = user.user_id |
142 user_log.action = action | 169 user_log.action = action |
143 user_log.repository = repo.replace('/', '') | 170 user_log.repository = repo.replace('/', '') |
144 user_log.action_date = datetime.now() | 171 user_log.action_date = datetime.now() |
145 sa.add(user_log) | 172 sa.add(user_log) |
146 sa.commit() | 173 sa.commit() |
147 log.info('Adding user %s, action %s on %s', | 174 log.info('Adding user %s, action %s on %s', |
148 username, action, repo) | 175 user.username, action, repo) |
149 except Exception as e: | 176 except Exception as e: |
150 sa.rollback() | 177 sa.rollback() |
151 log.error('could not log user action:%s', str(e)) | 178 log.error('could not log user action:%s', str(e)) |
152 | 179 |
153 def __invalidate_cache(self, repo_name): | 180 def __invalidate_cache(self, repo_name): |