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