##// END OF EJS Templates
user: speed up data propagatation for auth users by pre-filling only selected variables...
marcink -
r4018:e79bd088 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,979 +1,1000 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 users model for RhodeCode
22 users model for RhodeCode
23 """
23 """
24
24
25 import logging
25 import logging
26 import traceback
26 import traceback
27 import datetime
27 import datetime
28 import ipaddress
28 import ipaddress
29
29
30 from pyramid.threadlocal import get_current_request
30 from pyramid.threadlocal import get_current_request
31 from sqlalchemy.exc import DatabaseError
31 from sqlalchemy.exc import DatabaseError
32
32
33 from rhodecode import events
33 from rhodecode import events
34 from rhodecode.lib.user_log_filter import user_log_filter
34 from rhodecode.lib.user_log_filter import user_log_filter
35 from rhodecode.lib.utils2 import (
35 from rhodecode.lib.utils2 import (
36 safe_unicode, get_current_rhodecode_user, action_logger_generic,
36 safe_unicode, get_current_rhodecode_user, action_logger_generic,
37 AttributeDict, str2bool)
37 AttributeDict, str2bool)
38 from rhodecode.lib.exceptions import (
38 from rhodecode.lib.exceptions import (
39 DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException,
39 DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException,
40 UserOwnsUserGroupsException, NotAllowedToCreateUserError, UserOwnsArtifactsException)
40 UserOwnsUserGroupsException, NotAllowedToCreateUserError, UserOwnsArtifactsException)
41 from rhodecode.lib.caching_query import FromCache
41 from rhodecode.lib.caching_query import FromCache
42 from rhodecode.model import BaseModel
42 from rhodecode.model import BaseModel
43 from rhodecode.model.auth_token import AuthTokenModel
43 from rhodecode.model.auth_token import AuthTokenModel
44 from rhodecode.model.db import (
44 from rhodecode.model.db import (
45 _hash_key, true, false, or_, joinedload, User, UserToPerm,
45 _hash_key, true, false, or_, joinedload, User, UserToPerm,
46 UserEmailMap, UserIpMap, UserLog)
46 UserEmailMap, UserIpMap, UserLog)
47 from rhodecode.model.meta import Session
47 from rhodecode.model.meta import Session
48 from rhodecode.model.repo_group import RepoGroupModel
48 from rhodecode.model.repo_group import RepoGroupModel
49
49
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53
53
54 class UserModel(BaseModel):
54 class UserModel(BaseModel):
55 cls = User
55 cls = User
56
56
57 def get(self, user_id, cache=False):
57 def get(self, user_id, cache=False):
58 user = self.sa.query(User)
58 user = self.sa.query(User)
59 if cache:
59 if cache:
60 user = user.options(
60 user = user.options(
61 FromCache("sql_cache_short", "get_user_%s" % user_id))
61 FromCache("sql_cache_short", "get_user_%s" % user_id))
62 return user.get(user_id)
62 return user.get(user_id)
63
63
64 def get_user(self, user):
64 def get_user(self, user):
65 return self._get_user(user)
65 return self._get_user(user)
66
66
67 def _serialize_user(self, user):
67 def _serialize_user(self, user):
68 import rhodecode.lib.helpers as h
68 import rhodecode.lib.helpers as h
69
69
70 return {
70 return {
71 'id': user.user_id,
71 'id': user.user_id,
72 'first_name': user.first_name,
72 'first_name': user.first_name,
73 'last_name': user.last_name,
73 'last_name': user.last_name,
74 'username': user.username,
74 'username': user.username,
75 'email': user.email,
75 'email': user.email,
76 'icon_link': h.gravatar_url(user.email, 30),
76 'icon_link': h.gravatar_url(user.email, 30),
77 'profile_link': h.link_to_user(user),
77 'profile_link': h.link_to_user(user),
78 'value_display': h.escape(h.person(user)),
78 'value_display': h.escape(h.person(user)),
79 'value': user.username,
79 'value': user.username,
80 'value_type': 'user',
80 'value_type': 'user',
81 'active': user.active,
81 'active': user.active,
82 }
82 }
83
83
84 def get_users(self, name_contains=None, limit=20, only_active=True):
84 def get_users(self, name_contains=None, limit=20, only_active=True):
85
85
86 query = self.sa.query(User)
86 query = self.sa.query(User)
87 if only_active:
87 if only_active:
88 query = query.filter(User.active == true())
88 query = query.filter(User.active == true())
89
89
90 if name_contains:
90 if name_contains:
91 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
91 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
92 query = query.filter(
92 query = query.filter(
93 or_(
93 or_(
94 User.name.ilike(ilike_expression),
94 User.name.ilike(ilike_expression),
95 User.lastname.ilike(ilike_expression),
95 User.lastname.ilike(ilike_expression),
96 User.username.ilike(ilike_expression)
96 User.username.ilike(ilike_expression)
97 )
97 )
98 )
98 )
99 query = query.limit(limit)
99 query = query.limit(limit)
100 users = query.all()
100 users = query.all()
101
101
102 _users = [
102 _users = [
103 self._serialize_user(user) for user in users
103 self._serialize_user(user) for user in users
104 ]
104 ]
105 return _users
105 return _users
106
106
107 def get_by_username(self, username, cache=False, case_insensitive=False):
107 def get_by_username(self, username, cache=False, case_insensitive=False):
108
108
109 if case_insensitive:
109 if case_insensitive:
110 user = self.sa.query(User).filter(User.username.ilike(username))
110 user = self.sa.query(User).filter(User.username.ilike(username))
111 else:
111 else:
112 user = self.sa.query(User)\
112 user = self.sa.query(User)\
113 .filter(User.username == username)
113 .filter(User.username == username)
114 if cache:
114 if cache:
115 name_key = _hash_key(username)
115 name_key = _hash_key(username)
116 user = user.options(
116 user = user.options(
117 FromCache("sql_cache_short", "get_user_%s" % name_key))
117 FromCache("sql_cache_short", "get_user_%s" % name_key))
118 return user.scalar()
118 return user.scalar()
119
119
120 def get_by_email(self, email, cache=False, case_insensitive=False):
120 def get_by_email(self, email, cache=False, case_insensitive=False):
121 return User.get_by_email(email, case_insensitive, cache)
121 return User.get_by_email(email, case_insensitive, cache)
122
122
123 def get_by_auth_token(self, auth_token, cache=False):
123 def get_by_auth_token(self, auth_token, cache=False):
124 return User.get_by_auth_token(auth_token, cache)
124 return User.get_by_auth_token(auth_token, cache)
125
125
126 def get_active_user_count(self, cache=False):
126 def get_active_user_count(self, cache=False):
127 qry = User.query().filter(
127 qry = User.query().filter(
128 User.active == true()).filter(
128 User.active == true()).filter(
129 User.username != User.DEFAULT_USER)
129 User.username != User.DEFAULT_USER)
130 if cache:
130 if cache:
131 qry = qry.options(
131 qry = qry.options(
132 FromCache("sql_cache_short", "get_active_users"))
132 FromCache("sql_cache_short", "get_active_users"))
133 return qry.count()
133 return qry.count()
134
134
135 def create(self, form_data, cur_user=None):
135 def create(self, form_data, cur_user=None):
136 if not cur_user:
136 if not cur_user:
137 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
137 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
138
138
139 user_data = {
139 user_data = {
140 'username': form_data['username'],
140 'username': form_data['username'],
141 'password': form_data['password'],
141 'password': form_data['password'],
142 'email': form_data['email'],
142 'email': form_data['email'],
143 'firstname': form_data['firstname'],
143 'firstname': form_data['firstname'],
144 'lastname': form_data['lastname'],
144 'lastname': form_data['lastname'],
145 'active': form_data['active'],
145 'active': form_data['active'],
146 'extern_type': form_data['extern_type'],
146 'extern_type': form_data['extern_type'],
147 'extern_name': form_data['extern_name'],
147 'extern_name': form_data['extern_name'],
148 'admin': False,
148 'admin': False,
149 'cur_user': cur_user
149 'cur_user': cur_user
150 }
150 }
151
151
152 if 'create_repo_group' in form_data:
152 if 'create_repo_group' in form_data:
153 user_data['create_repo_group'] = str2bool(
153 user_data['create_repo_group'] = str2bool(
154 form_data.get('create_repo_group'))
154 form_data.get('create_repo_group'))
155
155
156 try:
156 try:
157 if form_data.get('password_change'):
157 if form_data.get('password_change'):
158 user_data['force_password_change'] = True
158 user_data['force_password_change'] = True
159 return UserModel().create_or_update(**user_data)
159 return UserModel().create_or_update(**user_data)
160 except Exception:
160 except Exception:
161 log.error(traceback.format_exc())
161 log.error(traceback.format_exc())
162 raise
162 raise
163
163
164 def update_user(self, user, skip_attrs=None, **kwargs):
164 def update_user(self, user, skip_attrs=None, **kwargs):
165 from rhodecode.lib.auth import get_crypt_password
165 from rhodecode.lib.auth import get_crypt_password
166
166
167 user = self._get_user(user)
167 user = self._get_user(user)
168 if user.username == User.DEFAULT_USER:
168 if user.username == User.DEFAULT_USER:
169 raise DefaultUserException(
169 raise DefaultUserException(
170 "You can't edit this user (`%(username)s`) since it's "
170 "You can't edit this user (`%(username)s`) since it's "
171 "crucial for entire application" % {
171 "crucial for entire application" % {
172 'username': user.username})
172 'username': user.username})
173
173
174 # first store only defaults
174 # first store only defaults
175 user_attrs = {
175 user_attrs = {
176 'updating_user_id': user.user_id,
176 'updating_user_id': user.user_id,
177 'username': user.username,
177 'username': user.username,
178 'password': user.password,
178 'password': user.password,
179 'email': user.email,
179 'email': user.email,
180 'firstname': user.name,
180 'firstname': user.name,
181 'lastname': user.lastname,
181 'lastname': user.lastname,
182 'active': user.active,
182 'active': user.active,
183 'admin': user.admin,
183 'admin': user.admin,
184 'extern_name': user.extern_name,
184 'extern_name': user.extern_name,
185 'extern_type': user.extern_type,
185 'extern_type': user.extern_type,
186 'language': user.user_data.get('language')
186 'language': user.user_data.get('language')
187 }
187 }
188
188
189 # in case there's new_password, that comes from form, use it to
189 # in case there's new_password, that comes from form, use it to
190 # store password
190 # store password
191 if kwargs.get('new_password'):
191 if kwargs.get('new_password'):
192 kwargs['password'] = kwargs['new_password']
192 kwargs['password'] = kwargs['new_password']
193
193
194 # cleanups, my_account password change form
194 # cleanups, my_account password change form
195 kwargs.pop('current_password', None)
195 kwargs.pop('current_password', None)
196 kwargs.pop('new_password', None)
196 kwargs.pop('new_password', None)
197
197
198 # cleanups, user edit password change form
198 # cleanups, user edit password change form
199 kwargs.pop('password_confirmation', None)
199 kwargs.pop('password_confirmation', None)
200 kwargs.pop('password_change', None)
200 kwargs.pop('password_change', None)
201
201
202 # create repo group on user creation
202 # create repo group on user creation
203 kwargs.pop('create_repo_group', None)
203 kwargs.pop('create_repo_group', None)
204
204
205 # legacy forms send name, which is the firstname
205 # legacy forms send name, which is the firstname
206 firstname = kwargs.pop('name', None)
206 firstname = kwargs.pop('name', None)
207 if firstname:
207 if firstname:
208 kwargs['firstname'] = firstname
208 kwargs['firstname'] = firstname
209
209
210 for k, v in kwargs.items():
210 for k, v in kwargs.items():
211 # skip if we don't want to update this
211 # skip if we don't want to update this
212 if skip_attrs and k in skip_attrs:
212 if skip_attrs and k in skip_attrs:
213 continue
213 continue
214
214
215 user_attrs[k] = v
215 user_attrs[k] = v
216
216
217 try:
217 try:
218 return self.create_or_update(**user_attrs)
218 return self.create_or_update(**user_attrs)
219 except Exception:
219 except Exception:
220 log.error(traceback.format_exc())
220 log.error(traceback.format_exc())
221 raise
221 raise
222
222
223 def create_or_update(
223 def create_or_update(
224 self, username, password, email, firstname='', lastname='',
224 self, username, password, email, firstname='', lastname='',
225 active=True, admin=False, extern_type=None, extern_name=None,
225 active=True, admin=False, extern_type=None, extern_name=None,
226 cur_user=None, plugin=None, force_password_change=False,
226 cur_user=None, plugin=None, force_password_change=False,
227 allow_to_create_user=True, create_repo_group=None,
227 allow_to_create_user=True, create_repo_group=None,
228 updating_user_id=None, language=None, strict_creation_check=True):
228 updating_user_id=None, language=None, strict_creation_check=True):
229 """
229 """
230 Creates a new instance if not found, or updates current one
230 Creates a new instance if not found, or updates current one
231
231
232 :param username:
232 :param username:
233 :param password:
233 :param password:
234 :param email:
234 :param email:
235 :param firstname:
235 :param firstname:
236 :param lastname:
236 :param lastname:
237 :param active:
237 :param active:
238 :param admin:
238 :param admin:
239 :param extern_type:
239 :param extern_type:
240 :param extern_name:
240 :param extern_name:
241 :param cur_user:
241 :param cur_user:
242 :param plugin: optional plugin this method was called from
242 :param plugin: optional plugin this method was called from
243 :param force_password_change: toggles new or existing user flag
243 :param force_password_change: toggles new or existing user flag
244 for password change
244 for password change
245 :param allow_to_create_user: Defines if the method can actually create
245 :param allow_to_create_user: Defines if the method can actually create
246 new users
246 new users
247 :param create_repo_group: Defines if the method should also
247 :param create_repo_group: Defines if the method should also
248 create an repo group with user name, and owner
248 create an repo group with user name, and owner
249 :param updating_user_id: if we set it up this is the user we want to
249 :param updating_user_id: if we set it up this is the user we want to
250 update this allows to editing username.
250 update this allows to editing username.
251 :param language: language of user from interface.
251 :param language: language of user from interface.
252
252
253 :returns: new User object with injected `is_new_user` attribute.
253 :returns: new User object with injected `is_new_user` attribute.
254 """
254 """
255
255
256 if not cur_user:
256 if not cur_user:
257 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
257 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
258
258
259 from rhodecode.lib.auth import (
259 from rhodecode.lib.auth import (
260 get_crypt_password, check_password, generate_auth_token)
260 get_crypt_password, check_password, generate_auth_token)
261 from rhodecode.lib.hooks_base import (
261 from rhodecode.lib.hooks_base import (
262 log_create_user, check_allowed_create_user)
262 log_create_user, check_allowed_create_user)
263
263
264 def _password_change(new_user, password):
264 def _password_change(new_user, password):
265 old_password = new_user.password or ''
265 old_password = new_user.password or ''
266 # empty password
266 # empty password
267 if not old_password:
267 if not old_password:
268 return False
268 return False
269
269
270 # password check is only needed for RhodeCode internal auth calls
270 # password check is only needed for RhodeCode internal auth calls
271 # in case it's a plugin we don't care
271 # in case it's a plugin we don't care
272 if not plugin:
272 if not plugin:
273
273
274 # first check if we gave crypted password back, and if it
274 # first check if we gave crypted password back, and if it
275 # matches it's not password change
275 # matches it's not password change
276 if new_user.password == password:
276 if new_user.password == password:
277 return False
277 return False
278
278
279 password_match = check_password(password, old_password)
279 password_match = check_password(password, old_password)
280 if not password_match:
280 if not password_match:
281 return True
281 return True
282
282
283 return False
283 return False
284
284
285 # read settings on default personal repo group creation
285 # read settings on default personal repo group creation
286 if create_repo_group is None:
286 if create_repo_group is None:
287 default_create_repo_group = RepoGroupModel()\
287 default_create_repo_group = RepoGroupModel()\
288 .get_default_create_personal_repo_group()
288 .get_default_create_personal_repo_group()
289 create_repo_group = default_create_repo_group
289 create_repo_group = default_create_repo_group
290
290
291 user_data = {
291 user_data = {
292 'username': username,
292 'username': username,
293 'password': password,
293 'password': password,
294 'email': email,
294 'email': email,
295 'firstname': firstname,
295 'firstname': firstname,
296 'lastname': lastname,
296 'lastname': lastname,
297 'active': active,
297 'active': active,
298 'admin': admin
298 'admin': admin
299 }
299 }
300
300
301 if updating_user_id:
301 if updating_user_id:
302 log.debug('Checking for existing account in RhodeCode '
302 log.debug('Checking for existing account in RhodeCode '
303 'database with user_id `%s` ', updating_user_id)
303 'database with user_id `%s` ', updating_user_id)
304 user = User.get(updating_user_id)
304 user = User.get(updating_user_id)
305 else:
305 else:
306 log.debug('Checking for existing account in RhodeCode '
306 log.debug('Checking for existing account in RhodeCode '
307 'database with username `%s` ', username)
307 'database with username `%s` ', username)
308 user = User.get_by_username(username, case_insensitive=True)
308 user = User.get_by_username(username, case_insensitive=True)
309
309
310 if user is None:
310 if user is None:
311 # we check internal flag if this method is actually allowed to
311 # we check internal flag if this method is actually allowed to
312 # create new user
312 # create new user
313 if not allow_to_create_user:
313 if not allow_to_create_user:
314 msg = ('Method wants to create new user, but it is not '
314 msg = ('Method wants to create new user, but it is not '
315 'allowed to do so')
315 'allowed to do so')
316 log.warning(msg)
316 log.warning(msg)
317 raise NotAllowedToCreateUserError(msg)
317 raise NotAllowedToCreateUserError(msg)
318
318
319 log.debug('Creating new user %s', username)
319 log.debug('Creating new user %s', username)
320
320
321 # only if we create user that is active
321 # only if we create user that is active
322 new_active_user = active
322 new_active_user = active
323 if new_active_user and strict_creation_check:
323 if new_active_user and strict_creation_check:
324 # raises UserCreationError if it's not allowed for any reason to
324 # raises UserCreationError if it's not allowed for any reason to
325 # create new active user, this also executes pre-create hooks
325 # create new active user, this also executes pre-create hooks
326 check_allowed_create_user(user_data, cur_user, strict_check=True)
326 check_allowed_create_user(user_data, cur_user, strict_check=True)
327 events.trigger(events.UserPreCreate(user_data))
327 events.trigger(events.UserPreCreate(user_data))
328 new_user = User()
328 new_user = User()
329 edit = False
329 edit = False
330 else:
330 else:
331 log.debug('updating user `%s`', username)
331 log.debug('updating user `%s`', username)
332 events.trigger(events.UserPreUpdate(user, user_data))
332 events.trigger(events.UserPreUpdate(user, user_data))
333 new_user = user
333 new_user = user
334 edit = True
334 edit = True
335
335
336 # we're not allowed to edit default user
336 # we're not allowed to edit default user
337 if user.username == User.DEFAULT_USER:
337 if user.username == User.DEFAULT_USER:
338 raise DefaultUserException(
338 raise DefaultUserException(
339 "You can't edit this user (`%(username)s`) since it's "
339 "You can't edit this user (`%(username)s`) since it's "
340 "crucial for entire application"
340 "crucial for entire application"
341 % {'username': user.username})
341 % {'username': user.username})
342
342
343 # inject special attribute that will tell us if User is new or old
343 # inject special attribute that will tell us if User is new or old
344 new_user.is_new_user = not edit
344 new_user.is_new_user = not edit
345 # for users that didn's specify auth type, we use RhodeCode built in
345 # for users that didn's specify auth type, we use RhodeCode built in
346 from rhodecode.authentication.plugins import auth_rhodecode
346 from rhodecode.authentication.plugins import auth_rhodecode
347 extern_name = extern_name or auth_rhodecode.RhodeCodeAuthPlugin.uid
347 extern_name = extern_name or auth_rhodecode.RhodeCodeAuthPlugin.uid
348 extern_type = extern_type or auth_rhodecode.RhodeCodeAuthPlugin.uid
348 extern_type = extern_type or auth_rhodecode.RhodeCodeAuthPlugin.uid
349
349
350 try:
350 try:
351 new_user.username = username
351 new_user.username = username
352 new_user.admin = admin
352 new_user.admin = admin
353 new_user.email = email
353 new_user.email = email
354 new_user.active = active
354 new_user.active = active
355 new_user.extern_name = safe_unicode(extern_name)
355 new_user.extern_name = safe_unicode(extern_name)
356 new_user.extern_type = safe_unicode(extern_type)
356 new_user.extern_type = safe_unicode(extern_type)
357 new_user.name = firstname
357 new_user.name = firstname
358 new_user.lastname = lastname
358 new_user.lastname = lastname
359
359
360 # set password only if creating an user or password is changed
360 # set password only if creating an user or password is changed
361 if not edit or _password_change(new_user, password):
361 if not edit or _password_change(new_user, password):
362 reason = 'new password' if edit else 'new user'
362 reason = 'new password' if edit else 'new user'
363 log.debug('Updating password reason=>%s', reason)
363 log.debug('Updating password reason=>%s', reason)
364 new_user.password = get_crypt_password(password) if password else None
364 new_user.password = get_crypt_password(password) if password else None
365
365
366 if force_password_change:
366 if force_password_change:
367 new_user.update_userdata(force_password_change=True)
367 new_user.update_userdata(force_password_change=True)
368 if language:
368 if language:
369 new_user.update_userdata(language=language)
369 new_user.update_userdata(language=language)
370 new_user.update_userdata(notification_status=True)
370 new_user.update_userdata(notification_status=True)
371
371
372 self.sa.add(new_user)
372 self.sa.add(new_user)
373
373
374 if not edit and create_repo_group:
374 if not edit and create_repo_group:
375 RepoGroupModel().create_personal_repo_group(
375 RepoGroupModel().create_personal_repo_group(
376 new_user, commit_early=False)
376 new_user, commit_early=False)
377
377
378 if not edit:
378 if not edit:
379 # add the RSS token
379 # add the RSS token
380 self.add_auth_token(
380 self.add_auth_token(
381 user=username, lifetime_minutes=-1,
381 user=username, lifetime_minutes=-1,
382 role=self.auth_token_role.ROLE_FEED,
382 role=self.auth_token_role.ROLE_FEED,
383 description=u'Generated feed token')
383 description=u'Generated feed token')
384
384
385 kwargs = new_user.get_dict()
385 kwargs = new_user.get_dict()
386 # backward compat, require api_keys present
386 # backward compat, require api_keys present
387 kwargs['api_keys'] = kwargs['auth_tokens']
387 kwargs['api_keys'] = kwargs['auth_tokens']
388 log_create_user(created_by=cur_user, **kwargs)
388 log_create_user(created_by=cur_user, **kwargs)
389 events.trigger(events.UserPostCreate(user_data))
389 events.trigger(events.UserPostCreate(user_data))
390 return new_user
390 return new_user
391 except (DatabaseError,):
391 except (DatabaseError,):
392 log.error(traceback.format_exc())
392 log.error(traceback.format_exc())
393 raise
393 raise
394
394
395 def create_registration(self, form_data,
395 def create_registration(self, form_data,
396 extern_name='rhodecode', extern_type='rhodecode'):
396 extern_name='rhodecode', extern_type='rhodecode'):
397 from rhodecode.model.notification import NotificationModel
397 from rhodecode.model.notification import NotificationModel
398 from rhodecode.model.notification import EmailNotificationModel
398 from rhodecode.model.notification import EmailNotificationModel
399
399
400 try:
400 try:
401 form_data['admin'] = False
401 form_data['admin'] = False
402 form_data['extern_name'] = extern_name
402 form_data['extern_name'] = extern_name
403 form_data['extern_type'] = extern_type
403 form_data['extern_type'] = extern_type
404 new_user = self.create(form_data)
404 new_user = self.create(form_data)
405
405
406 self.sa.add(new_user)
406 self.sa.add(new_user)
407 self.sa.flush()
407 self.sa.flush()
408
408
409 user_data = new_user.get_dict()
409 user_data = new_user.get_dict()
410 kwargs = {
410 kwargs = {
411 # use SQLALCHEMY safe dump of user data
411 # use SQLALCHEMY safe dump of user data
412 'user': AttributeDict(user_data),
412 'user': AttributeDict(user_data),
413 'date': datetime.datetime.now()
413 'date': datetime.datetime.now()
414 }
414 }
415 notification_type = EmailNotificationModel.TYPE_REGISTRATION
415 notification_type = EmailNotificationModel.TYPE_REGISTRATION
416 # pre-generate the subject for notification itself
416 # pre-generate the subject for notification itself
417 (subject,
417 (subject,
418 _h, _e, # we don't care about those
418 _h, _e, # we don't care about those
419 body_plaintext) = EmailNotificationModel().render_email(
419 body_plaintext) = EmailNotificationModel().render_email(
420 notification_type, **kwargs)
420 notification_type, **kwargs)
421
421
422 # create notification objects, and emails
422 # create notification objects, and emails
423 NotificationModel().create(
423 NotificationModel().create(
424 created_by=new_user,
424 created_by=new_user,
425 notification_subject=subject,
425 notification_subject=subject,
426 notification_body=body_plaintext,
426 notification_body=body_plaintext,
427 notification_type=notification_type,
427 notification_type=notification_type,
428 recipients=None, # all admins
428 recipients=None, # all admins
429 email_kwargs=kwargs,
429 email_kwargs=kwargs,
430 )
430 )
431
431
432 return new_user
432 return new_user
433 except Exception:
433 except Exception:
434 log.error(traceback.format_exc())
434 log.error(traceback.format_exc())
435 raise
435 raise
436
436
437 def _handle_user_repos(self, username, repositories, handle_mode=None):
437 def _handle_user_repos(self, username, repositories, handle_mode=None):
438 _superadmin = self.cls.get_first_super_admin()
438 _superadmin = self.cls.get_first_super_admin()
439 left_overs = True
439 left_overs = True
440
440
441 from rhodecode.model.repo import RepoModel
441 from rhodecode.model.repo import RepoModel
442
442
443 if handle_mode == 'detach':
443 if handle_mode == 'detach':
444 for obj in repositories:
444 for obj in repositories:
445 obj.user = _superadmin
445 obj.user = _superadmin
446 # set description we know why we super admin now owns
446 # set description we know why we super admin now owns
447 # additional repositories that were orphaned !
447 # additional repositories that were orphaned !
448 obj.description += ' \n::detached repository from deleted user: %s' % (username,)
448 obj.description += ' \n::detached repository from deleted user: %s' % (username,)
449 self.sa.add(obj)
449 self.sa.add(obj)
450 left_overs = False
450 left_overs = False
451 elif handle_mode == 'delete':
451 elif handle_mode == 'delete':
452 for obj in repositories:
452 for obj in repositories:
453 RepoModel().delete(obj, forks='detach')
453 RepoModel().delete(obj, forks='detach')
454 left_overs = False
454 left_overs = False
455
455
456 # if nothing is done we have left overs left
456 # if nothing is done we have left overs left
457 return left_overs
457 return left_overs
458
458
459 def _handle_user_repo_groups(self, username, repository_groups,
459 def _handle_user_repo_groups(self, username, repository_groups,
460 handle_mode=None):
460 handle_mode=None):
461 _superadmin = self.cls.get_first_super_admin()
461 _superadmin = self.cls.get_first_super_admin()
462 left_overs = True
462 left_overs = True
463
463
464 from rhodecode.model.repo_group import RepoGroupModel
464 from rhodecode.model.repo_group import RepoGroupModel
465
465
466 if handle_mode == 'detach':
466 if handle_mode == 'detach':
467 for r in repository_groups:
467 for r in repository_groups:
468 r.user = _superadmin
468 r.user = _superadmin
469 # set description we know why we super admin now owns
469 # set description we know why we super admin now owns
470 # additional repositories that were orphaned !
470 # additional repositories that were orphaned !
471 r.group_description += ' \n::detached repository group from deleted user: %s' % (username,)
471 r.group_description += ' \n::detached repository group from deleted user: %s' % (username,)
472 r.personal = False
472 r.personal = False
473 self.sa.add(r)
473 self.sa.add(r)
474 left_overs = False
474 left_overs = False
475 elif handle_mode == 'delete':
475 elif handle_mode == 'delete':
476 for r in repository_groups:
476 for r in repository_groups:
477 RepoGroupModel().delete(r)
477 RepoGroupModel().delete(r)
478 left_overs = False
478 left_overs = False
479
479
480 # if nothing is done we have left overs left
480 # if nothing is done we have left overs left
481 return left_overs
481 return left_overs
482
482
483 def _handle_user_user_groups(self, username, user_groups, handle_mode=None):
483 def _handle_user_user_groups(self, username, user_groups, handle_mode=None):
484 _superadmin = self.cls.get_first_super_admin()
484 _superadmin = self.cls.get_first_super_admin()
485 left_overs = True
485 left_overs = True
486
486
487 from rhodecode.model.user_group import UserGroupModel
487 from rhodecode.model.user_group import UserGroupModel
488
488
489 if handle_mode == 'detach':
489 if handle_mode == 'detach':
490 for r in user_groups:
490 for r in user_groups:
491 for user_user_group_to_perm in r.user_user_group_to_perm:
491 for user_user_group_to_perm in r.user_user_group_to_perm:
492 if user_user_group_to_perm.user.username == username:
492 if user_user_group_to_perm.user.username == username:
493 user_user_group_to_perm.user = _superadmin
493 user_user_group_to_perm.user = _superadmin
494 r.user = _superadmin
494 r.user = _superadmin
495 # set description we know why we super admin now owns
495 # set description we know why we super admin now owns
496 # additional repositories that were orphaned !
496 # additional repositories that were orphaned !
497 r.user_group_description += ' \n::detached user group from deleted user: %s' % (username,)
497 r.user_group_description += ' \n::detached user group from deleted user: %s' % (username,)
498 self.sa.add(r)
498 self.sa.add(r)
499 left_overs = False
499 left_overs = False
500 elif handle_mode == 'delete':
500 elif handle_mode == 'delete':
501 for r in user_groups:
501 for r in user_groups:
502 UserGroupModel().delete(r)
502 UserGroupModel().delete(r)
503 left_overs = False
503 left_overs = False
504
504
505 # if nothing is done we have left overs left
505 # if nothing is done we have left overs left
506 return left_overs
506 return left_overs
507
507
508 def _handle_user_artifacts(self, username, artifacts, handle_mode=None):
508 def _handle_user_artifacts(self, username, artifacts, handle_mode=None):
509 _superadmin = self.cls.get_first_super_admin()
509 _superadmin = self.cls.get_first_super_admin()
510 left_overs = True
510 left_overs = True
511
511
512 if handle_mode == 'detach':
512 if handle_mode == 'detach':
513 for a in artifacts:
513 for a in artifacts:
514 a.upload_user = _superadmin
514 a.upload_user = _superadmin
515 # set description we know why we super admin now owns
515 # set description we know why we super admin now owns
516 # additional artifacts that were orphaned !
516 # additional artifacts that were orphaned !
517 a.file_description += ' \n::detached artifact from deleted user: %s' % (username,)
517 a.file_description += ' \n::detached artifact from deleted user: %s' % (username,)
518 self.sa.add(a)
518 self.sa.add(a)
519 left_overs = False
519 left_overs = False
520 elif handle_mode == 'delete':
520 elif handle_mode == 'delete':
521 from rhodecode.apps.file_store import utils as store_utils
521 from rhodecode.apps.file_store import utils as store_utils
522 storage = store_utils.get_file_storage(self.request.registry.settings)
522 storage = store_utils.get_file_storage(self.request.registry.settings)
523 for a in artifacts:
523 for a in artifacts:
524 file_uid = a.file_uid
524 file_uid = a.file_uid
525 storage.delete(file_uid)
525 storage.delete(file_uid)
526 self.sa.delete(a)
526 self.sa.delete(a)
527
527
528 left_overs = False
528 left_overs = False
529
529
530 # if nothing is done we have left overs left
530 # if nothing is done we have left overs left
531 return left_overs
531 return left_overs
532
532
533 def delete(self, user, cur_user=None, handle_repos=None,
533 def delete(self, user, cur_user=None, handle_repos=None,
534 handle_repo_groups=None, handle_user_groups=None, handle_artifacts=None):
534 handle_repo_groups=None, handle_user_groups=None, handle_artifacts=None):
535 from rhodecode.lib.hooks_base import log_delete_user
535 from rhodecode.lib.hooks_base import log_delete_user
536
536
537 if not cur_user:
537 if not cur_user:
538 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
538 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
539 user = self._get_user(user)
539 user = self._get_user(user)
540
540
541 try:
541 try:
542 if user.username == User.DEFAULT_USER:
542 if user.username == User.DEFAULT_USER:
543 raise DefaultUserException(
543 raise DefaultUserException(
544 u"You can't remove this user since it's"
544 u"You can't remove this user since it's"
545 u" crucial for entire application")
545 u" crucial for entire application")
546
546
547 left_overs = self._handle_user_repos(
547 left_overs = self._handle_user_repos(
548 user.username, user.repositories, handle_repos)
548 user.username, user.repositories, handle_repos)
549 if left_overs and user.repositories:
549 if left_overs and user.repositories:
550 repos = [x.repo_name for x in user.repositories]
550 repos = [x.repo_name for x in user.repositories]
551 raise UserOwnsReposException(
551 raise UserOwnsReposException(
552 u'user "%(username)s" still owns %(len_repos)s repositories and cannot be '
552 u'user "%(username)s" still owns %(len_repos)s repositories and cannot be '
553 u'removed. Switch owners or remove those repositories:%(list_repos)s'
553 u'removed. Switch owners or remove those repositories:%(list_repos)s'
554 % {'username': user.username, 'len_repos': len(repos),
554 % {'username': user.username, 'len_repos': len(repos),
555 'list_repos': ', '.join(repos)})
555 'list_repos': ', '.join(repos)})
556
556
557 left_overs = self._handle_user_repo_groups(
557 left_overs = self._handle_user_repo_groups(
558 user.username, user.repository_groups, handle_repo_groups)
558 user.username, user.repository_groups, handle_repo_groups)
559 if left_overs and user.repository_groups:
559 if left_overs and user.repository_groups:
560 repo_groups = [x.group_name for x in user.repository_groups]
560 repo_groups = [x.group_name for x in user.repository_groups]
561 raise UserOwnsRepoGroupsException(
561 raise UserOwnsRepoGroupsException(
562 u'user "%(username)s" still owns %(len_repo_groups)s repository groups and cannot be '
562 u'user "%(username)s" still owns %(len_repo_groups)s repository groups and cannot be '
563 u'removed. Switch owners or remove those repository groups:%(list_repo_groups)s'
563 u'removed. Switch owners or remove those repository groups:%(list_repo_groups)s'
564 % {'username': user.username, 'len_repo_groups': len(repo_groups),
564 % {'username': user.username, 'len_repo_groups': len(repo_groups),
565 'list_repo_groups': ', '.join(repo_groups)})
565 'list_repo_groups': ', '.join(repo_groups)})
566
566
567 left_overs = self._handle_user_user_groups(
567 left_overs = self._handle_user_user_groups(
568 user.username, user.user_groups, handle_user_groups)
568 user.username, user.user_groups, handle_user_groups)
569 if left_overs and user.user_groups:
569 if left_overs and user.user_groups:
570 user_groups = [x.users_group_name for x in user.user_groups]
570 user_groups = [x.users_group_name for x in user.user_groups]
571 raise UserOwnsUserGroupsException(
571 raise UserOwnsUserGroupsException(
572 u'user "%s" still owns %s user groups and cannot be '
572 u'user "%s" still owns %s user groups and cannot be '
573 u'removed. Switch owners or remove those user groups:%s'
573 u'removed. Switch owners or remove those user groups:%s'
574 % (user.username, len(user_groups), ', '.join(user_groups)))
574 % (user.username, len(user_groups), ', '.join(user_groups)))
575
575
576 left_overs = self._handle_user_artifacts(
576 left_overs = self._handle_user_artifacts(
577 user.username, user.artifacts, handle_artifacts)
577 user.username, user.artifacts, handle_artifacts)
578 if left_overs and user.artifacts:
578 if left_overs and user.artifacts:
579 artifacts = [x.file_uid for x in user.artifacts]
579 artifacts = [x.file_uid for x in user.artifacts]
580 raise UserOwnsArtifactsException(
580 raise UserOwnsArtifactsException(
581 u'user "%s" still owns %s artifacts and cannot be '
581 u'user "%s" still owns %s artifacts and cannot be '
582 u'removed. Switch owners or remove those artifacts:%s'
582 u'removed. Switch owners or remove those artifacts:%s'
583 % (user.username, len(artifacts), ', '.join(artifacts)))
583 % (user.username, len(artifacts), ', '.join(artifacts)))
584
584
585 user_data = user.get_dict() # fetch user data before expire
585 user_data = user.get_dict() # fetch user data before expire
586
586
587 # we might change the user data with detach/delete, make sure
587 # we might change the user data with detach/delete, make sure
588 # the object is marked as expired before actually deleting !
588 # the object is marked as expired before actually deleting !
589 self.sa.expire(user)
589 self.sa.expire(user)
590 self.sa.delete(user)
590 self.sa.delete(user)
591
591
592 log_delete_user(deleted_by=cur_user, **user_data)
592 log_delete_user(deleted_by=cur_user, **user_data)
593 except Exception:
593 except Exception:
594 log.error(traceback.format_exc())
594 log.error(traceback.format_exc())
595 raise
595 raise
596
596
597 def reset_password_link(self, data, pwd_reset_url):
597 def reset_password_link(self, data, pwd_reset_url):
598 from rhodecode.lib.celerylib import tasks, run_task
598 from rhodecode.lib.celerylib import tasks, run_task
599 from rhodecode.model.notification import EmailNotificationModel
599 from rhodecode.model.notification import EmailNotificationModel
600 user_email = data['email']
600 user_email = data['email']
601 try:
601 try:
602 user = User.get_by_email(user_email)
602 user = User.get_by_email(user_email)
603 if user:
603 if user:
604 log.debug('password reset user found %s', user)
604 log.debug('password reset user found %s', user)
605
605
606 email_kwargs = {
606 email_kwargs = {
607 'password_reset_url': pwd_reset_url,
607 'password_reset_url': pwd_reset_url,
608 'user': user,
608 'user': user,
609 'email': user_email,
609 'email': user_email,
610 'date': datetime.datetime.now()
610 'date': datetime.datetime.now()
611 }
611 }
612
612
613 (subject, headers, email_body,
613 (subject, headers, email_body,
614 email_body_plaintext) = EmailNotificationModel().render_email(
614 email_body_plaintext) = EmailNotificationModel().render_email(
615 EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs)
615 EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs)
616
616
617 recipients = [user_email]
617 recipients = [user_email]
618
618
619 action_logger_generic(
619 action_logger_generic(
620 'sending password reset email to user: {}'.format(
620 'sending password reset email to user: {}'.format(
621 user), namespace='security.password_reset')
621 user), namespace='security.password_reset')
622
622
623 run_task(tasks.send_email, recipients, subject,
623 run_task(tasks.send_email, recipients, subject,
624 email_body_plaintext, email_body)
624 email_body_plaintext, email_body)
625
625
626 else:
626 else:
627 log.debug("password reset email %s not found", user_email)
627 log.debug("password reset email %s not found", user_email)
628 except Exception:
628 except Exception:
629 log.error(traceback.format_exc())
629 log.error(traceback.format_exc())
630 return False
630 return False
631
631
632 return True
632 return True
633
633
634 def reset_password(self, data):
634 def reset_password(self, data):
635 from rhodecode.lib.celerylib import tasks, run_task
635 from rhodecode.lib.celerylib import tasks, run_task
636 from rhodecode.model.notification import EmailNotificationModel
636 from rhodecode.model.notification import EmailNotificationModel
637 from rhodecode.lib import auth
637 from rhodecode.lib import auth
638 user_email = data['email']
638 user_email = data['email']
639 pre_db = True
639 pre_db = True
640 try:
640 try:
641 user = User.get_by_email(user_email)
641 user = User.get_by_email(user_email)
642 new_passwd = auth.PasswordGenerator().gen_password(
642 new_passwd = auth.PasswordGenerator().gen_password(
643 12, auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
643 12, auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
644 if user:
644 if user:
645 user.password = auth.get_crypt_password(new_passwd)
645 user.password = auth.get_crypt_password(new_passwd)
646 # also force this user to reset his password !
646 # also force this user to reset his password !
647 user.update_userdata(force_password_change=True)
647 user.update_userdata(force_password_change=True)
648
648
649 Session().add(user)
649 Session().add(user)
650
650
651 # now delete the token in question
651 # now delete the token in question
652 UserApiKeys = AuthTokenModel.cls
652 UserApiKeys = AuthTokenModel.cls
653 UserApiKeys().query().filter(
653 UserApiKeys().query().filter(
654 UserApiKeys.api_key == data['token']).delete()
654 UserApiKeys.api_key == data['token']).delete()
655
655
656 Session().commit()
656 Session().commit()
657 log.info('successfully reset password for `%s`', user_email)
657 log.info('successfully reset password for `%s`', user_email)
658
658
659 if new_passwd is None:
659 if new_passwd is None:
660 raise Exception('unable to generate new password')
660 raise Exception('unable to generate new password')
661
661
662 pre_db = False
662 pre_db = False
663
663
664 email_kwargs = {
664 email_kwargs = {
665 'new_password': new_passwd,
665 'new_password': new_passwd,
666 'user': user,
666 'user': user,
667 'email': user_email,
667 'email': user_email,
668 'date': datetime.datetime.now()
668 'date': datetime.datetime.now()
669 }
669 }
670
670
671 (subject, headers, email_body,
671 (subject, headers, email_body,
672 email_body_plaintext) = EmailNotificationModel().render_email(
672 email_body_plaintext) = EmailNotificationModel().render_email(
673 EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION,
673 EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION,
674 **email_kwargs)
674 **email_kwargs)
675
675
676 recipients = [user_email]
676 recipients = [user_email]
677
677
678 action_logger_generic(
678 action_logger_generic(
679 'sent new password to user: {} with email: {}'.format(
679 'sent new password to user: {} with email: {}'.format(
680 user, user_email), namespace='security.password_reset')
680 user, user_email), namespace='security.password_reset')
681
681
682 run_task(tasks.send_email, recipients, subject,
682 run_task(tasks.send_email, recipients, subject,
683 email_body_plaintext, email_body)
683 email_body_plaintext, email_body)
684
684
685 except Exception:
685 except Exception:
686 log.error('Failed to update user password')
686 log.error('Failed to update user password')
687 log.error(traceback.format_exc())
687 log.error(traceback.format_exc())
688 if pre_db:
688 if pre_db:
689 # we rollback only if local db stuff fails. If it goes into
689 # we rollback only if local db stuff fails. If it goes into
690 # run_task, we're pass rollback state this wouldn't work then
690 # run_task, we're pass rollback state this wouldn't work then
691 Session().rollback()
691 Session().rollback()
692
692
693 return True
693 return True
694
694
695 def fill_data(self, auth_user, user_id=None, api_key=None, username=None):
695 def fill_data(self, auth_user, user_id=None, api_key=None, username=None):
696 """
696 """
697 Fetches auth_user by user_id,or api_key if present.
697 Fetches auth_user by user_id,or api_key if present.
698 Fills auth_user attributes with those taken from database.
698 Fills auth_user attributes with those taken from database.
699 Additionally set's is_authenitated if lookup fails
699 Additionally set's is_authenitated if lookup fails
700 present in database
700 present in database
701
701
702 :param auth_user: instance of user to set attributes
702 :param auth_user: instance of user to set attributes
703 :param user_id: user id to fetch by
703 :param user_id: user id to fetch by
704 :param api_key: api key to fetch by
704 :param api_key: api key to fetch by
705 :param username: username to fetch by
705 :param username: username to fetch by
706 """
706 """
707 def token_obfuscate(token):
707 def token_obfuscate(token):
708 if token:
708 if token:
709 return token[:4] + "****"
709 return token[:4] + "****"
710
710
711 if user_id is None and api_key is None and username is None:
711 if user_id is None and api_key is None and username is None:
712 raise Exception('You need to pass user_id, api_key or username')
712 raise Exception('You need to pass user_id, api_key or username')
713
713
714 log.debug(
714 log.debug(
715 'AuthUser: fill data execution based on: '
715 'AuthUser: fill data execution based on: '
716 'user_id:%s api_key:%s username:%s', user_id, api_key, username)
716 'user_id:%s api_key:%s username:%s', user_id, api_key, username)
717 try:
717 try:
718 dbuser = None
718 dbuser = None
719 if user_id:
719 if user_id:
720 dbuser = self.get(user_id)
720 dbuser = self.get(user_id)
721 elif api_key:
721 elif api_key:
722 dbuser = self.get_by_auth_token(api_key)
722 dbuser = self.get_by_auth_token(api_key)
723 elif username:
723 elif username:
724 dbuser = self.get_by_username(username)
724 dbuser = self.get_by_username(username)
725
725
726 if not dbuser:
726 if not dbuser:
727 log.warning(
727 log.warning(
728 'Unable to lookup user by id:%s api_key:%s username:%s',
728 'Unable to lookup user by id:%s api_key:%s username:%s',
729 user_id, token_obfuscate(api_key), username)
729 user_id, token_obfuscate(api_key), username)
730 return False
730 return False
731 if not dbuser.active:
731 if not dbuser.active:
732 log.debug('User `%s:%s` is inactive, skipping fill data',
732 log.debug('User `%s:%s` is inactive, skipping fill data',
733 username, user_id)
733 username, user_id)
734 return False
734 return False
735
735
736 log.debug('AuthUser: filling found user:%s data', dbuser)
736 log.debug('AuthUser: filling found user:%s data', dbuser)
737 user_data = dbuser.get_dict()
738
737
739 user_data.update({
738 attrs = {
740 # set explicit the safe escaped values
739 'user_id': dbuser.user_id,
740 'username': dbuser.username,
741 'name': dbuser.name,
741 'first_name': dbuser.first_name,
742 'first_name': dbuser.first_name,
743 'firstname': dbuser.firstname,
742 'last_name': dbuser.last_name,
744 'last_name': dbuser.last_name,
743 })
745 'lastname': dbuser.lastname,
746 'admin': dbuser.admin,
747 'active': dbuser.active,
748
749 'email': dbuser.email,
750 'emails': dbuser.emails_cached(),
751 'short_contact': dbuser.short_contact,
752 'full_contact': dbuser.full_contact,
753 'full_name': dbuser.full_name,
754 'full_name_or_username': dbuser.full_name_or_username,
744
755
745 for k, v in user_data.items():
756 '_api_key': dbuser._api_key,
746 # properties of auth user we dont update
757 '_user_data': dbuser._user_data,
747 if k not in ['auth_tokens', 'permissions']:
758
748 setattr(auth_user, k, v)
759 'created_on': dbuser.created_on,
760 'extern_name': dbuser.extern_name,
761 'extern_type': dbuser.extern_type,
749
762
763 'inherit_default_permissions': dbuser.inherit_default_permissions,
764
765 'language': dbuser.language,
766 'last_activity': dbuser.last_activity,
767 'last_login': dbuser.last_login,
768 'password': dbuser.password,
769 }
770 auth_user.__dict__.update(attrs)
750 except Exception:
771 except Exception:
751 log.error(traceback.format_exc())
772 log.error(traceback.format_exc())
752 auth_user.is_authenticated = False
773 auth_user.is_authenticated = False
753 return False
774 return False
754
775
755 return True
776 return True
756
777
757 def has_perm(self, user, perm):
778 def has_perm(self, user, perm):
758 perm = self._get_perm(perm)
779 perm = self._get_perm(perm)
759 user = self._get_user(user)
780 user = self._get_user(user)
760
781
761 return UserToPerm.query().filter(UserToPerm.user == user)\
782 return UserToPerm.query().filter(UserToPerm.user == user)\
762 .filter(UserToPerm.permission == perm).scalar() is not None
783 .filter(UserToPerm.permission == perm).scalar() is not None
763
784
764 def grant_perm(self, user, perm):
785 def grant_perm(self, user, perm):
765 """
786 """
766 Grant user global permissions
787 Grant user global permissions
767
788
768 :param user:
789 :param user:
769 :param perm:
790 :param perm:
770 """
791 """
771 user = self._get_user(user)
792 user = self._get_user(user)
772 perm = self._get_perm(perm)
793 perm = self._get_perm(perm)
773 # if this permission is already granted skip it
794 # if this permission is already granted skip it
774 _perm = UserToPerm.query()\
795 _perm = UserToPerm.query()\
775 .filter(UserToPerm.user == user)\
796 .filter(UserToPerm.user == user)\
776 .filter(UserToPerm.permission == perm)\
797 .filter(UserToPerm.permission == perm)\
777 .scalar()
798 .scalar()
778 if _perm:
799 if _perm:
779 return
800 return
780 new = UserToPerm()
801 new = UserToPerm()
781 new.user = user
802 new.user = user
782 new.permission = perm
803 new.permission = perm
783 self.sa.add(new)
804 self.sa.add(new)
784 return new
805 return new
785
806
786 def revoke_perm(self, user, perm):
807 def revoke_perm(self, user, perm):
787 """
808 """
788 Revoke users global permissions
809 Revoke users global permissions
789
810
790 :param user:
811 :param user:
791 :param perm:
812 :param perm:
792 """
813 """
793 user = self._get_user(user)
814 user = self._get_user(user)
794 perm = self._get_perm(perm)
815 perm = self._get_perm(perm)
795
816
796 obj = UserToPerm.query()\
817 obj = UserToPerm.query()\
797 .filter(UserToPerm.user == user)\
818 .filter(UserToPerm.user == user)\
798 .filter(UserToPerm.permission == perm)\
819 .filter(UserToPerm.permission == perm)\
799 .scalar()
820 .scalar()
800 if obj:
821 if obj:
801 self.sa.delete(obj)
822 self.sa.delete(obj)
802
823
803 def add_extra_email(self, user, email):
824 def add_extra_email(self, user, email):
804 """
825 """
805 Adds email address to UserEmailMap
826 Adds email address to UserEmailMap
806
827
807 :param user:
828 :param user:
808 :param email:
829 :param email:
809 """
830 """
810
831
811 user = self._get_user(user)
832 user = self._get_user(user)
812
833
813 obj = UserEmailMap()
834 obj = UserEmailMap()
814 obj.user = user
835 obj.user = user
815 obj.email = email
836 obj.email = email
816 self.sa.add(obj)
837 self.sa.add(obj)
817 return obj
838 return obj
818
839
819 def delete_extra_email(self, user, email_id):
840 def delete_extra_email(self, user, email_id):
820 """
841 """
821 Removes email address from UserEmailMap
842 Removes email address from UserEmailMap
822
843
823 :param user:
844 :param user:
824 :param email_id:
845 :param email_id:
825 """
846 """
826 user = self._get_user(user)
847 user = self._get_user(user)
827 obj = UserEmailMap.query().get(email_id)
848 obj = UserEmailMap.query().get(email_id)
828 if obj and obj.user_id == user.user_id:
849 if obj and obj.user_id == user.user_id:
829 self.sa.delete(obj)
850 self.sa.delete(obj)
830
851
831 def parse_ip_range(self, ip_range):
852 def parse_ip_range(self, ip_range):
832 ip_list = []
853 ip_list = []
833
854
834 def make_unique(value):
855 def make_unique(value):
835 seen = []
856 seen = []
836 return [c for c in value if not (c in seen or seen.append(c))]
857 return [c for c in value if not (c in seen or seen.append(c))]
837
858
838 # firsts split by commas
859 # firsts split by commas
839 for ip_range in ip_range.split(','):
860 for ip_range in ip_range.split(','):
840 if not ip_range:
861 if not ip_range:
841 continue
862 continue
842 ip_range = ip_range.strip()
863 ip_range = ip_range.strip()
843 if '-' in ip_range:
864 if '-' in ip_range:
844 start_ip, end_ip = ip_range.split('-', 1)
865 start_ip, end_ip = ip_range.split('-', 1)
845 start_ip = ipaddress.ip_address(safe_unicode(start_ip.strip()))
866 start_ip = ipaddress.ip_address(safe_unicode(start_ip.strip()))
846 end_ip = ipaddress.ip_address(safe_unicode(end_ip.strip()))
867 end_ip = ipaddress.ip_address(safe_unicode(end_ip.strip()))
847 parsed_ip_range = []
868 parsed_ip_range = []
848
869
849 for index in xrange(int(start_ip), int(end_ip) + 1):
870 for index in xrange(int(start_ip), int(end_ip) + 1):
850 new_ip = ipaddress.ip_address(index)
871 new_ip = ipaddress.ip_address(index)
851 parsed_ip_range.append(str(new_ip))
872 parsed_ip_range.append(str(new_ip))
852 ip_list.extend(parsed_ip_range)
873 ip_list.extend(parsed_ip_range)
853 else:
874 else:
854 ip_list.append(ip_range)
875 ip_list.append(ip_range)
855
876
856 return make_unique(ip_list)
877 return make_unique(ip_list)
857
878
858 def add_extra_ip(self, user, ip, description=None):
879 def add_extra_ip(self, user, ip, description=None):
859 """
880 """
860 Adds ip address to UserIpMap
881 Adds ip address to UserIpMap
861
882
862 :param user:
883 :param user:
863 :param ip:
884 :param ip:
864 """
885 """
865
886
866 user = self._get_user(user)
887 user = self._get_user(user)
867 obj = UserIpMap()
888 obj = UserIpMap()
868 obj.user = user
889 obj.user = user
869 obj.ip_addr = ip
890 obj.ip_addr = ip
870 obj.description = description
891 obj.description = description
871 self.sa.add(obj)
892 self.sa.add(obj)
872 return obj
893 return obj
873
894
874 auth_token_role = AuthTokenModel.cls
895 auth_token_role = AuthTokenModel.cls
875
896
876 def add_auth_token(self, user, lifetime_minutes, role, description=u'',
897 def add_auth_token(self, user, lifetime_minutes, role, description=u'',
877 scope_callback=None):
898 scope_callback=None):
878 """
899 """
879 Add AuthToken for user.
900 Add AuthToken for user.
880
901
881 :param user: username/user_id
902 :param user: username/user_id
882 :param lifetime_minutes: in minutes the lifetime for token, -1 equals no limit
903 :param lifetime_minutes: in minutes the lifetime for token, -1 equals no limit
883 :param role: one of AuthTokenModel.cls.ROLE_*
904 :param role: one of AuthTokenModel.cls.ROLE_*
884 :param description: optional string description
905 :param description: optional string description
885 """
906 """
886
907
887 token = AuthTokenModel().create(
908 token = AuthTokenModel().create(
888 user, description, lifetime_minutes, role)
909 user, description, lifetime_minutes, role)
889 if scope_callback and callable(scope_callback):
910 if scope_callback and callable(scope_callback):
890 # call the callback if we provide, used to attach scope for EE edition
911 # call the callback if we provide, used to attach scope for EE edition
891 scope_callback(token)
912 scope_callback(token)
892 return token
913 return token
893
914
894 def delete_extra_ip(self, user, ip_id):
915 def delete_extra_ip(self, user, ip_id):
895 """
916 """
896 Removes ip address from UserIpMap
917 Removes ip address from UserIpMap
897
918
898 :param user:
919 :param user:
899 :param ip_id:
920 :param ip_id:
900 """
921 """
901 user = self._get_user(user)
922 user = self._get_user(user)
902 obj = UserIpMap.query().get(ip_id)
923 obj = UserIpMap.query().get(ip_id)
903 if obj and obj.user_id == user.user_id:
924 if obj and obj.user_id == user.user_id:
904 self.sa.delete(obj)
925 self.sa.delete(obj)
905
926
906 def get_accounts_in_creation_order(self, current_user=None):
927 def get_accounts_in_creation_order(self, current_user=None):
907 """
928 """
908 Get accounts in order of creation for deactivation for license limits
929 Get accounts in order of creation for deactivation for license limits
909
930
910 pick currently logged in user, and append to the list in position 0
931 pick currently logged in user, and append to the list in position 0
911 pick all super-admins in order of creation date and add it to the list
932 pick all super-admins in order of creation date and add it to the list
912 pick all other accounts in order of creation and add it to the list.
933 pick all other accounts in order of creation and add it to the list.
913
934
914 Based on that list, the last accounts can be disabled as they are
935 Based on that list, the last accounts can be disabled as they are
915 created at the end and don't include any of the super admins as well
936 created at the end and don't include any of the super admins as well
916 as the current user.
937 as the current user.
917
938
918 :param current_user: optionally current user running this operation
939 :param current_user: optionally current user running this operation
919 """
940 """
920
941
921 if not current_user:
942 if not current_user:
922 current_user = get_current_rhodecode_user()
943 current_user = get_current_rhodecode_user()
923 active_super_admins = [
944 active_super_admins = [
924 x.user_id for x in User.query()
945 x.user_id for x in User.query()
925 .filter(User.user_id != current_user.user_id)
946 .filter(User.user_id != current_user.user_id)
926 .filter(User.active == true())
947 .filter(User.active == true())
927 .filter(User.admin == true())
948 .filter(User.admin == true())
928 .order_by(User.created_on.asc())]
949 .order_by(User.created_on.asc())]
929
950
930 active_regular_users = [
951 active_regular_users = [
931 x.user_id for x in User.query()
952 x.user_id for x in User.query()
932 .filter(User.user_id != current_user.user_id)
953 .filter(User.user_id != current_user.user_id)
933 .filter(User.active == true())
954 .filter(User.active == true())
934 .filter(User.admin == false())
955 .filter(User.admin == false())
935 .order_by(User.created_on.asc())]
956 .order_by(User.created_on.asc())]
936
957
937 list_of_accounts = [current_user.user_id]
958 list_of_accounts = [current_user.user_id]
938 list_of_accounts += active_super_admins
959 list_of_accounts += active_super_admins
939 list_of_accounts += active_regular_users
960 list_of_accounts += active_regular_users
940
961
941 return list_of_accounts
962 return list_of_accounts
942
963
943 def deactivate_last_users(self, expected_users, current_user=None):
964 def deactivate_last_users(self, expected_users, current_user=None):
944 """
965 """
945 Deactivate accounts that are over the license limits.
966 Deactivate accounts that are over the license limits.
946 Algorithm of which accounts to disabled is based on the formula:
967 Algorithm of which accounts to disabled is based on the formula:
947
968
948 Get current user, then super admins in creation order, then regular
969 Get current user, then super admins in creation order, then regular
949 active users in creation order.
970 active users in creation order.
950
971
951 Using that list we mark all accounts from the end of it as inactive.
972 Using that list we mark all accounts from the end of it as inactive.
952 This way we block only latest created accounts.
973 This way we block only latest created accounts.
953
974
954 :param expected_users: list of users in special order, we deactivate
975 :param expected_users: list of users in special order, we deactivate
955 the end N amount of users from that list
976 the end N amount of users from that list
956 """
977 """
957
978
958 list_of_accounts = self.get_accounts_in_creation_order(
979 list_of_accounts = self.get_accounts_in_creation_order(
959 current_user=current_user)
980 current_user=current_user)
960
981
961 for acc_id in list_of_accounts[expected_users + 1:]:
982 for acc_id in list_of_accounts[expected_users + 1:]:
962 user = User.get(acc_id)
983 user = User.get(acc_id)
963 log.info('Deactivating account %s for license unlock', user)
984 log.info('Deactivating account %s for license unlock', user)
964 user.active = False
985 user.active = False
965 Session().add(user)
986 Session().add(user)
966 Session().commit()
987 Session().commit()
967
988
968 return
989 return
969
990
970 def get_user_log(self, user, filter_term):
991 def get_user_log(self, user, filter_term):
971 user_log = UserLog.query()\
992 user_log = UserLog.query()\
972 .filter(or_(UserLog.user_id == user.user_id,
993 .filter(or_(UserLog.user_id == user.user_id,
973 UserLog.username == user.username))\
994 UserLog.username == user.username))\
974 .options(joinedload(UserLog.user))\
995 .options(joinedload(UserLog.user))\
975 .options(joinedload(UserLog.repository))\
996 .options(joinedload(UserLog.repository))\
976 .order_by(UserLog.action_date.desc())
997 .order_by(UserLog.action_date.desc())
977
998
978 user_log = user_log_filter(user_log, filter_term)
999 user_log = user_log_filter(user_log, filter_term)
979 return user_log
1000 return user_log
General Comments 0
You need to be logged in to leave comments. Login now