##// END OF EJS Templates
typo fixes
marcink -
r1644:59c26a9a beta
parent child Browse files
Show More
@@ -1,207 +1,207
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.users
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Users crud controller for pylons
7 7
8 8 :created_on: Apr 4, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29
30 30 from formencode import htmlfill
31 31 from pylons import request, session, tmpl_context as c, url, config
32 32 from pylons.controllers.util import abort, redirect
33 33 from pylons.i18n.translation import _
34 34
35 35 from rhodecode.lib.exceptions import DefaultUserException, \
36 36 UserOwnsReposException
37 37 from rhodecode.lib import helpers as h
38 38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
39 39 from rhodecode.lib.base import BaseController, render
40 40
41 41 from rhodecode.model.db import User, UserRepoToPerm, UserToPerm, Permission
42 42 from rhodecode.model.forms import UserForm
43 43 from rhodecode.model.user import UserModel
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47
48 48 class UsersController(BaseController):
49 49 """REST Controller styled on the Atom Publishing Protocol"""
50 50 # To properly map this controller, ensure your config/routing.py
51 51 # file has a resource setup:
52 52 # map.resource('user', 'users')
53 53
54 54 @LoginRequired()
55 55 @HasPermissionAllDecorator('hg.admin')
56 56 def __before__(self):
57 57 c.admin_user = session.get('admin_user')
58 58 c.admin_username = session.get('admin_username')
59 59 super(UsersController, self).__before__()
60 60 c.available_permissions = config['available_permissions']
61 61
62 62 def index(self, format='html'):
63 63 """GET /users: All items in the collection"""
64 64 # url('users')
65 65
66 66 c.users_list = self.sa.query(User).all()
67 67 return render('admin/users/users.html')
68 68
69 69 def create(self):
70 70 """POST /users: Create a new item"""
71 71 # url('users')
72 72
73 73 user_model = UserModel()
74 login_form = UserForm()()
74 user_form = UserForm()()
75 75 try:
76 form_result = login_form.to_python(dict(request.POST))
76 form_result = user_form.to_python(dict(request.POST))
77 77 user_model.create(form_result)
78 78 h.flash(_('created user %s') % form_result['username'],
79 79 category='success')
80 80 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
81 81 except formencode.Invalid, errors:
82 82 return htmlfill.render(
83 83 render('admin/users/user_add.html'),
84 84 defaults=errors.value,
85 85 errors=errors.error_dict or {},
86 86 prefix_error=False,
87 87 encoding="UTF-8")
88 88 except Exception:
89 89 log.error(traceback.format_exc())
90 90 h.flash(_('error occurred during creation of user %s') \
91 91 % request.POST.get('username'), category='error')
92 92 return redirect(url('users'))
93 93
94 94 def new(self, format='html'):
95 95 """GET /users/new: Form to create a new item"""
96 96 # url('new_user')
97 97 return render('admin/users/user_add.html')
98 98
99 99 def update(self, id):
100 100 """PUT /users/id: Update an existing item"""
101 101 # Forms posted to this method should contain a hidden field:
102 102 # <input type="hidden" name="_method" value="PUT" />
103 103 # Or using helpers:
104 104 # h.form(url('update_user', id=ID),
105 105 # method='put')
106 106 # url('user', id=ID)
107 107 user_model = UserModel()
108 108 c.user = user_model.get(id)
109 109
110 110 _form = UserForm(edit=True, old_data={'user_id': id,
111 111 'email': c.user.email})()
112 112 form_result = {}
113 113 try:
114 114 form_result = _form.to_python(dict(request.POST))
115 115 user_model.update(id, form_result)
116 116 h.flash(_('User updated successfully'), category='success')
117 117
118 118 except formencode.Invalid, errors:
119 119 e = errors.error_dict or {}
120 120 perm = Permission.get_by_key('hg.create.repository')
121 121 e.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
122 122 return htmlfill.render(
123 123 render('admin/users/user_edit.html'),
124 124 defaults=errors.value,
125 125 errors=e,
126 126 prefix_error=False,
127 127 encoding="UTF-8")
128 128 except Exception:
129 129 log.error(traceback.format_exc())
130 130 h.flash(_('error occurred during update of user %s') \
131 131 % form_result.get('username'), category='error')
132 132
133 133 return redirect(url('users'))
134 134
135 135 def delete(self, id):
136 136 """DELETE /users/id: Delete an existing item"""
137 137 # Forms posted to this method should contain a hidden field:
138 138 # <input type="hidden" name="_method" value="DELETE" />
139 139 # Or using helpers:
140 140 # h.form(url('delete_user', id=ID),
141 141 # method='delete')
142 142 # url('user', id=ID)
143 143 user_model = UserModel()
144 144 try:
145 145 user_model.delete(id)
146 146 h.flash(_('successfully deleted user'), category='success')
147 147 except (UserOwnsReposException, DefaultUserException), e:
148 148 h.flash(str(e), category='warning')
149 149 except Exception:
150 150 h.flash(_('An error occurred during deletion of user'),
151 151 category='error')
152 152 return redirect(url('users'))
153 153
154 154 def show(self, id, format='html'):
155 155 """GET /users/id: Show a specific item"""
156 156 # url('user', id=ID)
157 157
158 158 def edit(self, id, format='html'):
159 159 """GET /users/id/edit: Form to edit an existing item"""
160 160 # url('edit_user', id=ID)
161 161 user_model = UserModel()
162 162 c.user = user_model.get(id)
163 163 if not c.user:
164 164 return redirect(url('users'))
165 165 if c.user.username == 'default':
166 166 h.flash(_("You can't edit this user"), category='warning')
167 167 return redirect(url('users'))
168 168 c.user.permissions = {}
169 169 c.granted_permissions = user_model.fill_perms(c.user)\
170 170 .permissions['global']
171 171
172 172 defaults = c.user.get_dict()
173 173 perm = Permission.get_by_key('hg.create.repository')
174 174 defaults.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
175 175
176 176 return htmlfill.render(
177 177 render('admin/users/user_edit.html'),
178 178 defaults=defaults,
179 179 encoding="UTF-8",
180 180 force_defaults=False
181 181 )
182 182
183 183 def update_perm(self, id):
184 184 """PUT /users_perm/id: Update an existing item"""
185 185 # url('user_perm', id=ID, method='put')
186 186
187 187 grant_perm = request.POST.get('create_repo_perm', False)
188 188
189 189 if grant_perm:
190 190 perm = Permission.get_by_key('hg.create.none')
191 191 UserToPerm.revoke_perm(id, perm)
192 192
193 193 perm = Permission.get_by_key('hg.create.repository')
194 194 UserToPerm.grant_perm(id, perm)
195 195 h.flash(_("Granted 'repository create' permission to user"),
196 196 category='success')
197 197
198 198 else:
199 199 perm = Permission.get_by_key('hg.create.repository')
200 200 UserToPerm.revoke_perm(id, perm)
201 201
202 202 perm = Permission.get_by_key('hg.create.none')
203 203 UserToPerm.grant_perm(id, perm)
204 204 h.flash(_("Revoked 'repository create' permission to user"),
205 205 category='success')
206 206
207 207 return redirect(url('edit_user', id=id))
@@ -1,677 +1,678
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.auth
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 authentication and permission libraries
7 7
8 8 :created_on: Apr 4, 2010
9 9 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 10 :license: GPLv3, see COPYING for more details.
11 11 """
12 12 # This program is free software: you can redistribute it and/or modify
13 13 # it under the terms of the GNU General Public License as published by
14 14 # the Free Software Foundation, either version 3 of the License, or
15 15 # (at your option) any later version.
16 16 #
17 17 # This program is distributed in the hope that it will be useful,
18 18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 20 # GNU General Public License for more details.
21 21 #
22 22 # You should have received a copy of the GNU General Public License
23 23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 24
25 25 import random
26 26 import logging
27 27 import traceback
28 28 import hashlib
29 29
30 30 from tempfile import _RandomNameSequence
31 31 from decorator import decorator
32 32
33 33 from pylons import config, session, url, request
34 34 from pylons.controllers.util import abort, redirect
35 35 from pylons.i18n.translation import _
36 36
37 37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
38 38
39 39 if __platform__ in PLATFORM_WIN:
40 40 from hashlib import sha256
41 41 if __platform__ in PLATFORM_OTHERS:
42 42 import bcrypt
43 43
44 44 from rhodecode.lib import str2bool, safe_unicode
45 45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
46 46 from rhodecode.lib.utils import get_repo_slug
47 47 from rhodecode.lib.auth_ldap import AuthLdap
48 48
49 49 from rhodecode.model import meta
50 50 from rhodecode.model.user import UserModel
51 51 from rhodecode.model.db import Permission, RhodeCodeSetting, User
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 class PasswordGenerator(object):
57 57 """This is a simple class for generating password from
58 58 different sets of characters
59 59 usage:
60 60 passwd_gen = PasswordGenerator()
61 61 #print 8-letter password containing only big and small letters
62 62 of alphabet
63 63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
64 64 """
65 65 ALPHABETS_NUM = r'''1234567890'''
66 66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
67 67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
68 68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
69 69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
70 70 + ALPHABETS_NUM + ALPHABETS_SPECIAL
71 71 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
72 72 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
73 73 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
74 74 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
75 75
76 76 def __init__(self, passwd=''):
77 77 self.passwd = passwd
78 78
79 79 def gen_password(self, len, type):
80 80 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
81 81 return self.passwd
82 82
83 83
84 84 class RhodeCodeCrypto(object):
85 85
86 86 @classmethod
87 87 def hash_string(cls, str_):
88 88 """
89 89 Cryptographic function used for password hashing based on pybcrypt
90 90 or pycrypto in windows
91 91
92 92 :param password: password to hash
93 93 """
94 94 if __platform__ in PLATFORM_WIN:
95 95 return sha256(str_).hexdigest()
96 96 elif __platform__ in PLATFORM_OTHERS:
97 97 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
98 98 else:
99 99 raise Exception('Unknown or unsupported platform %s' \
100 100 % __platform__)
101 101
102 102 @classmethod
103 103 def hash_check(cls, password, hashed):
104 104 """
105 105 Checks matching password with it's hashed value, runs different
106 106 implementation based on platform it runs on
107 107
108 108 :param password: password
109 109 :param hashed: password in hashed form
110 110 """
111 111
112 112 if __platform__ in PLATFORM_WIN:
113 113 return sha256(password).hexdigest() == hashed
114 114 elif __platform__ in PLATFORM_OTHERS:
115 115 return bcrypt.hashpw(password, hashed) == hashed
116 116 else:
117 117 raise Exception('Unknown or unsupported platform %s' \
118 118 % __platform__)
119 119
120 120
121 121 def get_crypt_password(password):
122 122 return RhodeCodeCrypto.hash_string(password)
123 123
124 124
125 125 def check_password(password, hashed):
126 126 return RhodeCodeCrypto.hash_check(password, hashed)
127 127
128 128 def generate_api_key(str_, salt=None):
129 129 """
130 130 Generates API KEY from given string
131 131
132 132 :param str_:
133 133 :param salt:
134 134 """
135 135
136 136 if salt is None:
137 137 salt = _RandomNameSequence().next()
138 138
139 139 return hashlib.sha1(str_ + salt).hexdigest()
140 140
141 141
142 142 def authfunc(environ, username, password):
143 143 """
144 Dummy authentication function used in Mercurial/Git/ and access control,
144 Dummy authentication wrapper function used in Mercurial and Git for
145 access control.
145 146
146 147 :param environ: needed only for using in Basic auth
147 148 """
148 149 return authenticate(username, password)
149 150
150 151
151 152 def authenticate(username, password):
152 153 """
153 154 Authentication function used for access control,
154 155 firstly checks for db authentication then if ldap is enabled for ldap
155 156 authentication, also creates ldap user if not in database
156 157
157 158 :param username: username
158 159 :param password: password
159 160 """
160 161
161 162 user_model = UserModel()
162 163 user = User.get_by_username(username)
163 164
164 165 log.debug('Authenticating user using RhodeCode account')
165 166 if user is not None and not user.ldap_dn:
166 167 if user.active:
167 168 if user.username == 'default' and user.active:
168 169 log.info('user %s authenticated correctly as anonymous user',
169 170 username)
170 171 return True
171 172
172 173 elif user.username == username and check_password(password,
173 174 user.password):
174 175 log.info('user %s authenticated correctly', username)
175 176 return True
176 177 else:
177 178 log.warning('user %s is disabled', username)
178 179
179 180 else:
180 181 log.debug('Regular authentication failed')
181 182 user_obj = User.get_by_username(username, case_insensitive=True)
182 183
183 184 if user_obj is not None and not user_obj.ldap_dn:
184 185 log.debug('this user already exists as non ldap')
185 186 return False
186 187
187 188 ldap_settings = RhodeCodeSetting.get_ldap_settings()
188 189 #======================================================================
189 190 # FALLBACK TO LDAP AUTH IF ENABLE
190 191 #======================================================================
191 192 if str2bool(ldap_settings.get('ldap_active')):
192 193 log.debug("Authenticating user using ldap")
193 194 kwargs = {
194 195 'server': ldap_settings.get('ldap_host', ''),
195 196 'base_dn': ldap_settings.get('ldap_base_dn', ''),
196 197 'port': ldap_settings.get('ldap_port'),
197 198 'bind_dn': ldap_settings.get('ldap_dn_user'),
198 199 'bind_pass': ldap_settings.get('ldap_dn_pass'),
199 200 'tls_kind': ldap_settings.get('ldap_tls_kind'),
200 201 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
201 202 'ldap_filter': ldap_settings.get('ldap_filter'),
202 203 'search_scope': ldap_settings.get('ldap_search_scope'),
203 204 'attr_login': ldap_settings.get('ldap_attr_login'),
204 205 'ldap_version': 3,
205 206 }
206 207 log.debug('Checking for ldap authentication')
207 208 try:
208 209 aldap = AuthLdap(**kwargs)
209 210 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
210 211 password)
211 212 log.debug('Got ldap DN response %s', user_dn)
212 213
213 214 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
214 215 .get(k), [''])[0]
215 216
216 217 user_attrs = {
217 218 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
218 219 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
219 220 'email': get_ldap_attr('ldap_attr_email'),
220 221 }
221 222
222 223 if user_model.create_ldap(username, password, user_dn,
223 224 user_attrs):
224 225 log.info('created new ldap user %s', username)
225 226
226 227 return True
227 228 except (LdapUsernameError, LdapPasswordError,):
228 229 pass
229 230 except (Exception,):
230 231 log.error(traceback.format_exc())
231 232 pass
232 233 return False
233 234
234 235 def login_container_auth(username):
235 236 user = User.get_by_username(username)
236 237 if user is None:
237 238 user_model = UserModel()
238 239 user_attrs = {
239 240 'name': username,
240 241 'lastname': None,
241 242 'email': None,
242 243 }
243 244 user = user_model.create_for_container_auth(username, user_attrs)
244 245 if not user:
245 246 return None
246 247 log.info('User %s was created by container authentication', username)
247 248
248 249 if not user.active:
249 250 return None
250 251
251 252 user.update_lastlogin()
252 253 log.debug('User %s is now logged in by container authentication',
253 254 user.username)
254 255 return user
255 256
256 257 def get_container_username(environ, config):
257 258 username = None
258 259
259 260 if str2bool(config.get('container_auth_enabled', False)):
260 261 from paste.httpheaders import REMOTE_USER
261 262 username = REMOTE_USER(environ)
262 263
263 264 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
264 265 username = environ.get('HTTP_X_FORWARDED_USER')
265 266
266 267 if username:
267 268 # Removing realm and domain from username
268 269 username = username.partition('@')[0]
269 270 username = username.rpartition('\\')[2]
270 271 log.debug('Received username %s from container', username)
271 272
272 273 return username
273 274
274 275 class AuthUser(object):
275 276 """
276 277 A simple object that handles all attributes of user in RhodeCode
277 278
278 279 It does lookup based on API key,given user, or user present in session
279 280 Then it fills all required information for such user. It also checks if
280 281 anonymous access is enabled and if so, it returns default user as logged
281 282 in
282 283 """
283 284
284 285 def __init__(self, user_id=None, api_key=None, username=None):
285 286
286 287 self.user_id = user_id
287 288 self.api_key = None
288 289 self.username = username
289 290
290 291 self.name = ''
291 292 self.lastname = ''
292 293 self.email = ''
293 294 self.is_authenticated = False
294 295 self.admin = False
295 296 self.permissions = {}
296 297 self._api_key = api_key
297 298 self.propagate_data()
298 299
299 300 def propagate_data(self):
300 301 user_model = UserModel()
301 302 self.anonymous_user = User.get_by_username('default')
302 303 is_user_loaded = False
303 304
304 305 # try go get user by api key
305 306 if self._api_key and self._api_key != self.anonymous_user.api_key:
306 307 log.debug('Auth User lookup by API KEY %s', self._api_key)
307 308 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
308 309 # lookup by userid
309 310 elif (self.user_id is not None and
310 311 self.user_id != self.anonymous_user.user_id):
311 312 log.debug('Auth User lookup by USER ID %s', self.user_id)
312 313 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
313 314 # lookup by username
314 315 elif self.username:
315 316 log.debug('Auth User lookup by USER NAME %s', self.username)
316 317 dbuser = login_container_auth(self.username)
317 318 if dbuser is not None:
318 319 for k, v in dbuser.get_dict().items():
319 320 setattr(self, k, v)
320 321 self.set_authenticated()
321 322 is_user_loaded = True
322 323
323 324 if not is_user_loaded:
324 325 # if we cannot authenticate user try anonymous
325 326 if self.anonymous_user.active is True:
326 327 user_model.fill_data(self,user_id=self.anonymous_user.user_id)
327 328 # then we set this user is logged in
328 329 self.is_authenticated = True
329 330 else:
330 331 self.user_id = None
331 332 self.username = None
332 333 self.is_authenticated = False
333 334
334 335 if not self.username:
335 336 self.username = 'None'
336 337
337 338 log.debug('Auth User is now %s', self)
338 339 user_model.fill_perms(self)
339 340
340 341 @property
341 342 def is_admin(self):
342 343 return self.admin
343 344
344 345 @property
345 346 def full_contact(self):
346 347 return '%s %s <%s>' % (self.name, self.lastname, self.email)
347 348
348 349 def __repr__(self):
349 350 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
350 351 self.is_authenticated)
351 352
352 353 def set_authenticated(self, authenticated=True):
353 354 if self.user_id != self.anonymous_user.user_id:
354 355 self.is_authenticated = authenticated
355 356
356 357
357 358 def set_available_permissions(config):
358 359 """
359 360 This function will propagate pylons globals with all available defined
360 361 permission given in db. We don't want to check each time from db for new
361 362 permissions since adding a new permission also requires application restart
362 363 ie. to decorate new views with the newly created permission
363 364
364 365 :param config: current pylons config instance
365 366
366 367 """
367 368 log.info('getting information about all available permissions')
368 369 try:
369 370 sa = meta.Session()
370 371 all_perms = sa.query(Permission).all()
371 372 except:
372 373 pass
373 374 finally:
374 375 meta.Session.remove()
375 376
376 377 config['available_permissions'] = [x.permission_name for x in all_perms]
377 378
378 379
379 380 #==============================================================================
380 381 # CHECK DECORATORS
381 382 #==============================================================================
382 383 class LoginRequired(object):
383 384 """
384 385 Must be logged in to execute this function else
385 386 redirect to login page
386 387
387 388 :param api_access: if enabled this checks only for valid auth token
388 389 and grants access based on valid token
389 390 """
390 391
391 392 def __init__(self, api_access=False):
392 393 self.api_access = api_access
393 394
394 395 def __call__(self, func):
395 396 return decorator(self.__wrapper, func)
396 397
397 398 def __wrapper(self, func, *fargs, **fkwargs):
398 399 cls = fargs[0]
399 400 user = cls.rhodecode_user
400 401
401 402 api_access_ok = False
402 403 if self.api_access:
403 404 log.debug('Checking API KEY access for %s', cls)
404 405 if user.api_key == request.GET.get('api_key'):
405 406 api_access_ok = True
406 407 else:
407 408 log.debug("API KEY token not valid")
408 409
409 410 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
410 411 if user.is_authenticated or api_access_ok:
411 412 log.debug('user %s is authenticated', user.username)
412 413 return func(*fargs, **fkwargs)
413 414 else:
414 415 log.warn('user %s NOT authenticated', user.username)
415 416 p = url.current()
416 417
417 418 log.debug('redirecting to login page with %s', p)
418 419 return redirect(url('login_home', came_from=p))
419 420
420 421
421 422 class NotAnonymous(object):
422 423 """Must be logged in to execute this function else
423 424 redirect to login page"""
424 425
425 426 def __call__(self, func):
426 427 return decorator(self.__wrapper, func)
427 428
428 429 def __wrapper(self, func, *fargs, **fkwargs):
429 430 cls = fargs[0]
430 431 self.user = cls.rhodecode_user
431 432
432 433 log.debug('Checking if user is not anonymous @%s', cls)
433 434
434 435 anonymous = self.user.username == 'default'
435 436
436 437 if anonymous:
437 438 p = url.current()
438 439
439 440 import rhodecode.lib.helpers as h
440 441 h.flash(_('You need to be a registered user to '
441 442 'perform this action'),
442 443 category='warning')
443 444 return redirect(url('login_home', came_from=p))
444 445 else:
445 446 return func(*fargs, **fkwargs)
446 447
447 448
448 449 class PermsDecorator(object):
449 450 """Base class for controller decorators"""
450 451
451 452 def __init__(self, *required_perms):
452 453 available_perms = config['available_permissions']
453 454 for perm in required_perms:
454 455 if perm not in available_perms:
455 456 raise Exception("'%s' permission is not defined" % perm)
456 457 self.required_perms = set(required_perms)
457 458 self.user_perms = None
458 459
459 460 def __call__(self, func):
460 461 return decorator(self.__wrapper, func)
461 462
462 463 def __wrapper(self, func, *fargs, **fkwargs):
463 464 cls = fargs[0]
464 465 self.user = cls.rhodecode_user
465 466 self.user_perms = self.user.permissions
466 467 log.debug('checking %s permissions %s for %s %s',
467 468 self.__class__.__name__, self.required_perms, cls,
468 469 self.user)
469 470
470 471 if self.check_permissions():
471 472 log.debug('Permission granted for %s %s', cls, self.user)
472 473 return func(*fargs, **fkwargs)
473 474
474 475 else:
475 476 log.warning('Permission denied for %s %s', cls, self.user)
476 477
477 478
478 479 anonymous = self.user.username == 'default'
479 480
480 481 if anonymous:
481 482 p = url.current()
482 483
483 484 import rhodecode.lib.helpers as h
484 485 h.flash(_('You need to be a signed in to '
485 486 'view this page'),
486 487 category='warning')
487 488 return redirect(url('login_home', came_from=p))
488 489
489 490 else:
490 491 # redirect with forbidden ret code
491 492 return abort(403)
492 493
493 494 def check_permissions(self):
494 495 """Dummy function for overriding"""
495 496 raise Exception('You have to write this function in child class')
496 497
497 498
498 499 class HasPermissionAllDecorator(PermsDecorator):
499 500 """Checks for access permission for all given predicates. All of them
500 501 have to be meet in order to fulfill the request
501 502 """
502 503
503 504 def check_permissions(self):
504 505 if self.required_perms.issubset(self.user_perms.get('global')):
505 506 return True
506 507 return False
507 508
508 509
509 510 class HasPermissionAnyDecorator(PermsDecorator):
510 511 """Checks for access permission for any of given predicates. In order to
511 512 fulfill the request any of predicates must be meet
512 513 """
513 514
514 515 def check_permissions(self):
515 516 if self.required_perms.intersection(self.user_perms.get('global')):
516 517 return True
517 518 return False
518 519
519 520
520 521 class HasRepoPermissionAllDecorator(PermsDecorator):
521 522 """Checks for access permission for all given predicates for specific
522 523 repository. All of them have to be meet in order to fulfill the request
523 524 """
524 525
525 526 def check_permissions(self):
526 527 repo_name = get_repo_slug(request)
527 528 try:
528 529 user_perms = set([self.user_perms['repositories'][repo_name]])
529 530 except KeyError:
530 531 return False
531 532 if self.required_perms.issubset(user_perms):
532 533 return True
533 534 return False
534 535
535 536
536 537 class HasRepoPermissionAnyDecorator(PermsDecorator):
537 538 """Checks for access permission for any of given predicates for specific
538 539 repository. In order to fulfill the request any of predicates must be meet
539 540 """
540 541
541 542 def check_permissions(self):
542 543 repo_name = get_repo_slug(request)
543 544
544 545 try:
545 546 user_perms = set([self.user_perms['repositories'][repo_name]])
546 547 except KeyError:
547 548 return False
548 549 if self.required_perms.intersection(user_perms):
549 550 return True
550 551 return False
551 552
552 553
553 554 #==============================================================================
554 555 # CHECK FUNCTIONS
555 556 #==============================================================================
556 557 class PermsFunction(object):
557 558 """Base function for other check functions"""
558 559
559 560 def __init__(self, *perms):
560 561 available_perms = config['available_permissions']
561 562
562 563 for perm in perms:
563 564 if perm not in available_perms:
564 565 raise Exception("'%s' permission in not defined" % perm)
565 566 self.required_perms = set(perms)
566 567 self.user_perms = None
567 568 self.granted_for = ''
568 569 self.repo_name = None
569 570
570 571 def __call__(self, check_Location=''):
571 572 user = session.get('rhodecode_user', False)
572 573 if not user:
573 574 return False
574 575 self.user_perms = user.permissions
575 576 self.granted_for = user
576 577 log.debug('checking %s %s %s', self.__class__.__name__,
577 578 self.required_perms, user)
578 579
579 580 if self.check_permissions():
580 581 log.debug('Permission granted %s @ %s', self.granted_for,
581 582 check_Location or 'unspecified location')
582 583 return True
583 584
584 585 else:
585 586 log.warning('Permission denied for %s @ %s', self.granted_for,
586 587 check_Location or 'unspecified location')
587 588 return False
588 589
589 590 def check_permissions(self):
590 591 """Dummy function for overriding"""
591 592 raise Exception('You have to write this function in child class')
592 593
593 594
594 595 class HasPermissionAll(PermsFunction):
595 596 def check_permissions(self):
596 597 if self.required_perms.issubset(self.user_perms.get('global')):
597 598 return True
598 599 return False
599 600
600 601
601 602 class HasPermissionAny(PermsFunction):
602 603 def check_permissions(self):
603 604 if self.required_perms.intersection(self.user_perms.get('global')):
604 605 return True
605 606 return False
606 607
607 608
608 609 class HasRepoPermissionAll(PermsFunction):
609 610
610 611 def __call__(self, repo_name=None, check_Location=''):
611 612 self.repo_name = repo_name
612 613 return super(HasRepoPermissionAll, self).__call__(check_Location)
613 614
614 615 def check_permissions(self):
615 616 if not self.repo_name:
616 617 self.repo_name = get_repo_slug(request)
617 618
618 619 try:
619 620 self.user_perms = set([self.user_perms['reposit'
620 621 'ories'][self.repo_name]])
621 622 except KeyError:
622 623 return False
623 624 self.granted_for = self.repo_name
624 625 if self.required_perms.issubset(self.user_perms):
625 626 return True
626 627 return False
627 628
628 629
629 630 class HasRepoPermissionAny(PermsFunction):
630 631
631 632 def __call__(self, repo_name=None, check_Location=''):
632 633 self.repo_name = repo_name
633 634 return super(HasRepoPermissionAny, self).__call__(check_Location)
634 635
635 636 def check_permissions(self):
636 637 if not self.repo_name:
637 638 self.repo_name = get_repo_slug(request)
638 639
639 640 try:
640 641 self.user_perms = set([self.user_perms['reposi'
641 642 'tories'][self.repo_name]])
642 643 except KeyError:
643 644 return False
644 645 self.granted_for = self.repo_name
645 646 if self.required_perms.intersection(self.user_perms):
646 647 return True
647 648 return False
648 649
649 650
650 651 #==============================================================================
651 652 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
652 653 #==============================================================================
653 654 class HasPermissionAnyMiddleware(object):
654 655 def __init__(self, *perms):
655 656 self.required_perms = set(perms)
656 657
657 658 def __call__(self, user, repo_name):
658 659 usr = AuthUser(user.user_id)
659 660 try:
660 661 self.user_perms = set([usr.permissions['repositories'][repo_name]])
661 662 except:
662 663 self.user_perms = set()
663 664 self.granted_for = ''
664 665 self.username = user.username
665 666 self.repo_name = repo_name
666 667 return self.check_permissions()
667 668
668 669 def check_permissions(self):
669 670 log.debug('checking mercurial protocol '
670 671 'permissions %s for user:%s repository:%s', self.user_perms,
671 672 self.username, self.repo_name)
672 673 if self.required_perms.intersection(self.user_perms):
673 674 log.debug('permission granted')
674 675 return True
675 676 log.debug('permission denied')
676 677 return False
677 678
General Comments 0
You need to be logged in to leave comments. Login now