##// END OF EJS Templates
fixed issue #644 When a user is both in read and write group, the permission taken in account is the last saved permission...
marcink -
r3094:b70c6652 beta
parent child Browse files
Show More
@@ -0,0 +1,1 b''
1 #TODO; write tests when we activate algo for permissions. No newline at end of file
@@ -1,675 +1,707 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 users model for RhodeCode
6 users model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 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 logging
26 import logging
27 import traceback
27 import traceback
28 import itertools
28 import itertools
29 import collections
30 import functools
29 from pylons import url
31 from pylons import url
30 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
31
33
32 from sqlalchemy.exc import DatabaseError
34 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.orm import joinedload
35 from sqlalchemy.orm import joinedload
34
36
35 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
37 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
36 from rhodecode.lib.caching_query import FromCache
38 from rhodecode.lib.caching_query import FromCache
37 from rhodecode.model import BaseModel
39 from rhodecode.model import BaseModel
38 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
40 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
39 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
41 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
40 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
42 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
41 UserEmailMap
43 UserEmailMap
42 from rhodecode.lib.exceptions import DefaultUserException, \
44 from rhodecode.lib.exceptions import DefaultUserException, \
43 UserOwnsReposException
45 UserOwnsReposException
44
46
45
47
46 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
47
49
48 PERM_WEIGHTS = Permission.PERM_WEIGHTS
50 PERM_WEIGHTS = Permission.PERM_WEIGHTS
49
51
50
52
51 class UserModel(BaseModel):
53 class UserModel(BaseModel):
52 cls = User
54 cls = User
53
55
54 def get(self, user_id, cache=False):
56 def get(self, user_id, cache=False):
55 user = self.sa.query(User)
57 user = self.sa.query(User)
56 if cache:
58 if cache:
57 user = user.options(FromCache("sql_cache_short",
59 user = user.options(FromCache("sql_cache_short",
58 "get_user_%s" % user_id))
60 "get_user_%s" % user_id))
59 return user.get(user_id)
61 return user.get(user_id)
60
62
61 def get_user(self, user):
63 def get_user(self, user):
62 return self._get_user(user)
64 return self._get_user(user)
63
65
64 def get_by_username(self, username, cache=False, case_insensitive=False):
66 def get_by_username(self, username, cache=False, case_insensitive=False):
65
67
66 if case_insensitive:
68 if case_insensitive:
67 user = self.sa.query(User).filter(User.username.ilike(username))
69 user = self.sa.query(User).filter(User.username.ilike(username))
68 else:
70 else:
69 user = self.sa.query(User)\
71 user = self.sa.query(User)\
70 .filter(User.username == username)
72 .filter(User.username == username)
71 if cache:
73 if cache:
72 user = user.options(FromCache("sql_cache_short",
74 user = user.options(FromCache("sql_cache_short",
73 "get_user_%s" % username))
75 "get_user_%s" % username))
74 return user.scalar()
76 return user.scalar()
75
77
76 def get_by_email(self, email, cache=False, case_insensitive=False):
78 def get_by_email(self, email, cache=False, case_insensitive=False):
77 return User.get_by_email(email, case_insensitive, cache)
79 return User.get_by_email(email, case_insensitive, cache)
78
80
79 def get_by_api_key(self, api_key, cache=False):
81 def get_by_api_key(self, api_key, cache=False):
80 return User.get_by_api_key(api_key, cache)
82 return User.get_by_api_key(api_key, cache)
81
83
82 def create(self, form_data):
84 def create(self, form_data):
83 from rhodecode.lib.auth import get_crypt_password
85 from rhodecode.lib.auth import get_crypt_password
84 try:
86 try:
85 new_user = User()
87 new_user = User()
86 for k, v in form_data.items():
88 for k, v in form_data.items():
87 if k == 'password':
89 if k == 'password':
88 v = get_crypt_password(v)
90 v = get_crypt_password(v)
89 if k == 'firstname':
91 if k == 'firstname':
90 k = 'name'
92 k = 'name'
91 setattr(new_user, k, v)
93 setattr(new_user, k, v)
92
94
93 new_user.api_key = generate_api_key(form_data['username'])
95 new_user.api_key = generate_api_key(form_data['username'])
94 self.sa.add(new_user)
96 self.sa.add(new_user)
95 return new_user
97 return new_user
96 except:
98 except:
97 log.error(traceback.format_exc())
99 log.error(traceback.format_exc())
98 raise
100 raise
99
101
100 def create_or_update(self, username, password, email, firstname='',
102 def create_or_update(self, username, password, email, firstname='',
101 lastname='', active=True, admin=False, ldap_dn=None):
103 lastname='', active=True, admin=False, ldap_dn=None):
102 """
104 """
103 Creates a new instance if not found, or updates current one
105 Creates a new instance if not found, or updates current one
104
106
105 :param username:
107 :param username:
106 :param password:
108 :param password:
107 :param email:
109 :param email:
108 :param active:
110 :param active:
109 :param firstname:
111 :param firstname:
110 :param lastname:
112 :param lastname:
111 :param active:
113 :param active:
112 :param admin:
114 :param admin:
113 :param ldap_dn:
115 :param ldap_dn:
114 """
116 """
115
117
116 from rhodecode.lib.auth import get_crypt_password
118 from rhodecode.lib.auth import get_crypt_password
117
119
118 log.debug('Checking for %s account in RhodeCode database' % username)
120 log.debug('Checking for %s account in RhodeCode database' % username)
119 user = User.get_by_username(username, case_insensitive=True)
121 user = User.get_by_username(username, case_insensitive=True)
120 if user is None:
122 if user is None:
121 log.debug('creating new user %s' % username)
123 log.debug('creating new user %s' % username)
122 new_user = User()
124 new_user = User()
123 edit = False
125 edit = False
124 else:
126 else:
125 log.debug('updating user %s' % username)
127 log.debug('updating user %s' % username)
126 new_user = user
128 new_user = user
127 edit = True
129 edit = True
128
130
129 try:
131 try:
130 new_user.username = username
132 new_user.username = username
131 new_user.admin = admin
133 new_user.admin = admin
132 # set password only if creating an user or password is changed
134 # set password only if creating an user or password is changed
133 if edit is False or user.password != password:
135 if edit is False or user.password != password:
134 new_user.password = get_crypt_password(password)
136 new_user.password = get_crypt_password(password)
135 new_user.api_key = generate_api_key(username)
137 new_user.api_key = generate_api_key(username)
136 new_user.email = email
138 new_user.email = email
137 new_user.active = active
139 new_user.active = active
138 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
140 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
139 new_user.name = firstname
141 new_user.name = firstname
140 new_user.lastname = lastname
142 new_user.lastname = lastname
141 self.sa.add(new_user)
143 self.sa.add(new_user)
142 return new_user
144 return new_user
143 except (DatabaseError,):
145 except (DatabaseError,):
144 log.error(traceback.format_exc())
146 log.error(traceback.format_exc())
145 raise
147 raise
146
148
147 def create_for_container_auth(self, username, attrs):
149 def create_for_container_auth(self, username, attrs):
148 """
150 """
149 Creates the given user if it's not already in the database
151 Creates the given user if it's not already in the database
150
152
151 :param username:
153 :param username:
152 :param attrs:
154 :param attrs:
153 """
155 """
154 if self.get_by_username(username, case_insensitive=True) is None:
156 if self.get_by_username(username, case_insensitive=True) is None:
155
157
156 # autogenerate email for container account without one
158 # autogenerate email for container account without one
157 generate_email = lambda usr: '%s@container_auth.account' % usr
159 generate_email = lambda usr: '%s@container_auth.account' % usr
158
160
159 try:
161 try:
160 new_user = User()
162 new_user = User()
161 new_user.username = username
163 new_user.username = username
162 new_user.password = None
164 new_user.password = None
163 new_user.api_key = generate_api_key(username)
165 new_user.api_key = generate_api_key(username)
164 new_user.email = attrs['email']
166 new_user.email = attrs['email']
165 new_user.active = attrs.get('active', True)
167 new_user.active = attrs.get('active', True)
166 new_user.name = attrs['name'] or generate_email(username)
168 new_user.name = attrs['name'] or generate_email(username)
167 new_user.lastname = attrs['lastname']
169 new_user.lastname = attrs['lastname']
168
170
169 self.sa.add(new_user)
171 self.sa.add(new_user)
170 return new_user
172 return new_user
171 except (DatabaseError,):
173 except (DatabaseError,):
172 log.error(traceback.format_exc())
174 log.error(traceback.format_exc())
173 self.sa.rollback()
175 self.sa.rollback()
174 raise
176 raise
175 log.debug('User %s already exists. Skipping creation of account'
177 log.debug('User %s already exists. Skipping creation of account'
176 ' for container auth.', username)
178 ' for container auth.', username)
177 return None
179 return None
178
180
179 def create_ldap(self, username, password, user_dn, attrs):
181 def create_ldap(self, username, password, user_dn, attrs):
180 """
182 """
181 Checks if user is in database, if not creates this user marked
183 Checks if user is in database, if not creates this user marked
182 as ldap user
184 as ldap user
183
185
184 :param username:
186 :param username:
185 :param password:
187 :param password:
186 :param user_dn:
188 :param user_dn:
187 :param attrs:
189 :param attrs:
188 """
190 """
189 from rhodecode.lib.auth import get_crypt_password
191 from rhodecode.lib.auth import get_crypt_password
190 log.debug('Checking for such ldap account in RhodeCode database')
192 log.debug('Checking for such ldap account in RhodeCode database')
191 if self.get_by_username(username, case_insensitive=True) is None:
193 if self.get_by_username(username, case_insensitive=True) is None:
192
194
193 # autogenerate email for ldap account without one
195 # autogenerate email for ldap account without one
194 generate_email = lambda usr: '%s@ldap.account' % usr
196 generate_email = lambda usr: '%s@ldap.account' % usr
195
197
196 try:
198 try:
197 new_user = User()
199 new_user = User()
198 username = username.lower()
200 username = username.lower()
199 # add ldap account always lowercase
201 # add ldap account always lowercase
200 new_user.username = username
202 new_user.username = username
201 new_user.password = get_crypt_password(password)
203 new_user.password = get_crypt_password(password)
202 new_user.api_key = generate_api_key(username)
204 new_user.api_key = generate_api_key(username)
203 new_user.email = attrs['email'] or generate_email(username)
205 new_user.email = attrs['email'] or generate_email(username)
204 new_user.active = attrs.get('active', True)
206 new_user.active = attrs.get('active', True)
205 new_user.ldap_dn = safe_unicode(user_dn)
207 new_user.ldap_dn = safe_unicode(user_dn)
206 new_user.name = attrs['name']
208 new_user.name = attrs['name']
207 new_user.lastname = attrs['lastname']
209 new_user.lastname = attrs['lastname']
208
210
209 self.sa.add(new_user)
211 self.sa.add(new_user)
210 return new_user
212 return new_user
211 except (DatabaseError,):
213 except (DatabaseError,):
212 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
213 self.sa.rollback()
215 self.sa.rollback()
214 raise
216 raise
215 log.debug('this %s user exists skipping creation of ldap account',
217 log.debug('this %s user exists skipping creation of ldap account',
216 username)
218 username)
217 return None
219 return None
218
220
219 def create_registration(self, form_data):
221 def create_registration(self, form_data):
220 from rhodecode.model.notification import NotificationModel
222 from rhodecode.model.notification import NotificationModel
221
223
222 try:
224 try:
223 form_data['admin'] = False
225 form_data['admin'] = False
224 new_user = self.create(form_data)
226 new_user = self.create(form_data)
225
227
226 self.sa.add(new_user)
228 self.sa.add(new_user)
227 self.sa.flush()
229 self.sa.flush()
228
230
229 # notification to admins
231 # notification to admins
230 subject = _('new user registration')
232 subject = _('new user registration')
231 body = ('New user registration\n'
233 body = ('New user registration\n'
232 '---------------------\n'
234 '---------------------\n'
233 '- Username: %s\n'
235 '- Username: %s\n'
234 '- Full Name: %s\n'
236 '- Full Name: %s\n'
235 '- Email: %s\n')
237 '- Email: %s\n')
236 body = body % (new_user.username, new_user.full_name,
238 body = body % (new_user.username, new_user.full_name,
237 new_user.email)
239 new_user.email)
238 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
240 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
239 kw = {'registered_user_url': edit_url}
241 kw = {'registered_user_url': edit_url}
240 NotificationModel().create(created_by=new_user, subject=subject,
242 NotificationModel().create(created_by=new_user, subject=subject,
241 body=body, recipients=None,
243 body=body, recipients=None,
242 type_=Notification.TYPE_REGISTRATION,
244 type_=Notification.TYPE_REGISTRATION,
243 email_kwargs=kw)
245 email_kwargs=kw)
244
246
245 except:
247 except:
246 log.error(traceback.format_exc())
248 log.error(traceback.format_exc())
247 raise
249 raise
248
250
249 def update(self, user_id, form_data, skip_attrs=[]):
251 def update(self, user_id, form_data, skip_attrs=[]):
250 from rhodecode.lib.auth import get_crypt_password
252 from rhodecode.lib.auth import get_crypt_password
251 try:
253 try:
252 user = self.get(user_id, cache=False)
254 user = self.get(user_id, cache=False)
253 if user.username == 'default':
255 if user.username == 'default':
254 raise DefaultUserException(
256 raise DefaultUserException(
255 _("You can't Edit this user since it's"
257 _("You can't Edit this user since it's"
256 " crucial for entire application"))
258 " crucial for entire application"))
257
259
258 for k, v in form_data.items():
260 for k, v in form_data.items():
259 if k in skip_attrs:
261 if k in skip_attrs:
260 continue
262 continue
261 if k == 'new_password' and v:
263 if k == 'new_password' and v:
262 user.password = get_crypt_password(v)
264 user.password = get_crypt_password(v)
263 user.api_key = generate_api_key(user.username)
265 user.api_key = generate_api_key(user.username)
264 else:
266 else:
265 if k == 'firstname':
267 if k == 'firstname':
266 k = 'name'
268 k = 'name'
267 setattr(user, k, v)
269 setattr(user, k, v)
268 self.sa.add(user)
270 self.sa.add(user)
269 except:
271 except:
270 log.error(traceback.format_exc())
272 log.error(traceback.format_exc())
271 raise
273 raise
272
274
273 def update_user(self, user, **kwargs):
275 def update_user(self, user, **kwargs):
274 from rhodecode.lib.auth import get_crypt_password
276 from rhodecode.lib.auth import get_crypt_password
275 try:
277 try:
276 user = self._get_user(user)
278 user = self._get_user(user)
277 if user.username == 'default':
279 if user.username == 'default':
278 raise DefaultUserException(
280 raise DefaultUserException(
279 _("You can't Edit this user since it's"
281 _("You can't Edit this user since it's"
280 " crucial for entire application")
282 " crucial for entire application")
281 )
283 )
282
284
283 for k, v in kwargs.items():
285 for k, v in kwargs.items():
284 if k == 'password' and v:
286 if k == 'password' and v:
285 v = get_crypt_password(v)
287 v = get_crypt_password(v)
286 user.api_key = generate_api_key(user.username)
288 user.api_key = generate_api_key(user.username)
287
289
288 setattr(user, k, v)
290 setattr(user, k, v)
289 self.sa.add(user)
291 self.sa.add(user)
290 return user
292 return user
291 except:
293 except:
292 log.error(traceback.format_exc())
294 log.error(traceback.format_exc())
293 raise
295 raise
294
296
295 def update_my_account(self, user_id, form_data):
297 def update_my_account(self, user_id, form_data):
296 from rhodecode.lib.auth import get_crypt_password
298 from rhodecode.lib.auth import get_crypt_password
297 try:
299 try:
298 user = self.get(user_id, cache=False)
300 user = self.get(user_id, cache=False)
299 if user.username == 'default':
301 if user.username == 'default':
300 raise DefaultUserException(
302 raise DefaultUserException(
301 _("You can't Edit this user since it's"
303 _("You can't Edit this user since it's"
302 " crucial for entire application")
304 " crucial for entire application")
303 )
305 )
304 for k, v in form_data.items():
306 for k, v in form_data.items():
305 if k == 'new_password' and v:
307 if k == 'new_password' and v:
306 user.password = get_crypt_password(v)
308 user.password = get_crypt_password(v)
307 user.api_key = generate_api_key(user.username)
309 user.api_key = generate_api_key(user.username)
308 else:
310 else:
309 if k == 'firstname':
311 if k == 'firstname':
310 k = 'name'
312 k = 'name'
311 if k not in ['admin', 'active']:
313 if k not in ['admin', 'active']:
312 setattr(user, k, v)
314 setattr(user, k, v)
313
315
314 self.sa.add(user)
316 self.sa.add(user)
315 except:
317 except:
316 log.error(traceback.format_exc())
318 log.error(traceback.format_exc())
317 raise
319 raise
318
320
319 def delete(self, user):
321 def delete(self, user):
320 user = self._get_user(user)
322 user = self._get_user(user)
321
323
322 try:
324 try:
323 if user.username == 'default':
325 if user.username == 'default':
324 raise DefaultUserException(
326 raise DefaultUserException(
325 _(u"You can't remove this user since it's"
327 _(u"You can't remove this user since it's"
326 " crucial for entire application")
328 " crucial for entire application")
327 )
329 )
328 if user.repositories:
330 if user.repositories:
329 repos = [x.repo_name for x in user.repositories]
331 repos = [x.repo_name for x in user.repositories]
330 raise UserOwnsReposException(
332 raise UserOwnsReposException(
331 _(u'user "%s" still owns %s repositories and cannot be '
333 _(u'user "%s" still owns %s repositories and cannot be '
332 'removed. Switch owners or remove those repositories. %s')
334 'removed. Switch owners or remove those repositories. %s')
333 % (user.username, len(repos), ', '.join(repos))
335 % (user.username, len(repos), ', '.join(repos))
334 )
336 )
335 self.sa.delete(user)
337 self.sa.delete(user)
336 except:
338 except:
337 log.error(traceback.format_exc())
339 log.error(traceback.format_exc())
338 raise
340 raise
339
341
340 def reset_password_link(self, data):
342 def reset_password_link(self, data):
341 from rhodecode.lib.celerylib import tasks, run_task
343 from rhodecode.lib.celerylib import tasks, run_task
342 run_task(tasks.send_password_link, data['email'])
344 run_task(tasks.send_password_link, data['email'])
343
345
344 def reset_password(self, data):
346 def reset_password(self, data):
345 from rhodecode.lib.celerylib import tasks, run_task
347 from rhodecode.lib.celerylib import tasks, run_task
346 run_task(tasks.reset_user_password, data['email'])
348 run_task(tasks.reset_user_password, data['email'])
347
349
348 def fill_data(self, auth_user, user_id=None, api_key=None):
350 def fill_data(self, auth_user, user_id=None, api_key=None):
349 """
351 """
350 Fetches auth_user by user_id,or api_key if present.
352 Fetches auth_user by user_id,or api_key if present.
351 Fills auth_user attributes with those taken from database.
353 Fills auth_user attributes with those taken from database.
352 Additionally set's is_authenitated if lookup fails
354 Additionally set's is_authenitated if lookup fails
353 present in database
355 present in database
354
356
355 :param auth_user: instance of user to set attributes
357 :param auth_user: instance of user to set attributes
356 :param user_id: user id to fetch by
358 :param user_id: user id to fetch by
357 :param api_key: api key to fetch by
359 :param api_key: api key to fetch by
358 """
360 """
359 if user_id is None and api_key is None:
361 if user_id is None and api_key is None:
360 raise Exception('You need to pass user_id or api_key')
362 raise Exception('You need to pass user_id or api_key')
361
363
362 try:
364 try:
363 if api_key:
365 if api_key:
364 dbuser = self.get_by_api_key(api_key)
366 dbuser = self.get_by_api_key(api_key)
365 else:
367 else:
366 dbuser = self.get(user_id)
368 dbuser = self.get(user_id)
367
369
368 if dbuser is not None and dbuser.active:
370 if dbuser is not None and dbuser.active:
369 log.debug('filling %s data' % dbuser)
371 log.debug('filling %s data' % dbuser)
370 for k, v in dbuser.get_dict().items():
372 for k, v in dbuser.get_dict().items():
371 setattr(auth_user, k, v)
373 setattr(auth_user, k, v)
372 else:
374 else:
373 return False
375 return False
374
376
375 except:
377 except:
376 log.error(traceback.format_exc())
378 log.error(traceback.format_exc())
377 auth_user.is_authenticated = False
379 auth_user.is_authenticated = False
378 return False
380 return False
379
381
380 return True
382 return True
381
383
382 def fill_perms(self, user):
384 def fill_perms(self, user, explicit=True, algo='higherwin'):
383 """
385 """
384 Fills user permission attribute with permissions taken from database
386 Fills user permission attribute with permissions taken from database
385 works for permissions given for repositories, and for permissions that
387 works for permissions given for repositories, and for permissions that
386 are granted to groups
388 are granted to groups
387
389
388 :param user: user instance to fill his perms
390 :param user: user instance to fill his perms
391 :param explicit: In case there are permissions both for user and a group
392 that user is part of, explicit flag will defiine if user will
393 explicitly override permissions from group, if it's False it will
394 make decision based on the algo
395 :param algo: algorithm to decide what permission should be choose if
396 it's multiple defined, eg user in two different groups. It also
397 decides if explicit flag is turned off how to specify the permission
398 for case when user is in a group + have defined separate permission
389 """
399 """
390 RK = 'repositories'
400 RK = 'repositories'
391 GK = 'repositories_groups'
401 GK = 'repositories_groups'
392 GLOBAL = 'global'
402 GLOBAL = 'global'
393 user.permissions[RK] = {}
403 user.permissions[RK] = {}
394 user.permissions[GK] = {}
404 user.permissions[GK] = {}
395 user.permissions[GLOBAL] = set()
405 user.permissions[GLOBAL] = set()
396
406
407 def _choose_perm(new_perm, cur_perm):
408 new_perm_val = PERM_WEIGHTS[new_perm]
409 cur_perm_val = PERM_WEIGHTS[cur_perm]
410 if algo == 'higherwin':
411 if new_perm_val > cur_perm_val:
412 return new_perm
413 return cur_perm
414 elif algo == 'lowerwin':
415 if new_perm_val < cur_perm_val:
416 return new_perm
417 return cur_perm
418
397 #======================================================================
419 #======================================================================
398 # fetch default permissions
420 # fetch default permissions
399 #======================================================================
421 #======================================================================
400 default_user = User.get_by_username('default', cache=True)
422 default_user = User.get_by_username('default', cache=True)
401 default_user_id = default_user.user_id
423 default_user_id = default_user.user_id
402
424
403 default_repo_perms = Permission.get_default_perms(default_user_id)
425 default_repo_perms = Permission.get_default_perms(default_user_id)
404 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
426 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
405
427
406 if user.is_admin:
428 if user.is_admin:
407 #==================================================================
429 #==================================================================
408 # admin user have all default rights for repositories
430 # admin user have all default rights for repositories
409 # and groups set to admin
431 # and groups set to admin
410 #==================================================================
432 #==================================================================
411 user.permissions[GLOBAL].add('hg.admin')
433 user.permissions[GLOBAL].add('hg.admin')
412
434
413 # repositories
435 # repositories
414 for perm in default_repo_perms:
436 for perm in default_repo_perms:
415 r_k = perm.UserRepoToPerm.repository.repo_name
437 r_k = perm.UserRepoToPerm.repository.repo_name
416 p = 'repository.admin'
438 p = 'repository.admin'
417 user.permissions[RK][r_k] = p
439 user.permissions[RK][r_k] = p
418
440
419 # repositories groups
441 # repositories groups
420 for perm in default_repo_groups_perms:
442 for perm in default_repo_groups_perms:
421 rg_k = perm.UserRepoGroupToPerm.group.group_name
443 rg_k = perm.UserRepoGroupToPerm.group.group_name
422 p = 'group.admin'
444 p = 'group.admin'
423 user.permissions[GK][rg_k] = p
445 user.permissions[GK][rg_k] = p
424 return user
446 return user
425
447
426 #==================================================================
448 #==================================================================
427 # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS
449 # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS
428 #==================================================================
450 #==================================================================
429 uid = user.user_id
451 uid = user.user_id
430
452
431 # default global permissions taken fron the default user
453 # default global permissions taken fron the default user
432 default_global_perms = self.sa.query(UserToPerm)\
454 default_global_perms = self.sa.query(UserToPerm)\
433 .filter(UserToPerm.user_id == default_user_id)
455 .filter(UserToPerm.user_id == default_user_id)
434
456
435 for perm in default_global_perms:
457 for perm in default_global_perms:
436 user.permissions[GLOBAL].add(perm.permission.permission_name)
458 user.permissions[GLOBAL].add(perm.permission.permission_name)
437
459
438 # defaults for repositories, taken from default user
460 # defaults for repositories, taken from default user
439 for perm in default_repo_perms:
461 for perm in default_repo_perms:
440 r_k = perm.UserRepoToPerm.repository.repo_name
462 r_k = perm.UserRepoToPerm.repository.repo_name
441 if perm.Repository.private and not (perm.Repository.user_id == uid):
463 if perm.Repository.private and not (perm.Repository.user_id == uid):
442 # disable defaults for private repos,
464 # disable defaults for private repos,
443 p = 'repository.none'
465 p = 'repository.none'
444 elif perm.Repository.user_id == uid:
466 elif perm.Repository.user_id == uid:
445 # set admin if owner
467 # set admin if owner
446 p = 'repository.admin'
468 p = 'repository.admin'
447 else:
469 else:
448 p = perm.Permission.permission_name
470 p = perm.Permission.permission_name
449
471
450 user.permissions[RK][r_k] = p
472 user.permissions[RK][r_k] = p
451
473
452 # defaults for repositories groups taken from default user permission
474 # defaults for repositories groups taken from default user permission
453 # on given group
475 # on given group
454 for perm in default_repo_groups_perms:
476 for perm in default_repo_groups_perms:
455 rg_k = perm.UserRepoGroupToPerm.group.group_name
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
456 p = perm.Permission.permission_name
478 p = perm.Permission.permission_name
457 user.permissions[GK][rg_k] = p
479 user.permissions[GK][rg_k] = p
458
480
459 #======================================================================
481 #======================================================================
460 # !! OVERRIDE GLOBALS !! with user permissions if any found
482 # !! OVERRIDE GLOBALS !! with user permissions if any found
461 #======================================================================
483 #======================================================================
462 # those can be configured from groups or users explicitly
484 # those can be configured from groups or users explicitly
463 _configurable = set(['hg.fork.none', 'hg.fork.repository',
485 _configurable = set(['hg.fork.none', 'hg.fork.repository',
464 'hg.create.none', 'hg.create.repository'])
486 'hg.create.none', 'hg.create.repository'])
465
487
466 # USER GROUPS comes first
488 # USER GROUPS comes first
467 # users group global permissions
489 # users group global permissions
468 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
490 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
469 .options(joinedload(UsersGroupToPerm.permission))\
491 .options(joinedload(UsersGroupToPerm.permission))\
470 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
492 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
471 UsersGroupMember.users_group_id))\
493 UsersGroupMember.users_group_id))\
472 .filter(UsersGroupMember.user_id == uid)\
494 .filter(UsersGroupMember.user_id == uid)\
473 .order_by(UsersGroupToPerm.users_group_id)\
495 .order_by(UsersGroupToPerm.users_group_id)\
474 .all()
496 .all()
475 #need to group here by groups since user can be in more than one group
497 #need to group here by groups since user can be in more than one group
476 _grouped = [[x, list(y)] for x, y in
498 _grouped = [[x, list(y)] for x, y in
477 itertools.groupby(user_perms_from_users_groups,
499 itertools.groupby(user_perms_from_users_groups,
478 lambda x:x.users_group)]
500 lambda x:x.users_group)]
479 for gr, perms in _grouped:
501 for gr, perms in _grouped:
480 # since user can be in multiple groups iterate over them and
502 # since user can be in multiple groups iterate over them and
481 # select the lowest permissions first (more explicit)
503 # select the lowest permissions first (more explicit)
482 ##TODO: do this^^
504 ##TODO: do this^^
483 if not gr.inherit_default_permissions:
505 if not gr.inherit_default_permissions:
484 # NEED TO IGNORE all configurable permissions and
506 # NEED TO IGNORE all configurable permissions and
485 # replace them with explicitly set
507 # replace them with explicitly set
486 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
508 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
487 .difference(_configurable)
509 .difference(_configurable)
488 for perm in perms:
510 for perm in perms:
489 user.permissions[GLOBAL].add(perm.permission.permission_name)
511 user.permissions[GLOBAL].add(perm.permission.permission_name)
490
512
491 # user specific global permissions
513 # user specific global permissions
492 user_perms = self.sa.query(UserToPerm)\
514 user_perms = self.sa.query(UserToPerm)\
493 .options(joinedload(UserToPerm.permission))\
515 .options(joinedload(UserToPerm.permission))\
494 .filter(UserToPerm.user_id == uid).all()
516 .filter(UserToPerm.user_id == uid).all()
495
517
496 if not user.inherit_default_permissions:
518 if not user.inherit_default_permissions:
497 # NEED TO IGNORE all configurable permissions and
519 # NEED TO IGNORE all configurable permissions and
498 # replace them with explicitly set
520 # replace them with explicitly set
499 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
521 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
500 .difference(_configurable)
522 .difference(_configurable)
501
523
502 for perm in user_perms:
524 for perm in user_perms:
503 user.permissions[GLOBAL].add(perm.permission.permission_name)
525 user.permissions[GLOBAL].add(perm.permission.permission_name)
504
526
505 #======================================================================
527 #======================================================================
506 # !! REPO PERMISSIONS !!
528 # !! PERMISSIONS FOR REPOSITORIES !!
507 #======================================================================
529 #======================================================================
508 #======================================================================
530 #======================================================================
509 # check if user is part of user groups for this repository and
531 # check if user is part of user groups for this repository and
510 # fill in (or NOT replace with higher `or 1` permissions
532 # fill in his permission from it. _choose_perm decides of which
533 # permission should be selected based on selected method
511 #======================================================================
534 #======================================================================
535
512 # users group for repositories permissions
536 # users group for repositories permissions
513 user_repo_perms_from_users_groups = \
537 user_repo_perms_from_users_groups = \
514 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
538 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
515 .join((Repository, UsersGroupRepoToPerm.repository_id ==
539 .join((Repository, UsersGroupRepoToPerm.repository_id ==
516 Repository.repo_id))\
540 Repository.repo_id))\
517 .join((Permission, UsersGroupRepoToPerm.permission_id ==
541 .join((Permission, UsersGroupRepoToPerm.permission_id ==
518 Permission.permission_id))\
542 Permission.permission_id))\
519 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
543 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
520 UsersGroupMember.users_group_id))\
544 UsersGroupMember.users_group_id))\
521 .filter(UsersGroupMember.user_id == uid)\
545 .filter(UsersGroupMember.user_id == uid)\
522 .all()
546 .all()
523
547
548 multiple_counter = collections.Counter()
524 for perm in user_repo_perms_from_users_groups:
549 for perm in user_repo_perms_from_users_groups:
525 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
550 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
551 multiple_counter[r_k] += 1
526 p = perm.Permission.permission_name
552 p = perm.Permission.permission_name
527 cur_perm = user.permissions[RK][r_k]
553 cur_perm = user.permissions[RK][r_k]
528 # overwrite permission only if it's greater than permission
529 # given from other sources - disabled with `or 1` now
530 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
531 if perm.Repository.user_id == uid:
532 # set admin if owner
533 p = 'repository.admin'
534
554
535 user.permissions[RK][r_k] = p
555 if perm.Repository.user_id == uid:
556 # set admin if owner
557 p = 'repository.admin'
558 else:
559 if multiple_counter[r_k] > 1:
560 p = _choose_perm(p, cur_perm)
561 user.permissions[RK][r_k] = p
536
562
537 # user explicit permissions for repositories
563 # user explicit permissions for repositories, overrides any specified
564 # by the group permission
538 user_repo_perms = \
565 user_repo_perms = \
539 self.sa.query(UserRepoToPerm, Permission, Repository)\
566 self.sa.query(UserRepoToPerm, Permission, Repository)\
540 .join((Repository, UserRepoToPerm.repository_id ==
567 .join((Repository, UserRepoToPerm.repository_id ==
541 Repository.repo_id))\
568 Repository.repo_id))\
542 .join((Permission, UserRepoToPerm.permission_id ==
569 .join((Permission, UserRepoToPerm.permission_id ==
543 Permission.permission_id))\
570 Permission.permission_id))\
544 .filter(UserRepoToPerm.user_id == uid)\
571 .filter(UserRepoToPerm.user_id == uid)\
545 .all()
572 .all()
546
573
547 for perm in user_repo_perms:
574 for perm in user_repo_perms:
575 r_k = perm.UserRepoToPerm.repository.repo_name
576 cur_perm = user.permissions[RK][r_k]
548 # set admin if owner
577 # set admin if owner
549 r_k = perm.UserRepoToPerm.repository.repo_name
550 if perm.Repository.user_id == uid:
578 if perm.Repository.user_id == uid:
551 p = 'repository.admin'
579 p = 'repository.admin'
552 else:
580 else:
553 p = perm.Permission.permission_name
581 p = perm.Permission.permission_name
582 if not explicit:
583 p = _choose_perm(p, cur_perm)
554 user.permissions[RK][r_k] = p
584 user.permissions[RK][r_k] = p
555
585
556 # REPO GROUP
586 #======================================================================
557 #==================================================================
587 # !! PERMISSIONS FOR REPOSITORIES GROUPS !!
558 # get access for this user for repos group and override defaults
588 #======================================================================
559 #==================================================================
589 #======================================================================
590 # check if user is part of user groups for this repository groups and
591 # fill in his permission from it. _choose_perm decides of which
592 # permission should be selected based on selected method
593 #======================================================================
594 # users group for repo groups permissions
595 user_repo_group_perms_from_users_groups = \
596 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
597 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
598 .join((Permission, UsersGroupRepoGroupToPerm.permission_id
599 == Permission.permission_id))\
600 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id
601 == UsersGroupMember.users_group_id))\
602 .filter(UsersGroupMember.user_id == uid)\
603 .all()
560
604
561 # user explicit permissions for repository
605 multiple_counter = collections.Counter()
606 for perm in user_repo_group_perms_from_users_groups:
607 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
608 multiple_counter[g_k] += 1
609 p = perm.Permission.permission_name
610 cur_perm = user.permissions[GK][g_k]
611 if multiple_counter[g_k] > 1:
612 p = _choose_perm(p, cur_perm)
613 user.permissions[GK][g_k] = p
614
615 # user explicit permissions for repository groups
562 user_repo_groups_perms = \
616 user_repo_groups_perms = \
563 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
617 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
564 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
618 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
565 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
619 .join((Permission, UserRepoGroupToPerm.permission_id
620 == Permission.permission_id))\
566 .filter(UserRepoGroupToPerm.user_id == uid)\
621 .filter(UserRepoGroupToPerm.user_id == uid)\
567 .all()
622 .all()
568
623
569 for perm in user_repo_groups_perms:
624 for perm in user_repo_groups_perms:
570 rg_k = perm.UserRepoGroupToPerm.group.group_name
625 rg_k = perm.UserRepoGroupToPerm.group.group_name
571 p = perm.Permission.permission_name
626 p = perm.Permission.permission_name
572 cur_perm = user.permissions[GK][rg_k]
627 cur_perm = user.permissions[GK][rg_k]
573 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
628 if not explicit:
574 user.permissions[GK][rg_k] = p
629 p = _choose_perm(p, cur_perm)
575
630 user.permissions[GK][rg_k] = p
576 # REPO GROUP + USER GROUP
577 #==================================================================
578 # check if user is part of user groups for this repo group and
579 # fill in (or replace with higher) permissions
580 #==================================================================
581
582 # users group for repositories permissions
583 user_repo_group_perms_from_users_groups = \
584 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
585 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
586 .join((Permission, UsersGroupRepoGroupToPerm.permission_id == Permission.permission_id))\
587 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
588 .filter(UsersGroupMember.user_id == uid)\
589 .all()
590
591 for perm in user_repo_group_perms_from_users_groups:
592 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
593 p = perm.Permission.permission_name
594 cur_perm = user.permissions[GK][g_k]
595 # overwrite permission only if it's greater than permission
596 # given from other sources
597 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
598 user.permissions[GK][g_k] = p
599
631
600 return user
632 return user
601
633
602 def has_perm(self, user, perm):
634 def has_perm(self, user, perm):
603 perm = self._get_perm(perm)
635 perm = self._get_perm(perm)
604 user = self._get_user(user)
636 user = self._get_user(user)
605
637
606 return UserToPerm.query().filter(UserToPerm.user == user)\
638 return UserToPerm.query().filter(UserToPerm.user == user)\
607 .filter(UserToPerm.permission == perm).scalar() is not None
639 .filter(UserToPerm.permission == perm).scalar() is not None
608
640
609 def grant_perm(self, user, perm):
641 def grant_perm(self, user, perm):
610 """
642 """
611 Grant user global permissions
643 Grant user global permissions
612
644
613 :param user:
645 :param user:
614 :param perm:
646 :param perm:
615 """
647 """
616 user = self._get_user(user)
648 user = self._get_user(user)
617 perm = self._get_perm(perm)
649 perm = self._get_perm(perm)
618 # if this permission is already granted skip it
650 # if this permission is already granted skip it
619 _perm = UserToPerm.query()\
651 _perm = UserToPerm.query()\
620 .filter(UserToPerm.user == user)\
652 .filter(UserToPerm.user == user)\
621 .filter(UserToPerm.permission == perm)\
653 .filter(UserToPerm.permission == perm)\
622 .scalar()
654 .scalar()
623 if _perm:
655 if _perm:
624 return
656 return
625 new = UserToPerm()
657 new = UserToPerm()
626 new.user = user
658 new.user = user
627 new.permission = perm
659 new.permission = perm
628 self.sa.add(new)
660 self.sa.add(new)
629
661
630 def revoke_perm(self, user, perm):
662 def revoke_perm(self, user, perm):
631 """
663 """
632 Revoke users global permissions
664 Revoke users global permissions
633
665
634 :param user:
666 :param user:
635 :param perm:
667 :param perm:
636 """
668 """
637 user = self._get_user(user)
669 user = self._get_user(user)
638 perm = self._get_perm(perm)
670 perm = self._get_perm(perm)
639
671
640 obj = UserToPerm.query()\
672 obj = UserToPerm.query()\
641 .filter(UserToPerm.user == user)\
673 .filter(UserToPerm.user == user)\
642 .filter(UserToPerm.permission == perm)\
674 .filter(UserToPerm.permission == perm)\
643 .scalar()
675 .scalar()
644 if obj:
676 if obj:
645 self.sa.delete(obj)
677 self.sa.delete(obj)
646
678
647 def add_extra_email(self, user, email):
679 def add_extra_email(self, user, email):
648 """
680 """
649 Adds email address to UserEmailMap
681 Adds email address to UserEmailMap
650
682
651 :param user:
683 :param user:
652 :param email:
684 :param email:
653 """
685 """
654 from rhodecode.model import forms
686 from rhodecode.model import forms
655 form = forms.UserExtraEmailForm()()
687 form = forms.UserExtraEmailForm()()
656 data = form.to_python(dict(email=email))
688 data = form.to_python(dict(email=email))
657 user = self._get_user(user)
689 user = self._get_user(user)
658
690
659 obj = UserEmailMap()
691 obj = UserEmailMap()
660 obj.user = user
692 obj.user = user
661 obj.email = data['email']
693 obj.email = data['email']
662 self.sa.add(obj)
694 self.sa.add(obj)
663 return obj
695 return obj
664
696
665 def delete_extra_email(self, user, email_id):
697 def delete_extra_email(self, user, email_id):
666 """
698 """
667 Removes email address from UserEmailMap
699 Removes email address from UserEmailMap
668
700
669 :param user:
701 :param user:
670 :param email_id:
702 :param email_id:
671 """
703 """
672 user = self._get_user(user)
704 user = self._get_user(user)
673 obj = UserEmailMap.query().get(email_id)
705 obj = UserEmailMap.query().get(email_id)
674 if obj:
706 if obj:
675 self.sa.delete(obj)
707 self.sa.delete(obj)
General Comments 0
You need to be logged in to leave comments. Login now