##// END OF EJS Templates
adde cleanup username flag into get_container_username function
marcink -
r3173:db0871d9 beta
parent child Browse files
Show More
@@ -1,984 +1,995 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 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import random
26 import random
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import hashlib
29 import hashlib
30
30
31 from tempfile import _RandomNameSequence
31 from tempfile import _RandomNameSequence
32 from decorator import decorator
32 from decorator import decorator
33
33
34 from pylons import config, url, request
34 from pylons import config, url, request
35 from pylons.controllers.util import abort, redirect
35 from pylons.controllers.util import abort, redirect
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 from rhodecode import __platform__, is_windows, is_unix
38 from rhodecode import __platform__, is_windows, is_unix
39 from rhodecode.model.meta import Session
39 from rhodecode.model.meta import Session
40
40
41 from rhodecode.lib.utils2 import str2bool, safe_unicode
41 from rhodecode.lib.utils2 import str2bool, safe_unicode
42 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
42 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
43 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
43 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
44 from rhodecode.lib.auth_ldap import AuthLdap
44 from rhodecode.lib.auth_ldap import AuthLdap
45
45
46 from rhodecode.model import meta
46 from rhodecode.model import meta
47 from rhodecode.model.user import UserModel
47 from rhodecode.model.user import UserModel
48 from rhodecode.model.db import Permission, RhodeCodeSetting, User, UserIpMap
48 from rhodecode.model.db import Permission, RhodeCodeSetting, User, UserIpMap
49 from rhodecode.lib.caching_query import FromCache
49 from rhodecode.lib.caching_query import FromCache
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53
53
54 class PasswordGenerator(object):
54 class PasswordGenerator(object):
55 """
55 """
56 This is a simple class for generating password from different sets of
56 This is a simple class for generating password from different sets of
57 characters
57 characters
58 usage::
58 usage::
59
59
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 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
63 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, length, type_=None):
79 def gen_password(self, length, type_=None):
80 if type_ is None:
80 if type_ is None:
81 type_ = self.ALPHABETS_FULL
81 type_ = self.ALPHABETS_FULL
82 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
82 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
83 return self.passwd
83 return self.passwd
84
84
85
85
86 class RhodeCodeCrypto(object):
86 class RhodeCodeCrypto(object):
87
87
88 @classmethod
88 @classmethod
89 def hash_string(cls, str_):
89 def hash_string(cls, str_):
90 """
90 """
91 Cryptographic function used for password hashing based on pybcrypt
91 Cryptographic function used for password hashing based on pybcrypt
92 or pycrypto in windows
92 or pycrypto in windows
93
93
94 :param password: password to hash
94 :param password: password to hash
95 """
95 """
96 if is_windows:
96 if is_windows:
97 from hashlib import sha256
97 from hashlib import sha256
98 return sha256(str_).hexdigest()
98 return sha256(str_).hexdigest()
99 elif is_unix:
99 elif is_unix:
100 import bcrypt
100 import bcrypt
101 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
101 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
102 else:
102 else:
103 raise Exception('Unknown or unsupported platform %s' \
103 raise Exception('Unknown or unsupported platform %s' \
104 % __platform__)
104 % __platform__)
105
105
106 @classmethod
106 @classmethod
107 def hash_check(cls, password, hashed):
107 def hash_check(cls, password, hashed):
108 """
108 """
109 Checks matching password with it's hashed value, runs different
109 Checks matching password with it's hashed value, runs different
110 implementation based on platform it runs on
110 implementation based on platform it runs on
111
111
112 :param password: password
112 :param password: password
113 :param hashed: password in hashed form
113 :param hashed: password in hashed form
114 """
114 """
115
115
116 if is_windows:
116 if is_windows:
117 from hashlib import sha256
117 from hashlib import sha256
118 return sha256(password).hexdigest() == hashed
118 return sha256(password).hexdigest() == hashed
119 elif is_unix:
119 elif is_unix:
120 import bcrypt
120 import bcrypt
121 return bcrypt.hashpw(password, hashed) == hashed
121 return bcrypt.hashpw(password, hashed) == hashed
122 else:
122 else:
123 raise Exception('Unknown or unsupported platform %s' \
123 raise Exception('Unknown or unsupported platform %s' \
124 % __platform__)
124 % __platform__)
125
125
126
126
127 def get_crypt_password(password):
127 def get_crypt_password(password):
128 return RhodeCodeCrypto.hash_string(password)
128 return RhodeCodeCrypto.hash_string(password)
129
129
130
130
131 def check_password(password, hashed):
131 def check_password(password, hashed):
132 return RhodeCodeCrypto.hash_check(password, hashed)
132 return RhodeCodeCrypto.hash_check(password, hashed)
133
133
134
134
135 def generate_api_key(str_, salt=None):
135 def generate_api_key(str_, salt=None):
136 """
136 """
137 Generates API KEY from given string
137 Generates API KEY from given string
138
138
139 :param str_:
139 :param str_:
140 :param salt:
140 :param salt:
141 """
141 """
142
142
143 if salt is None:
143 if salt is None:
144 salt = _RandomNameSequence().next()
144 salt = _RandomNameSequence().next()
145
145
146 return hashlib.sha1(str_ + salt).hexdigest()
146 return hashlib.sha1(str_ + salt).hexdigest()
147
147
148
148
149 def authfunc(environ, username, password):
149 def authfunc(environ, username, password):
150 """
150 """
151 Dummy authentication wrapper function used in Mercurial and Git for
151 Dummy authentication wrapper function used in Mercurial and Git for
152 access control.
152 access control.
153
153
154 :param environ: needed only for using in Basic auth
154 :param environ: needed only for using in Basic auth
155 """
155 """
156 return authenticate(username, password)
156 return authenticate(username, password)
157
157
158
158
159 def authenticate(username, password):
159 def authenticate(username, password):
160 """
160 """
161 Authentication function used for access control,
161 Authentication function used for access control,
162 firstly checks for db authentication then if ldap is enabled for ldap
162 firstly checks for db authentication then if ldap is enabled for ldap
163 authentication, also creates ldap user if not in database
163 authentication, also creates ldap user if not in database
164
164
165 :param username: username
165 :param username: username
166 :param password: password
166 :param password: password
167 """
167 """
168
168
169 user_model = UserModel()
169 user_model = UserModel()
170 user = User.get_by_username(username)
170 user = User.get_by_username(username)
171
171
172 log.debug('Authenticating user using RhodeCode account')
172 log.debug('Authenticating user using RhodeCode account')
173 if user is not None and not user.ldap_dn:
173 if user is not None and not user.ldap_dn:
174 if user.active:
174 if user.active:
175 if user.username == 'default' and user.active:
175 if user.username == 'default' and user.active:
176 log.info('user %s authenticated correctly as anonymous user' %
176 log.info('user %s authenticated correctly as anonymous user' %
177 username)
177 username)
178 return True
178 return True
179
179
180 elif user.username == username and check_password(password,
180 elif user.username == username and check_password(password,
181 user.password):
181 user.password):
182 log.info('user %s authenticated correctly' % username)
182 log.info('user %s authenticated correctly' % username)
183 return True
183 return True
184 else:
184 else:
185 log.warning('user %s tried auth but is disabled' % username)
185 log.warning('user %s tried auth but is disabled' % username)
186
186
187 else:
187 else:
188 log.debug('Regular authentication failed')
188 log.debug('Regular authentication failed')
189 user_obj = User.get_by_username(username, case_insensitive=True)
189 user_obj = User.get_by_username(username, case_insensitive=True)
190
190
191 if user_obj is not None and not user_obj.ldap_dn:
191 if user_obj is not None and not user_obj.ldap_dn:
192 log.debug('this user already exists as non ldap')
192 log.debug('this user already exists as non ldap')
193 return False
193 return False
194
194
195 ldap_settings = RhodeCodeSetting.get_ldap_settings()
195 ldap_settings = RhodeCodeSetting.get_ldap_settings()
196 #======================================================================
196 #======================================================================
197 # FALLBACK TO LDAP AUTH IF ENABLE
197 # FALLBACK TO LDAP AUTH IF ENABLE
198 #======================================================================
198 #======================================================================
199 if str2bool(ldap_settings.get('ldap_active')):
199 if str2bool(ldap_settings.get('ldap_active')):
200 log.debug("Authenticating user using ldap")
200 log.debug("Authenticating user using ldap")
201 kwargs = {
201 kwargs = {
202 'server': ldap_settings.get('ldap_host', ''),
202 'server': ldap_settings.get('ldap_host', ''),
203 'base_dn': ldap_settings.get('ldap_base_dn', ''),
203 'base_dn': ldap_settings.get('ldap_base_dn', ''),
204 'port': ldap_settings.get('ldap_port'),
204 'port': ldap_settings.get('ldap_port'),
205 'bind_dn': ldap_settings.get('ldap_dn_user'),
205 'bind_dn': ldap_settings.get('ldap_dn_user'),
206 'bind_pass': ldap_settings.get('ldap_dn_pass'),
206 'bind_pass': ldap_settings.get('ldap_dn_pass'),
207 'tls_kind': ldap_settings.get('ldap_tls_kind'),
207 'tls_kind': ldap_settings.get('ldap_tls_kind'),
208 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
208 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
209 'ldap_filter': ldap_settings.get('ldap_filter'),
209 'ldap_filter': ldap_settings.get('ldap_filter'),
210 'search_scope': ldap_settings.get('ldap_search_scope'),
210 'search_scope': ldap_settings.get('ldap_search_scope'),
211 'attr_login': ldap_settings.get('ldap_attr_login'),
211 'attr_login': ldap_settings.get('ldap_attr_login'),
212 'ldap_version': 3,
212 'ldap_version': 3,
213 }
213 }
214 log.debug('Checking for ldap authentication')
214 log.debug('Checking for ldap authentication')
215 try:
215 try:
216 aldap = AuthLdap(**kwargs)
216 aldap = AuthLdap(**kwargs)
217 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
217 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
218 password)
218 password)
219 log.debug('Got ldap DN response %s' % user_dn)
219 log.debug('Got ldap DN response %s' % user_dn)
220
220
221 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
221 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
222 .get(k), [''])[0]
222 .get(k), [''])[0]
223
223
224 user_attrs = {
224 user_attrs = {
225 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
225 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
226 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
226 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
227 'email': get_ldap_attr('ldap_attr_email'),
227 'email': get_ldap_attr('ldap_attr_email'),
228 }
228 }
229
229
230 # don't store LDAP password since we don't need it. Override
230 # don't store LDAP password since we don't need it. Override
231 # with some random generated password
231 # with some random generated password
232 _password = PasswordGenerator().gen_password(length=8)
232 _password = PasswordGenerator().gen_password(length=8)
233 # create this user on the fly if it doesn't exist in rhodecode
233 # create this user on the fly if it doesn't exist in rhodecode
234 # database
234 # database
235 if user_model.create_ldap(username, _password, user_dn,
235 if user_model.create_ldap(username, _password, user_dn,
236 user_attrs):
236 user_attrs):
237 log.info('created new ldap user %s' % username)
237 log.info('created new ldap user %s' % username)
238
238
239 Session().commit()
239 Session().commit()
240 return True
240 return True
241 except (LdapUsernameError, LdapPasswordError,):
241 except (LdapUsernameError, LdapPasswordError,):
242 pass
242 pass
243 except (Exception,):
243 except (Exception,):
244 log.error(traceback.format_exc())
244 log.error(traceback.format_exc())
245 pass
245 pass
246 return False
246 return False
247
247
248
248
249 def login_container_auth(username):
249 def login_container_auth(username):
250 user = User.get_by_username(username)
250 user = User.get_by_username(username)
251 if user is None:
251 if user is None:
252 user_attrs = {
252 user_attrs = {
253 'name': username,
253 'name': username,
254 'lastname': None,
254 'lastname': None,
255 'email': None,
255 'email': None,
256 }
256 }
257 user = UserModel().create_for_container_auth(username, user_attrs)
257 user = UserModel().create_for_container_auth(username, user_attrs)
258 if not user:
258 if not user:
259 return None
259 return None
260 log.info('User %s was created by container authentication' % username)
260 log.info('User %s was created by container authentication' % username)
261
261
262 if not user.active:
262 if not user.active:
263 return None
263 return None
264
264
265 user.update_lastlogin()
265 user.update_lastlogin()
266 Session().commit()
266 Session().commit()
267
267
268 log.debug('User %s is now logged in by container authentication',
268 log.debug('User %s is now logged in by container authentication',
269 user.username)
269 user.username)
270 return user
270 return user
271
271
272
272
273 def get_container_username(environ, config):
273 def get_container_username(environ, config, clean_username=False):
274 """
275 Get's the container_auth username (or email). It tries to get username
276 from REMOTE_USER if container_auth_enabled is enabled, if that fails
277 it tries to get username from HTTP_X_FORWARDED_USER if proxypass_auth_enabled
278 is enabled. clean_username extracts the username from this data if it's
279 having @ in it.
280
281 :param environ:
282 :param config:
283 :param clean_username:
284 """
274 username = None
285 username = None
275
286
276 if str2bool(config.get('container_auth_enabled', False)):
287 if str2bool(config.get('container_auth_enabled', False)):
277 from paste.httpheaders import REMOTE_USER
288 from paste.httpheaders import REMOTE_USER
278 username = REMOTE_USER(environ)
289 username = REMOTE_USER(environ)
279 log.debug('extracted REMOTE_USER:%s' % (username))
290 log.debug('extracted REMOTE_USER:%s' % (username))
280
291
281 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
292 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
282 username = environ.get('HTTP_X_FORWARDED_USER')
293 username = environ.get('HTTP_X_FORWARDED_USER')
283 log.debug('extracted HTTP_X_FORWARDED_USER:%s' % (username))
294 log.debug('extracted HTTP_X_FORWARDED_USER:%s' % (username))
284
295
285 if username:
296 if username and clean_username:
286 # Removing realm and domain from username
297 # Removing realm and domain from username
287 username = username.partition('@')[0]
298 username = username.partition('@')[0]
288 username = username.rpartition('\\')[2]
299 username = username.rpartition('\\')[2]
289 log.debug('Received username %s from container' % username)
300 log.debug('Received username %s from container' % username)
290
301
291 return username
302 return username
292
303
293
304
294 class CookieStoreWrapper(object):
305 class CookieStoreWrapper(object):
295
306
296 def __init__(self, cookie_store):
307 def __init__(self, cookie_store):
297 self.cookie_store = cookie_store
308 self.cookie_store = cookie_store
298
309
299 def __repr__(self):
310 def __repr__(self):
300 return 'CookieStore<%s>' % (self.cookie_store)
311 return 'CookieStore<%s>' % (self.cookie_store)
301
312
302 def get(self, key, other=None):
313 def get(self, key, other=None):
303 if isinstance(self.cookie_store, dict):
314 if isinstance(self.cookie_store, dict):
304 return self.cookie_store.get(key, other)
315 return self.cookie_store.get(key, other)
305 elif isinstance(self.cookie_store, AuthUser):
316 elif isinstance(self.cookie_store, AuthUser):
306 return self.cookie_store.__dict__.get(key, other)
317 return self.cookie_store.__dict__.get(key, other)
307
318
308
319
309 class AuthUser(object):
320 class AuthUser(object):
310 """
321 """
311 A simple object that handles all attributes of user in RhodeCode
322 A simple object that handles all attributes of user in RhodeCode
312
323
313 It does lookup based on API key,given user, or user present in session
324 It does lookup based on API key,given user, or user present in session
314 Then it fills all required information for such user. It also checks if
325 Then it fills all required information for such user. It also checks if
315 anonymous access is enabled and if so, it returns default user as logged
326 anonymous access is enabled and if so, it returns default user as logged
316 in
327 in
317 """
328 """
318
329
319 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
330 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
320
331
321 self.user_id = user_id
332 self.user_id = user_id
322 self.api_key = None
333 self.api_key = None
323 self.username = username
334 self.username = username
324 self.ip_addr = ip_addr
335 self.ip_addr = ip_addr
325
336
326 self.name = ''
337 self.name = ''
327 self.lastname = ''
338 self.lastname = ''
328 self.email = ''
339 self.email = ''
329 self.is_authenticated = False
340 self.is_authenticated = False
330 self.admin = False
341 self.admin = False
331 self.inherit_default_permissions = False
342 self.inherit_default_permissions = False
332 self.permissions = {}
343 self.permissions = {}
333 self._api_key = api_key
344 self._api_key = api_key
334 self.propagate_data()
345 self.propagate_data()
335 self._instance = None
346 self._instance = None
336
347
337 def propagate_data(self):
348 def propagate_data(self):
338 user_model = UserModel()
349 user_model = UserModel()
339 self.anonymous_user = User.get_by_username('default', cache=True)
350 self.anonymous_user = User.get_by_username('default', cache=True)
340 is_user_loaded = False
351 is_user_loaded = False
341
352
342 # try go get user by api key
353 # try go get user by api key
343 if self._api_key and self._api_key != self.anonymous_user.api_key:
354 if self._api_key and self._api_key != self.anonymous_user.api_key:
344 log.debug('Auth User lookup by API KEY %s' % self._api_key)
355 log.debug('Auth User lookup by API KEY %s' % self._api_key)
345 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
356 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
346 # lookup by userid
357 # lookup by userid
347 elif (self.user_id is not None and
358 elif (self.user_id is not None and
348 self.user_id != self.anonymous_user.user_id):
359 self.user_id != self.anonymous_user.user_id):
349 log.debug('Auth User lookup by USER ID %s' % self.user_id)
360 log.debug('Auth User lookup by USER ID %s' % self.user_id)
350 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
361 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
351 # lookup by username
362 # lookup by username
352 elif self.username and \
363 elif self.username and \
353 str2bool(config.get('container_auth_enabled', False)):
364 str2bool(config.get('container_auth_enabled', False)):
354
365
355 log.debug('Auth User lookup by USER NAME %s' % self.username)
366 log.debug('Auth User lookup by USER NAME %s' % self.username)
356 dbuser = login_container_auth(self.username)
367 dbuser = login_container_auth(self.username)
357 if dbuser is not None:
368 if dbuser is not None:
358 log.debug('filling all attributes to object')
369 log.debug('filling all attributes to object')
359 for k, v in dbuser.get_dict().items():
370 for k, v in dbuser.get_dict().items():
360 setattr(self, k, v)
371 setattr(self, k, v)
361 self.set_authenticated()
372 self.set_authenticated()
362 is_user_loaded = True
373 is_user_loaded = True
363 else:
374 else:
364 log.debug('No data in %s that could been used to log in' % self)
375 log.debug('No data in %s that could been used to log in' % self)
365
376
366 if not is_user_loaded:
377 if not is_user_loaded:
367 # if we cannot authenticate user try anonymous
378 # if we cannot authenticate user try anonymous
368 if self.anonymous_user.active is True:
379 if self.anonymous_user.active is True:
369 user_model.fill_data(self, user_id=self.anonymous_user.user_id)
380 user_model.fill_data(self, user_id=self.anonymous_user.user_id)
370 # then we set this user is logged in
381 # then we set this user is logged in
371 self.is_authenticated = True
382 self.is_authenticated = True
372 else:
383 else:
373 self.user_id = None
384 self.user_id = None
374 self.username = None
385 self.username = None
375 self.is_authenticated = False
386 self.is_authenticated = False
376
387
377 if not self.username:
388 if not self.username:
378 self.username = 'None'
389 self.username = 'None'
379
390
380 log.debug('Auth User is now %s' % self)
391 log.debug('Auth User is now %s' % self)
381 user_model.fill_perms(self)
392 user_model.fill_perms(self)
382
393
383 @property
394 @property
384 def is_admin(self):
395 def is_admin(self):
385 return self.admin
396 return self.admin
386
397
387 @property
398 @property
388 def ip_allowed(self):
399 def ip_allowed(self):
389 """
400 """
390 Checks if ip_addr used in constructor is allowed from defined list of
401 Checks if ip_addr used in constructor is allowed from defined list of
391 allowed ip_addresses for user
402 allowed ip_addresses for user
392
403
393 :returns: boolean, True if ip is in allowed ip range
404 :returns: boolean, True if ip is in allowed ip range
394 """
405 """
395 #check IP
406 #check IP
396 allowed_ips = AuthUser.get_allowed_ips(self.user_id, cache=True)
407 allowed_ips = AuthUser.get_allowed_ips(self.user_id, cache=True)
397 if check_ip_access(source_ip=self.ip_addr, allowed_ips=allowed_ips):
408 if check_ip_access(source_ip=self.ip_addr, allowed_ips=allowed_ips):
398 log.debug('IP:%s is in range of %s' % (self.ip_addr, allowed_ips))
409 log.debug('IP:%s is in range of %s' % (self.ip_addr, allowed_ips))
399 return True
410 return True
400 else:
411 else:
401 log.info('Access for IP:%s forbidden, '
412 log.info('Access for IP:%s forbidden, '
402 'not in %s' % (self.ip_addr, allowed_ips))
413 'not in %s' % (self.ip_addr, allowed_ips))
403 return False
414 return False
404
415
405 def __repr__(self):
416 def __repr__(self):
406 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
417 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
407 self.is_authenticated)
418 self.is_authenticated)
408
419
409 def set_authenticated(self, authenticated=True):
420 def set_authenticated(self, authenticated=True):
410 if self.user_id != self.anonymous_user.user_id:
421 if self.user_id != self.anonymous_user.user_id:
411 self.is_authenticated = authenticated
422 self.is_authenticated = authenticated
412
423
413 def get_cookie_store(self):
424 def get_cookie_store(self):
414 return {'username': self.username,
425 return {'username': self.username,
415 'user_id': self.user_id,
426 'user_id': self.user_id,
416 'is_authenticated': self.is_authenticated}
427 'is_authenticated': self.is_authenticated}
417
428
418 @classmethod
429 @classmethod
419 def from_cookie_store(cls, cookie_store):
430 def from_cookie_store(cls, cookie_store):
420 """
431 """
421 Creates AuthUser from a cookie store
432 Creates AuthUser from a cookie store
422
433
423 :param cls:
434 :param cls:
424 :param cookie_store:
435 :param cookie_store:
425 """
436 """
426 user_id = cookie_store.get('user_id')
437 user_id = cookie_store.get('user_id')
427 username = cookie_store.get('username')
438 username = cookie_store.get('username')
428 api_key = cookie_store.get('api_key')
439 api_key = cookie_store.get('api_key')
429 return AuthUser(user_id, api_key, username)
440 return AuthUser(user_id, api_key, username)
430
441
431 @classmethod
442 @classmethod
432 def get_allowed_ips(cls, user_id, cache=False):
443 def get_allowed_ips(cls, user_id, cache=False):
433 _set = set()
444 _set = set()
434 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
445 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
435 if cache:
446 if cache:
436 user_ips = user_ips.options(FromCache("sql_cache_short",
447 user_ips = user_ips.options(FromCache("sql_cache_short",
437 "get_user_ips_%s" % user_id))
448 "get_user_ips_%s" % user_id))
438 for ip in user_ips:
449 for ip in user_ips:
439 _set.add(ip.ip_addr)
450 _set.add(ip.ip_addr)
440 return _set or set(['0.0.0.0/0'])
451 return _set or set(['0.0.0.0/0'])
441
452
442
453
443 def set_available_permissions(config):
454 def set_available_permissions(config):
444 """
455 """
445 This function will propagate pylons globals with all available defined
456 This function will propagate pylons globals with all available defined
446 permission given in db. We don't want to check each time from db for new
457 permission given in db. We don't want to check each time from db for new
447 permissions since adding a new permission also requires application restart
458 permissions since adding a new permission also requires application restart
448 ie. to decorate new views with the newly created permission
459 ie. to decorate new views with the newly created permission
449
460
450 :param config: current pylons config instance
461 :param config: current pylons config instance
451
462
452 """
463 """
453 log.info('getting information about all available permissions')
464 log.info('getting information about all available permissions')
454 try:
465 try:
455 sa = meta.Session
466 sa = meta.Session
456 all_perms = sa.query(Permission).all()
467 all_perms = sa.query(Permission).all()
457 except Exception:
468 except Exception:
458 pass
469 pass
459 finally:
470 finally:
460 meta.Session.remove()
471 meta.Session.remove()
461
472
462 config['available_permissions'] = [x.permission_name for x in all_perms]
473 config['available_permissions'] = [x.permission_name for x in all_perms]
463
474
464
475
465 #==============================================================================
476 #==============================================================================
466 # CHECK DECORATORS
477 # CHECK DECORATORS
467 #==============================================================================
478 #==============================================================================
468 class LoginRequired(object):
479 class LoginRequired(object):
469 """
480 """
470 Must be logged in to execute this function else
481 Must be logged in to execute this function else
471 redirect to login page
482 redirect to login page
472
483
473 :param api_access: if enabled this checks only for valid auth token
484 :param api_access: if enabled this checks only for valid auth token
474 and grants access based on valid token
485 and grants access based on valid token
475 """
486 """
476
487
477 def __init__(self, api_access=False):
488 def __init__(self, api_access=False):
478 self.api_access = api_access
489 self.api_access = api_access
479
490
480 def __call__(self, func):
491 def __call__(self, func):
481 return decorator(self.__wrapper, func)
492 return decorator(self.__wrapper, func)
482
493
483 def __wrapper(self, func, *fargs, **fkwargs):
494 def __wrapper(self, func, *fargs, **fkwargs):
484 cls = fargs[0]
495 cls = fargs[0]
485 user = cls.rhodecode_user
496 user = cls.rhodecode_user
486 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
497 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
487
498
488 #check IP
499 #check IP
489 ip_access_ok = True
500 ip_access_ok = True
490 if not user.ip_allowed:
501 if not user.ip_allowed:
491 from rhodecode.lib import helpers as h
502 from rhodecode.lib import helpers as h
492 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr))),
503 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr))),
493 category='warning')
504 category='warning')
494 ip_access_ok = False
505 ip_access_ok = False
495
506
496 api_access_ok = False
507 api_access_ok = False
497 if self.api_access:
508 if self.api_access:
498 log.debug('Checking API KEY access for %s' % cls)
509 log.debug('Checking API KEY access for %s' % cls)
499 if user.api_key == request.GET.get('api_key'):
510 if user.api_key == request.GET.get('api_key'):
500 api_access_ok = True
511 api_access_ok = True
501 else:
512 else:
502 log.debug("API KEY token not valid")
513 log.debug("API KEY token not valid")
503
514
504 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
515 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
505 if (user.is_authenticated or api_access_ok) and ip_access_ok:
516 if (user.is_authenticated or api_access_ok) and ip_access_ok:
506 reason = 'RegularAuth' if user.is_authenticated else 'APIAuth'
517 reason = 'RegularAuth' if user.is_authenticated else 'APIAuth'
507 log.info('user %s is authenticated and granted access to %s '
518 log.info('user %s is authenticated and granted access to %s '
508 'using %s' % (user.username, loc, reason)
519 'using %s' % (user.username, loc, reason)
509 )
520 )
510 return func(*fargs, **fkwargs)
521 return func(*fargs, **fkwargs)
511 else:
522 else:
512 log.warn('user %s NOT authenticated on func: %s' % (
523 log.warn('user %s NOT authenticated on func: %s' % (
513 user, loc)
524 user, loc)
514 )
525 )
515 p = url.current()
526 p = url.current()
516
527
517 log.debug('redirecting to login page with %s' % p)
528 log.debug('redirecting to login page with %s' % p)
518 return redirect(url('login_home', came_from=p))
529 return redirect(url('login_home', came_from=p))
519
530
520
531
521 class NotAnonymous(object):
532 class NotAnonymous(object):
522 """
533 """
523 Must be logged in to execute this function else
534 Must be logged in to execute this function else
524 redirect to login page"""
535 redirect to login page"""
525
536
526 def __call__(self, func):
537 def __call__(self, func):
527 return decorator(self.__wrapper, func)
538 return decorator(self.__wrapper, func)
528
539
529 def __wrapper(self, func, *fargs, **fkwargs):
540 def __wrapper(self, func, *fargs, **fkwargs):
530 cls = fargs[0]
541 cls = fargs[0]
531 self.user = cls.rhodecode_user
542 self.user = cls.rhodecode_user
532
543
533 log.debug('Checking if user is not anonymous @%s' % cls)
544 log.debug('Checking if user is not anonymous @%s' % cls)
534
545
535 anonymous = self.user.username == 'default'
546 anonymous = self.user.username == 'default'
536
547
537 if anonymous:
548 if anonymous:
538 p = url.current()
549 p = url.current()
539
550
540 import rhodecode.lib.helpers as h
551 import rhodecode.lib.helpers as h
541 h.flash(_('You need to be a registered user to '
552 h.flash(_('You need to be a registered user to '
542 'perform this action'),
553 'perform this action'),
543 category='warning')
554 category='warning')
544 return redirect(url('login_home', came_from=p))
555 return redirect(url('login_home', came_from=p))
545 else:
556 else:
546 return func(*fargs, **fkwargs)
557 return func(*fargs, **fkwargs)
547
558
548
559
549 class PermsDecorator(object):
560 class PermsDecorator(object):
550 """Base class for controller decorators"""
561 """Base class for controller decorators"""
551
562
552 def __init__(self, *required_perms):
563 def __init__(self, *required_perms):
553 available_perms = config['available_permissions']
564 available_perms = config['available_permissions']
554 for perm in required_perms:
565 for perm in required_perms:
555 if perm not in available_perms:
566 if perm not in available_perms:
556 raise Exception("'%s' permission is not defined" % perm)
567 raise Exception("'%s' permission is not defined" % perm)
557 self.required_perms = set(required_perms)
568 self.required_perms = set(required_perms)
558 self.user_perms = None
569 self.user_perms = None
559
570
560 def __call__(self, func):
571 def __call__(self, func):
561 return decorator(self.__wrapper, func)
572 return decorator(self.__wrapper, func)
562
573
563 def __wrapper(self, func, *fargs, **fkwargs):
574 def __wrapper(self, func, *fargs, **fkwargs):
564 cls = fargs[0]
575 cls = fargs[0]
565 self.user = cls.rhodecode_user
576 self.user = cls.rhodecode_user
566 self.user_perms = self.user.permissions
577 self.user_perms = self.user.permissions
567 log.debug('checking %s permissions %s for %s %s',
578 log.debug('checking %s permissions %s for %s %s',
568 self.__class__.__name__, self.required_perms, cls, self.user)
579 self.__class__.__name__, self.required_perms, cls, self.user)
569
580
570 if self.check_permissions():
581 if self.check_permissions():
571 log.debug('Permission granted for %s %s' % (cls, self.user))
582 log.debug('Permission granted for %s %s' % (cls, self.user))
572 return func(*fargs, **fkwargs)
583 return func(*fargs, **fkwargs)
573
584
574 else:
585 else:
575 log.debug('Permission denied for %s %s' % (cls, self.user))
586 log.debug('Permission denied for %s %s' % (cls, self.user))
576 anonymous = self.user.username == 'default'
587 anonymous = self.user.username == 'default'
577
588
578 if anonymous:
589 if anonymous:
579 p = url.current()
590 p = url.current()
580
591
581 import rhodecode.lib.helpers as h
592 import rhodecode.lib.helpers as h
582 h.flash(_('You need to be a signed in to '
593 h.flash(_('You need to be a signed in to '
583 'view this page'),
594 'view this page'),
584 category='warning')
595 category='warning')
585 return redirect(url('login_home', came_from=p))
596 return redirect(url('login_home', came_from=p))
586
597
587 else:
598 else:
588 # redirect with forbidden ret code
599 # redirect with forbidden ret code
589 return abort(403)
600 return abort(403)
590
601
591 def check_permissions(self):
602 def check_permissions(self):
592 """Dummy function for overriding"""
603 """Dummy function for overriding"""
593 raise Exception('You have to write this function in child class')
604 raise Exception('You have to write this function in child class')
594
605
595
606
596 class HasPermissionAllDecorator(PermsDecorator):
607 class HasPermissionAllDecorator(PermsDecorator):
597 """
608 """
598 Checks for access permission for all given predicates. All of them
609 Checks for access permission for all given predicates. All of them
599 have to be meet in order to fulfill the request
610 have to be meet in order to fulfill the request
600 """
611 """
601
612
602 def check_permissions(self):
613 def check_permissions(self):
603 if self.required_perms.issubset(self.user_perms.get('global')):
614 if self.required_perms.issubset(self.user_perms.get('global')):
604 return True
615 return True
605 return False
616 return False
606
617
607
618
608 class HasPermissionAnyDecorator(PermsDecorator):
619 class HasPermissionAnyDecorator(PermsDecorator):
609 """
620 """
610 Checks for access permission for any of given predicates. In order to
621 Checks for access permission for any of given predicates. In order to
611 fulfill the request any of predicates must be meet
622 fulfill the request any of predicates must be meet
612 """
623 """
613
624
614 def check_permissions(self):
625 def check_permissions(self):
615 if self.required_perms.intersection(self.user_perms.get('global')):
626 if self.required_perms.intersection(self.user_perms.get('global')):
616 return True
627 return True
617 return False
628 return False
618
629
619
630
620 class HasRepoPermissionAllDecorator(PermsDecorator):
631 class HasRepoPermissionAllDecorator(PermsDecorator):
621 """
632 """
622 Checks for access permission for all given predicates for specific
633 Checks for access permission for all given predicates for specific
623 repository. All of them have to be meet in order to fulfill the request
634 repository. All of them have to be meet in order to fulfill the request
624 """
635 """
625
636
626 def check_permissions(self):
637 def check_permissions(self):
627 repo_name = get_repo_slug(request)
638 repo_name = get_repo_slug(request)
628 try:
639 try:
629 user_perms = set([self.user_perms['repositories'][repo_name]])
640 user_perms = set([self.user_perms['repositories'][repo_name]])
630 except KeyError:
641 except KeyError:
631 return False
642 return False
632 if self.required_perms.issubset(user_perms):
643 if self.required_perms.issubset(user_perms):
633 return True
644 return True
634 return False
645 return False
635
646
636
647
637 class HasRepoPermissionAnyDecorator(PermsDecorator):
648 class HasRepoPermissionAnyDecorator(PermsDecorator):
638 """
649 """
639 Checks for access permission for any of given predicates for specific
650 Checks for access permission for any of given predicates for specific
640 repository. In order to fulfill the request any of predicates must be meet
651 repository. In order to fulfill the request any of predicates must be meet
641 """
652 """
642
653
643 def check_permissions(self):
654 def check_permissions(self):
644 repo_name = get_repo_slug(request)
655 repo_name = get_repo_slug(request)
645
656
646 try:
657 try:
647 user_perms = set([self.user_perms['repositories'][repo_name]])
658 user_perms = set([self.user_perms['repositories'][repo_name]])
648 except KeyError:
659 except KeyError:
649 return False
660 return False
650
661
651 if self.required_perms.intersection(user_perms):
662 if self.required_perms.intersection(user_perms):
652 return True
663 return True
653 return False
664 return False
654
665
655
666
656 class HasReposGroupPermissionAllDecorator(PermsDecorator):
667 class HasReposGroupPermissionAllDecorator(PermsDecorator):
657 """
668 """
658 Checks for access permission for all given predicates for specific
669 Checks for access permission for all given predicates for specific
659 repository. All of them have to be meet in order to fulfill the request
670 repository. All of them have to be meet in order to fulfill the request
660 """
671 """
661
672
662 def check_permissions(self):
673 def check_permissions(self):
663 group_name = get_repos_group_slug(request)
674 group_name = get_repos_group_slug(request)
664 try:
675 try:
665 user_perms = set([self.user_perms['repositories_groups'][group_name]])
676 user_perms = set([self.user_perms['repositories_groups'][group_name]])
666 except KeyError:
677 except KeyError:
667 return False
678 return False
668 if self.required_perms.issubset(user_perms):
679 if self.required_perms.issubset(user_perms):
669 return True
680 return True
670 return False
681 return False
671
682
672
683
673 class HasReposGroupPermissionAnyDecorator(PermsDecorator):
684 class HasReposGroupPermissionAnyDecorator(PermsDecorator):
674 """
685 """
675 Checks for access permission for any of given predicates for specific
686 Checks for access permission for any of given predicates for specific
676 repository. In order to fulfill the request any of predicates must be meet
687 repository. In order to fulfill the request any of predicates must be meet
677 """
688 """
678
689
679 def check_permissions(self):
690 def check_permissions(self):
680 group_name = get_repos_group_slug(request)
691 group_name = get_repos_group_slug(request)
681
692
682 try:
693 try:
683 user_perms = set([self.user_perms['repositories_groups'][group_name]])
694 user_perms = set([self.user_perms['repositories_groups'][group_name]])
684 except KeyError:
695 except KeyError:
685 return False
696 return False
686 if self.required_perms.intersection(user_perms):
697 if self.required_perms.intersection(user_perms):
687 return True
698 return True
688 return False
699 return False
689
700
690
701
691 #==============================================================================
702 #==============================================================================
692 # CHECK FUNCTIONS
703 # CHECK FUNCTIONS
693 #==============================================================================
704 #==============================================================================
694 class PermsFunction(object):
705 class PermsFunction(object):
695 """Base function for other check functions"""
706 """Base function for other check functions"""
696
707
697 def __init__(self, *perms):
708 def __init__(self, *perms):
698 available_perms = config['available_permissions']
709 available_perms = config['available_permissions']
699
710
700 for perm in perms:
711 for perm in perms:
701 if perm not in available_perms:
712 if perm not in available_perms:
702 raise Exception("'%s' permission is not defined" % perm)
713 raise Exception("'%s' permission is not defined" % perm)
703 self.required_perms = set(perms)
714 self.required_perms = set(perms)
704 self.user_perms = None
715 self.user_perms = None
705 self.repo_name = None
716 self.repo_name = None
706 self.group_name = None
717 self.group_name = None
707
718
708 def __call__(self, check_Location=''):
719 def __call__(self, check_Location=''):
709 user = request.user
720 user = request.user
710 cls_name = self.__class__.__name__
721 cls_name = self.__class__.__name__
711 check_scope = {
722 check_scope = {
712 'HasPermissionAll': '',
723 'HasPermissionAll': '',
713 'HasPermissionAny': '',
724 'HasPermissionAny': '',
714 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
725 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
715 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
726 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
716 'HasReposGroupPermissionAll': 'group:%s' % self.group_name,
727 'HasReposGroupPermissionAll': 'group:%s' % self.group_name,
717 'HasReposGroupPermissionAny': 'group:%s' % self.group_name,
728 'HasReposGroupPermissionAny': 'group:%s' % self.group_name,
718 }.get(cls_name, '?')
729 }.get(cls_name, '?')
719 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
730 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
720 self.required_perms, user, check_scope,
731 self.required_perms, user, check_scope,
721 check_Location or 'unspecified location')
732 check_Location or 'unspecified location')
722 if not user:
733 if not user:
723 log.debug('Empty request user')
734 log.debug('Empty request user')
724 return False
735 return False
725 self.user_perms = user.permissions
736 self.user_perms = user.permissions
726 if self.check_permissions():
737 if self.check_permissions():
727 log.debug('Permission to %s granted for user: %s @ %s', self.repo_name, user,
738 log.debug('Permission to %s granted for user: %s @ %s', self.repo_name, user,
728 check_Location or 'unspecified location')
739 check_Location or 'unspecified location')
729 return True
740 return True
730
741
731 else:
742 else:
732 log.debug('Permission to %s denied for user: %s @ %s', self.repo_name, user,
743 log.debug('Permission to %s denied for user: %s @ %s', self.repo_name, user,
733 check_Location or 'unspecified location')
744 check_Location or 'unspecified location')
734 return False
745 return False
735
746
736 def check_permissions(self):
747 def check_permissions(self):
737 """Dummy function for overriding"""
748 """Dummy function for overriding"""
738 raise Exception('You have to write this function in child class')
749 raise Exception('You have to write this function in child class')
739
750
740
751
741 class HasPermissionAll(PermsFunction):
752 class HasPermissionAll(PermsFunction):
742 def check_permissions(self):
753 def check_permissions(self):
743 if self.required_perms.issubset(self.user_perms.get('global')):
754 if self.required_perms.issubset(self.user_perms.get('global')):
744 return True
755 return True
745 return False
756 return False
746
757
747
758
748 class HasPermissionAny(PermsFunction):
759 class HasPermissionAny(PermsFunction):
749 def check_permissions(self):
760 def check_permissions(self):
750 if self.required_perms.intersection(self.user_perms.get('global')):
761 if self.required_perms.intersection(self.user_perms.get('global')):
751 return True
762 return True
752 return False
763 return False
753
764
754
765
755 class HasRepoPermissionAll(PermsFunction):
766 class HasRepoPermissionAll(PermsFunction):
756 def __call__(self, repo_name=None, check_Location=''):
767 def __call__(self, repo_name=None, check_Location=''):
757 self.repo_name = repo_name
768 self.repo_name = repo_name
758 return super(HasRepoPermissionAll, self).__call__(check_Location)
769 return super(HasRepoPermissionAll, self).__call__(check_Location)
759
770
760 def check_permissions(self):
771 def check_permissions(self):
761 if not self.repo_name:
772 if not self.repo_name:
762 self.repo_name = get_repo_slug(request)
773 self.repo_name = get_repo_slug(request)
763
774
764 try:
775 try:
765 self._user_perms = set(
776 self._user_perms = set(
766 [self.user_perms['repositories'][self.repo_name]]
777 [self.user_perms['repositories'][self.repo_name]]
767 )
778 )
768 except KeyError:
779 except KeyError:
769 return False
780 return False
770 if self.required_perms.issubset(self._user_perms):
781 if self.required_perms.issubset(self._user_perms):
771 return True
782 return True
772 return False
783 return False
773
784
774
785
775 class HasRepoPermissionAny(PermsFunction):
786 class HasRepoPermissionAny(PermsFunction):
776 def __call__(self, repo_name=None, check_Location=''):
787 def __call__(self, repo_name=None, check_Location=''):
777 self.repo_name = repo_name
788 self.repo_name = repo_name
778 return super(HasRepoPermissionAny, self).__call__(check_Location)
789 return super(HasRepoPermissionAny, self).__call__(check_Location)
779
790
780 def check_permissions(self):
791 def check_permissions(self):
781 if not self.repo_name:
792 if not self.repo_name:
782 self.repo_name = get_repo_slug(request)
793 self.repo_name = get_repo_slug(request)
783
794
784 try:
795 try:
785 self._user_perms = set(
796 self._user_perms = set(
786 [self.user_perms['repositories'][self.repo_name]]
797 [self.user_perms['repositories'][self.repo_name]]
787 )
798 )
788 except KeyError:
799 except KeyError:
789 return False
800 return False
790 if self.required_perms.intersection(self._user_perms):
801 if self.required_perms.intersection(self._user_perms):
791 return True
802 return True
792 return False
803 return False
793
804
794
805
795 class HasReposGroupPermissionAny(PermsFunction):
806 class HasReposGroupPermissionAny(PermsFunction):
796 def __call__(self, group_name=None, check_Location=''):
807 def __call__(self, group_name=None, check_Location=''):
797 self.group_name = group_name
808 self.group_name = group_name
798 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
809 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
799
810
800 def check_permissions(self):
811 def check_permissions(self):
801 try:
812 try:
802 self._user_perms = set(
813 self._user_perms = set(
803 [self.user_perms['repositories_groups'][self.group_name]]
814 [self.user_perms['repositories_groups'][self.group_name]]
804 )
815 )
805 except KeyError:
816 except KeyError:
806 return False
817 return False
807 if self.required_perms.intersection(self._user_perms):
818 if self.required_perms.intersection(self._user_perms):
808 return True
819 return True
809 return False
820 return False
810
821
811
822
812 class HasReposGroupPermissionAll(PermsFunction):
823 class HasReposGroupPermissionAll(PermsFunction):
813 def __call__(self, group_name=None, check_Location=''):
824 def __call__(self, group_name=None, check_Location=''):
814 self.group_name = group_name
825 self.group_name = group_name
815 return super(HasReposGroupPermissionAll, self).__call__(check_Location)
826 return super(HasReposGroupPermissionAll, self).__call__(check_Location)
816
827
817 def check_permissions(self):
828 def check_permissions(self):
818 try:
829 try:
819 self._user_perms = set(
830 self._user_perms = set(
820 [self.user_perms['repositories_groups'][self.group_name]]
831 [self.user_perms['repositories_groups'][self.group_name]]
821 )
832 )
822 except KeyError:
833 except KeyError:
823 return False
834 return False
824 if self.required_perms.issubset(self._user_perms):
835 if self.required_perms.issubset(self._user_perms):
825 return True
836 return True
826 return False
837 return False
827
838
828
839
829 #==============================================================================
840 #==============================================================================
830 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
841 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
831 #==============================================================================
842 #==============================================================================
832 class HasPermissionAnyMiddleware(object):
843 class HasPermissionAnyMiddleware(object):
833 def __init__(self, *perms):
844 def __init__(self, *perms):
834 self.required_perms = set(perms)
845 self.required_perms = set(perms)
835
846
836 def __call__(self, user, repo_name):
847 def __call__(self, user, repo_name):
837 # repo_name MUST be unicode, since we handle keys in permission
848 # repo_name MUST be unicode, since we handle keys in permission
838 # dict by unicode
849 # dict by unicode
839 repo_name = safe_unicode(repo_name)
850 repo_name = safe_unicode(repo_name)
840 usr = AuthUser(user.user_id)
851 usr = AuthUser(user.user_id)
841 try:
852 try:
842 self.user_perms = set([usr.permissions['repositories'][repo_name]])
853 self.user_perms = set([usr.permissions['repositories'][repo_name]])
843 except Exception:
854 except Exception:
844 log.error('Exception while accessing permissions %s' %
855 log.error('Exception while accessing permissions %s' %
845 traceback.format_exc())
856 traceback.format_exc())
846 self.user_perms = set()
857 self.user_perms = set()
847 self.username = user.username
858 self.username = user.username
848 self.repo_name = repo_name
859 self.repo_name = repo_name
849 return self.check_permissions()
860 return self.check_permissions()
850
861
851 def check_permissions(self):
862 def check_permissions(self):
852 log.debug('checking VCS protocol '
863 log.debug('checking VCS protocol '
853 'permissions %s for user:%s repository:%s', self.user_perms,
864 'permissions %s for user:%s repository:%s', self.user_perms,
854 self.username, self.repo_name)
865 self.username, self.repo_name)
855 if self.required_perms.intersection(self.user_perms):
866 if self.required_perms.intersection(self.user_perms):
856 log.debug('permission granted for user:%s on repo:%s' % (
867 log.debug('permission granted for user:%s on repo:%s' % (
857 self.username, self.repo_name
868 self.username, self.repo_name
858 )
869 )
859 )
870 )
860 return True
871 return True
861 log.debug('permission denied for user:%s on repo:%s' % (
872 log.debug('permission denied for user:%s on repo:%s' % (
862 self.username, self.repo_name
873 self.username, self.repo_name
863 )
874 )
864 )
875 )
865 return False
876 return False
866
877
867
878
868 #==============================================================================
879 #==============================================================================
869 # SPECIAL VERSION TO HANDLE API AUTH
880 # SPECIAL VERSION TO HANDLE API AUTH
870 #==============================================================================
881 #==============================================================================
871 class _BaseApiPerm(object):
882 class _BaseApiPerm(object):
872 def __init__(self, *perms):
883 def __init__(self, *perms):
873 self.required_perms = set(perms)
884 self.required_perms = set(perms)
874
885
875 def __call__(self, check_location='unspecified', user=None, repo_name=None):
886 def __call__(self, check_location='unspecified', user=None, repo_name=None):
876 cls_name = self.__class__.__name__
887 cls_name = self.__class__.__name__
877 check_scope = 'user:%s, repo:%s' % (user, repo_name)
888 check_scope = 'user:%s, repo:%s' % (user, repo_name)
878 log.debug('checking cls:%s %s %s @ %s', cls_name,
889 log.debug('checking cls:%s %s %s @ %s', cls_name,
879 self.required_perms, check_scope, check_location)
890 self.required_perms, check_scope, check_location)
880 if not user:
891 if not user:
881 log.debug('Empty User passed into arguments')
892 log.debug('Empty User passed into arguments')
882 return False
893 return False
883
894
884 ## process user
895 ## process user
885 if not isinstance(user, AuthUser):
896 if not isinstance(user, AuthUser):
886 user = AuthUser(user.user_id)
897 user = AuthUser(user.user_id)
887
898
888 if self.check_permissions(user.permissions, repo_name):
899 if self.check_permissions(user.permissions, repo_name):
889 log.debug('Permission to %s granted for user: %s @ %s', repo_name,
900 log.debug('Permission to %s granted for user: %s @ %s', repo_name,
890 user, check_location)
901 user, check_location)
891 return True
902 return True
892
903
893 else:
904 else:
894 log.debug('Permission to %s denied for user: %s @ %s', repo_name,
905 log.debug('Permission to %s denied for user: %s @ %s', repo_name,
895 user, check_location)
906 user, check_location)
896 return False
907 return False
897
908
898 def check_permissions(self, perm_defs, repo_name):
909 def check_permissions(self, perm_defs, repo_name):
899 """
910 """
900 implement in child class should return True if permissions are ok,
911 implement in child class should return True if permissions are ok,
901 False otherwise
912 False otherwise
902
913
903 :param perm_defs: dict with permission definitions
914 :param perm_defs: dict with permission definitions
904 :param repo_name: repo name
915 :param repo_name: repo name
905 """
916 """
906 raise NotImplementedError()
917 raise NotImplementedError()
907
918
908
919
909 class HasPermissionAllApi(_BaseApiPerm):
920 class HasPermissionAllApi(_BaseApiPerm):
910 def __call__(self, user, check_location=''):
921 def __call__(self, user, check_location=''):
911 return super(HasPermissionAllApi, self)\
922 return super(HasPermissionAllApi, self)\
912 .__call__(check_location=check_location, user=user)
923 .__call__(check_location=check_location, user=user)
913
924
914 def check_permissions(self, perm_defs, repo):
925 def check_permissions(self, perm_defs, repo):
915 if self.required_perms.issubset(perm_defs.get('global')):
926 if self.required_perms.issubset(perm_defs.get('global')):
916 return True
927 return True
917 return False
928 return False
918
929
919
930
920 class HasPermissionAnyApi(_BaseApiPerm):
931 class HasPermissionAnyApi(_BaseApiPerm):
921 def __call__(self, user, check_location=''):
932 def __call__(self, user, check_location=''):
922 return super(HasPermissionAnyApi, self)\
933 return super(HasPermissionAnyApi, self)\
923 .__call__(check_location=check_location, user=user)
934 .__call__(check_location=check_location, user=user)
924
935
925 def check_permissions(self, perm_defs, repo):
936 def check_permissions(self, perm_defs, repo):
926 if self.required_perms.intersection(perm_defs.get('global')):
937 if self.required_perms.intersection(perm_defs.get('global')):
927 return True
938 return True
928 return False
939 return False
929
940
930
941
931 class HasRepoPermissionAllApi(_BaseApiPerm):
942 class HasRepoPermissionAllApi(_BaseApiPerm):
932 def __call__(self, user, repo_name, check_location=''):
943 def __call__(self, user, repo_name, check_location=''):
933 return super(HasRepoPermissionAllApi, self)\
944 return super(HasRepoPermissionAllApi, self)\
934 .__call__(check_location=check_location, user=user,
945 .__call__(check_location=check_location, user=user,
935 repo_name=repo_name)
946 repo_name=repo_name)
936
947
937 def check_permissions(self, perm_defs, repo_name):
948 def check_permissions(self, perm_defs, repo_name):
938
949
939 try:
950 try:
940 self._user_perms = set(
951 self._user_perms = set(
941 [perm_defs['repositories'][repo_name]]
952 [perm_defs['repositories'][repo_name]]
942 )
953 )
943 except KeyError:
954 except KeyError:
944 log.warning(traceback.format_exc())
955 log.warning(traceback.format_exc())
945 return False
956 return False
946 if self.required_perms.issubset(self._user_perms):
957 if self.required_perms.issubset(self._user_perms):
947 return True
958 return True
948 return False
959 return False
949
960
950
961
951 class HasRepoPermissionAnyApi(_BaseApiPerm):
962 class HasRepoPermissionAnyApi(_BaseApiPerm):
952 def __call__(self, user, repo_name, check_location=''):
963 def __call__(self, user, repo_name, check_location=''):
953 return super(HasRepoPermissionAnyApi, self)\
964 return super(HasRepoPermissionAnyApi, self)\
954 .__call__(check_location=check_location, user=user,
965 .__call__(check_location=check_location, user=user,
955 repo_name=repo_name)
966 repo_name=repo_name)
956
967
957 def check_permissions(self, perm_defs, repo_name):
968 def check_permissions(self, perm_defs, repo_name):
958
969
959 try:
970 try:
960 _user_perms = set(
971 _user_perms = set(
961 [perm_defs['repositories'][repo_name]]
972 [perm_defs['repositories'][repo_name]]
962 )
973 )
963 except KeyError:
974 except KeyError:
964 log.warning(traceback.format_exc())
975 log.warning(traceback.format_exc())
965 return False
976 return False
966 if self.required_perms.intersection(_user_perms):
977 if self.required_perms.intersection(_user_perms):
967 return True
978 return True
968 return False
979 return False
969
980
970
981
971 def check_ip_access(source_ip, allowed_ips=None):
982 def check_ip_access(source_ip, allowed_ips=None):
972 """
983 """
973 Checks if source_ip is a subnet of any of allowed_ips.
984 Checks if source_ip is a subnet of any of allowed_ips.
974
985
975 :param source_ip:
986 :param source_ip:
976 :param allowed_ips: list of allowed ips together with mask
987 :param allowed_ips: list of allowed ips together with mask
977 """
988 """
978 from rhodecode.lib import ipaddr
989 from rhodecode.lib import ipaddr
979 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
990 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
980 if isinstance(allowed_ips, (tuple, list, set)):
991 if isinstance(allowed_ips, (tuple, list, set)):
981 for ip in allowed_ips:
992 for ip in allowed_ips:
982 if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip):
993 if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip):
983 return True
994 return True
984 return False
995 return False
General Comments 0
You need to be logged in to leave comments. Login now