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