##// END OF EJS Templates
logs: fix leaking of tokens to logging. Fixes #5452
marcink -
r2657:98ca006e default
parent child Browse files
Show More
@@ -1,914 +1,918 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 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)
40 UserOwnsUserGroupsException, NotAllowedToCreateUserError)
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.name
347 extern_name = extern_name or auth_rhodecode.RhodeCodeAuthPlugin.name
348 extern_type = extern_type or auth_rhodecode.RhodeCodeAuthPlugin.name
348 extern_type = extern_type or auth_rhodecode.RhodeCodeAuthPlugin.name
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 AuthTokenModel().create(username,
380 AuthTokenModel().create(username,
381 description=u'Generated feed token',
381 description=u'Generated feed token',
382 role=AuthTokenModel.cls.ROLE_FEED)
382 role=AuthTokenModel.cls.ROLE_FEED)
383 kwargs = new_user.get_dict()
383 kwargs = new_user.get_dict()
384 # backward compat, require api_keys present
384 # backward compat, require api_keys present
385 kwargs['api_keys'] = kwargs['auth_tokens']
385 kwargs['api_keys'] = kwargs['auth_tokens']
386 log_create_user(created_by=cur_user, **kwargs)
386 log_create_user(created_by=cur_user, **kwargs)
387 events.trigger(events.UserPostCreate(user_data))
387 events.trigger(events.UserPostCreate(user_data))
388 return new_user
388 return new_user
389 except (DatabaseError,):
389 except (DatabaseError,):
390 log.error(traceback.format_exc())
390 log.error(traceback.format_exc())
391 raise
391 raise
392
392
393 def create_registration(self, form_data):
393 def create_registration(self, form_data):
394 from rhodecode.model.notification import NotificationModel
394 from rhodecode.model.notification import NotificationModel
395 from rhodecode.model.notification import EmailNotificationModel
395 from rhodecode.model.notification import EmailNotificationModel
396
396
397 try:
397 try:
398 form_data['admin'] = False
398 form_data['admin'] = False
399 form_data['extern_name'] = 'rhodecode'
399 form_data['extern_name'] = 'rhodecode'
400 form_data['extern_type'] = 'rhodecode'
400 form_data['extern_type'] = 'rhodecode'
401 new_user = self.create(form_data)
401 new_user = self.create(form_data)
402
402
403 self.sa.add(new_user)
403 self.sa.add(new_user)
404 self.sa.flush()
404 self.sa.flush()
405
405
406 user_data = new_user.get_dict()
406 user_data = new_user.get_dict()
407 kwargs = {
407 kwargs = {
408 # use SQLALCHEMY safe dump of user data
408 # use SQLALCHEMY safe dump of user data
409 'user': AttributeDict(user_data),
409 'user': AttributeDict(user_data),
410 'date': datetime.datetime.now()
410 'date': datetime.datetime.now()
411 }
411 }
412 notification_type = EmailNotificationModel.TYPE_REGISTRATION
412 notification_type = EmailNotificationModel.TYPE_REGISTRATION
413 # pre-generate the subject for notification itself
413 # pre-generate the subject for notification itself
414 (subject,
414 (subject,
415 _h, _e, # we don't care about those
415 _h, _e, # we don't care about those
416 body_plaintext) = EmailNotificationModel().render_email(
416 body_plaintext) = EmailNotificationModel().render_email(
417 notification_type, **kwargs)
417 notification_type, **kwargs)
418
418
419 # create notification objects, and emails
419 # create notification objects, and emails
420 NotificationModel().create(
420 NotificationModel().create(
421 created_by=new_user,
421 created_by=new_user,
422 notification_subject=subject,
422 notification_subject=subject,
423 notification_body=body_plaintext,
423 notification_body=body_plaintext,
424 notification_type=notification_type,
424 notification_type=notification_type,
425 recipients=None, # all admins
425 recipients=None, # all admins
426 email_kwargs=kwargs,
426 email_kwargs=kwargs,
427 )
427 )
428
428
429 return new_user
429 return new_user
430 except Exception:
430 except Exception:
431 log.error(traceback.format_exc())
431 log.error(traceback.format_exc())
432 raise
432 raise
433
433
434 def _handle_user_repos(self, username, repositories, handle_mode=None):
434 def _handle_user_repos(self, username, repositories, handle_mode=None):
435 _superadmin = self.cls.get_first_super_admin()
435 _superadmin = self.cls.get_first_super_admin()
436 left_overs = True
436 left_overs = True
437
437
438 from rhodecode.model.repo import RepoModel
438 from rhodecode.model.repo import RepoModel
439
439
440 if handle_mode == 'detach':
440 if handle_mode == 'detach':
441 for obj in repositories:
441 for obj in repositories:
442 obj.user = _superadmin
442 obj.user = _superadmin
443 # set description we know why we super admin now owns
443 # set description we know why we super admin now owns
444 # additional repositories that were orphaned !
444 # additional repositories that were orphaned !
445 obj.description += ' \n::detached repository from deleted user: %s' % (username,)
445 obj.description += ' \n::detached repository from deleted user: %s' % (username,)
446 self.sa.add(obj)
446 self.sa.add(obj)
447 left_overs = False
447 left_overs = False
448 elif handle_mode == 'delete':
448 elif handle_mode == 'delete':
449 for obj in repositories:
449 for obj in repositories:
450 RepoModel().delete(obj, forks='detach')
450 RepoModel().delete(obj, forks='detach')
451 left_overs = False
451 left_overs = False
452
452
453 # if nothing is done we have left overs left
453 # if nothing is done we have left overs left
454 return left_overs
454 return left_overs
455
455
456 def _handle_user_repo_groups(self, username, repository_groups,
456 def _handle_user_repo_groups(self, username, repository_groups,
457 handle_mode=None):
457 handle_mode=None):
458 _superadmin = self.cls.get_first_super_admin()
458 _superadmin = self.cls.get_first_super_admin()
459 left_overs = True
459 left_overs = True
460
460
461 from rhodecode.model.repo_group import RepoGroupModel
461 from rhodecode.model.repo_group import RepoGroupModel
462
462
463 if handle_mode == 'detach':
463 if handle_mode == 'detach':
464 for r in repository_groups:
464 for r in repository_groups:
465 r.user = _superadmin
465 r.user = _superadmin
466 # set description we know why we super admin now owns
466 # set description we know why we super admin now owns
467 # additional repositories that were orphaned !
467 # additional repositories that were orphaned !
468 r.group_description += ' \n::detached repository group from deleted user: %s' % (username,)
468 r.group_description += ' \n::detached repository group from deleted user: %s' % (username,)
469 self.sa.add(r)
469 self.sa.add(r)
470 left_overs = False
470 left_overs = False
471 elif handle_mode == 'delete':
471 elif handle_mode == 'delete':
472 for r in repository_groups:
472 for r in repository_groups:
473 RepoGroupModel().delete(r)
473 RepoGroupModel().delete(r)
474 left_overs = False
474 left_overs = False
475
475
476 # if nothing is done we have left overs left
476 # if nothing is done we have left overs left
477 return left_overs
477 return left_overs
478
478
479 def _handle_user_user_groups(self, username, user_groups, handle_mode=None):
479 def _handle_user_user_groups(self, username, user_groups, handle_mode=None):
480 _superadmin = self.cls.get_first_super_admin()
480 _superadmin = self.cls.get_first_super_admin()
481 left_overs = True
481 left_overs = True
482
482
483 from rhodecode.model.user_group import UserGroupModel
483 from rhodecode.model.user_group import UserGroupModel
484
484
485 if handle_mode == 'detach':
485 if handle_mode == 'detach':
486 for r in user_groups:
486 for r in user_groups:
487 for user_user_group_to_perm in r.user_user_group_to_perm:
487 for user_user_group_to_perm in r.user_user_group_to_perm:
488 if user_user_group_to_perm.user.username == username:
488 if user_user_group_to_perm.user.username == username:
489 user_user_group_to_perm.user = _superadmin
489 user_user_group_to_perm.user = _superadmin
490 r.user = _superadmin
490 r.user = _superadmin
491 # set description we know why we super admin now owns
491 # set description we know why we super admin now owns
492 # additional repositories that were orphaned !
492 # additional repositories that were orphaned !
493 r.user_group_description += ' \n::detached user group from deleted user: %s' % (username,)
493 r.user_group_description += ' \n::detached user group from deleted user: %s' % (username,)
494 self.sa.add(r)
494 self.sa.add(r)
495 left_overs = False
495 left_overs = False
496 elif handle_mode == 'delete':
496 elif handle_mode == 'delete':
497 for r in user_groups:
497 for r in user_groups:
498 UserGroupModel().delete(r)
498 UserGroupModel().delete(r)
499 left_overs = False
499 left_overs = False
500
500
501 # if nothing is done we have left overs left
501 # if nothing is done we have left overs left
502 return left_overs
502 return left_overs
503
503
504 def delete(self, user, cur_user=None, handle_repos=None,
504 def delete(self, user, cur_user=None, handle_repos=None,
505 handle_repo_groups=None, handle_user_groups=None):
505 handle_repo_groups=None, handle_user_groups=None):
506 if not cur_user:
506 if not cur_user:
507 cur_user = getattr(
507 cur_user = getattr(
508 get_current_rhodecode_user(), 'username', None)
508 get_current_rhodecode_user(), 'username', None)
509 user = self._get_user(user)
509 user = self._get_user(user)
510
510
511 try:
511 try:
512 if user.username == User.DEFAULT_USER:
512 if user.username == User.DEFAULT_USER:
513 raise DefaultUserException(
513 raise DefaultUserException(
514 u"You can't remove this user since it's"
514 u"You can't remove this user since it's"
515 u" crucial for entire application")
515 u" crucial for entire application")
516
516
517 left_overs = self._handle_user_repos(
517 left_overs = self._handle_user_repos(
518 user.username, user.repositories, handle_repos)
518 user.username, user.repositories, handle_repos)
519 if left_overs and user.repositories:
519 if left_overs and user.repositories:
520 repos = [x.repo_name for x in user.repositories]
520 repos = [x.repo_name for x in user.repositories]
521 raise UserOwnsReposException(
521 raise UserOwnsReposException(
522 u'user "%(username)s" still owns %(len_repos)s repositories and cannot be '
522 u'user "%(username)s" still owns %(len_repos)s repositories and cannot be '
523 u'removed. Switch owners or remove those repositories:%(list_repos)s'
523 u'removed. Switch owners or remove those repositories:%(list_repos)s'
524 % {'username': user.username, 'len_repos': len(repos),
524 % {'username': user.username, 'len_repos': len(repos),
525 'list_repos': ', '.join(repos)})
525 'list_repos': ', '.join(repos)})
526
526
527 left_overs = self._handle_user_repo_groups(
527 left_overs = self._handle_user_repo_groups(
528 user.username, user.repository_groups, handle_repo_groups)
528 user.username, user.repository_groups, handle_repo_groups)
529 if left_overs and user.repository_groups:
529 if left_overs and user.repository_groups:
530 repo_groups = [x.group_name for x in user.repository_groups]
530 repo_groups = [x.group_name for x in user.repository_groups]
531 raise UserOwnsRepoGroupsException(
531 raise UserOwnsRepoGroupsException(
532 u'user "%(username)s" still owns %(len_repo_groups)s repository groups and cannot be '
532 u'user "%(username)s" still owns %(len_repo_groups)s repository groups and cannot be '
533 u'removed. Switch owners or remove those repository groups:%(list_repo_groups)s'
533 u'removed. Switch owners or remove those repository groups:%(list_repo_groups)s'
534 % {'username': user.username, 'len_repo_groups': len(repo_groups),
534 % {'username': user.username, 'len_repo_groups': len(repo_groups),
535 'list_repo_groups': ', '.join(repo_groups)})
535 'list_repo_groups': ', '.join(repo_groups)})
536
536
537 left_overs = self._handle_user_user_groups(
537 left_overs = self._handle_user_user_groups(
538 user.username, user.user_groups, handle_user_groups)
538 user.username, user.user_groups, handle_user_groups)
539 if left_overs and user.user_groups:
539 if left_overs and user.user_groups:
540 user_groups = [x.users_group_name for x in user.user_groups]
540 user_groups = [x.users_group_name for x in user.user_groups]
541 raise UserOwnsUserGroupsException(
541 raise UserOwnsUserGroupsException(
542 u'user "%s" still owns %s user groups and cannot be '
542 u'user "%s" still owns %s user groups and cannot be '
543 u'removed. Switch owners or remove those user groups:%s'
543 u'removed. Switch owners or remove those user groups:%s'
544 % (user.username, len(user_groups), ', '.join(user_groups)))
544 % (user.username, len(user_groups), ', '.join(user_groups)))
545
545
546 # we might change the user data with detach/delete, make sure
546 # we might change the user data with detach/delete, make sure
547 # the object is marked as expired before actually deleting !
547 # the object is marked as expired before actually deleting !
548 self.sa.expire(user)
548 self.sa.expire(user)
549 self.sa.delete(user)
549 self.sa.delete(user)
550 from rhodecode.lib.hooks_base import log_delete_user
550 from rhodecode.lib.hooks_base import log_delete_user
551 log_delete_user(deleted_by=cur_user, **user.get_dict())
551 log_delete_user(deleted_by=cur_user, **user.get_dict())
552 except Exception:
552 except Exception:
553 log.error(traceback.format_exc())
553 log.error(traceback.format_exc())
554 raise
554 raise
555
555
556 def reset_password_link(self, data, pwd_reset_url):
556 def reset_password_link(self, data, pwd_reset_url):
557 from rhodecode.lib.celerylib import tasks, run_task
557 from rhodecode.lib.celerylib import tasks, run_task
558 from rhodecode.model.notification import EmailNotificationModel
558 from rhodecode.model.notification import EmailNotificationModel
559 user_email = data['email']
559 user_email = data['email']
560 try:
560 try:
561 user = User.get_by_email(user_email)
561 user = User.get_by_email(user_email)
562 if user:
562 if user:
563 log.debug('password reset user found %s', user)
563 log.debug('password reset user found %s', user)
564
564
565 email_kwargs = {
565 email_kwargs = {
566 'password_reset_url': pwd_reset_url,
566 'password_reset_url': pwd_reset_url,
567 'user': user,
567 'user': user,
568 'email': user_email,
568 'email': user_email,
569 'date': datetime.datetime.now()
569 'date': datetime.datetime.now()
570 }
570 }
571
571
572 (subject, headers, email_body,
572 (subject, headers, email_body,
573 email_body_plaintext) = EmailNotificationModel().render_email(
573 email_body_plaintext) = EmailNotificationModel().render_email(
574 EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs)
574 EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs)
575
575
576 recipients = [user_email]
576 recipients = [user_email]
577
577
578 action_logger_generic(
578 action_logger_generic(
579 'sending password reset email to user: {}'.format(
579 'sending password reset email to user: {}'.format(
580 user), namespace='security.password_reset')
580 user), namespace='security.password_reset')
581
581
582 run_task(tasks.send_email, recipients, subject,
582 run_task(tasks.send_email, recipients, subject,
583 email_body_plaintext, email_body)
583 email_body_plaintext, email_body)
584
584
585 else:
585 else:
586 log.debug("password reset email %s not found", user_email)
586 log.debug("password reset email %s not found", user_email)
587 except Exception:
587 except Exception:
588 log.error(traceback.format_exc())
588 log.error(traceback.format_exc())
589 return False
589 return False
590
590
591 return True
591 return True
592
592
593 def reset_password(self, data):
593 def reset_password(self, data):
594 from rhodecode.lib.celerylib import tasks, run_task
594 from rhodecode.lib.celerylib import tasks, run_task
595 from rhodecode.model.notification import EmailNotificationModel
595 from rhodecode.model.notification import EmailNotificationModel
596 from rhodecode.lib import auth
596 from rhodecode.lib import auth
597 user_email = data['email']
597 user_email = data['email']
598 pre_db = True
598 pre_db = True
599 try:
599 try:
600 user = User.get_by_email(user_email)
600 user = User.get_by_email(user_email)
601 new_passwd = auth.PasswordGenerator().gen_password(
601 new_passwd = auth.PasswordGenerator().gen_password(
602 12, auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
602 12, auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
603 if user:
603 if user:
604 user.password = auth.get_crypt_password(new_passwd)
604 user.password = auth.get_crypt_password(new_passwd)
605 # also force this user to reset his password !
605 # also force this user to reset his password !
606 user.update_userdata(force_password_change=True)
606 user.update_userdata(force_password_change=True)
607
607
608 Session().add(user)
608 Session().add(user)
609
609
610 # now delete the token in question
610 # now delete the token in question
611 UserApiKeys = AuthTokenModel.cls
611 UserApiKeys = AuthTokenModel.cls
612 UserApiKeys().query().filter(
612 UserApiKeys().query().filter(
613 UserApiKeys.api_key == data['token']).delete()
613 UserApiKeys.api_key == data['token']).delete()
614
614
615 Session().commit()
615 Session().commit()
616 log.info('successfully reset password for `%s`', user_email)
616 log.info('successfully reset password for `%s`', user_email)
617
617
618 if new_passwd is None:
618 if new_passwd is None:
619 raise Exception('unable to generate new password')
619 raise Exception('unable to generate new password')
620
620
621 pre_db = False
621 pre_db = False
622
622
623 email_kwargs = {
623 email_kwargs = {
624 'new_password': new_passwd,
624 'new_password': new_passwd,
625 'user': user,
625 'user': user,
626 'email': user_email,
626 'email': user_email,
627 'date': datetime.datetime.now()
627 'date': datetime.datetime.now()
628 }
628 }
629
629
630 (subject, headers, email_body,
630 (subject, headers, email_body,
631 email_body_plaintext) = EmailNotificationModel().render_email(
631 email_body_plaintext) = EmailNotificationModel().render_email(
632 EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION,
632 EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION,
633 **email_kwargs)
633 **email_kwargs)
634
634
635 recipients = [user_email]
635 recipients = [user_email]
636
636
637 action_logger_generic(
637 action_logger_generic(
638 'sent new password to user: {} with email: {}'.format(
638 'sent new password to user: {} with email: {}'.format(
639 user, user_email), namespace='security.password_reset')
639 user, user_email), namespace='security.password_reset')
640
640
641 run_task(tasks.send_email, recipients, subject,
641 run_task(tasks.send_email, recipients, subject,
642 email_body_plaintext, email_body)
642 email_body_plaintext, email_body)
643
643
644 except Exception:
644 except Exception:
645 log.error('Failed to update user password')
645 log.error('Failed to update user password')
646 log.error(traceback.format_exc())
646 log.error(traceback.format_exc())
647 if pre_db:
647 if pre_db:
648 # we rollback only if local db stuff fails. If it goes into
648 # we rollback only if local db stuff fails. If it goes into
649 # run_task, we're pass rollback state this wouldn't work then
649 # run_task, we're pass rollback state this wouldn't work then
650 Session().rollback()
650 Session().rollback()
651
651
652 return True
652 return True
653
653
654 def fill_data(self, auth_user, user_id=None, api_key=None, username=None):
654 def fill_data(self, auth_user, user_id=None, api_key=None, username=None):
655 """
655 """
656 Fetches auth_user by user_id,or api_key if present.
656 Fetches auth_user by user_id,or api_key if present.
657 Fills auth_user attributes with those taken from database.
657 Fills auth_user attributes with those taken from database.
658 Additionally set's is_authenitated if lookup fails
658 Additionally set's is_authenitated if lookup fails
659 present in database
659 present in database
660
660
661 :param auth_user: instance of user to set attributes
661 :param auth_user: instance of user to set attributes
662 :param user_id: user id to fetch by
662 :param user_id: user id to fetch by
663 :param api_key: api key to fetch by
663 :param api_key: api key to fetch by
664 :param username: username to fetch by
664 :param username: username to fetch by
665 """
665 """
666 def token_obfuscate(token):
667 if token:
668 return token[:4] + "****"
669
666 if user_id is None and api_key is None and username is None:
670 if user_id is None and api_key is None and username is None:
667 raise Exception('You need to pass user_id, api_key or username')
671 raise Exception('You need to pass user_id, api_key or username')
668
672
669 log.debug(
673 log.debug(
670 'AuthUser: fill data execution based on: '
674 'AuthUser: fill data execution based on: '
671 'user_id:%s api_key:%s username:%s', user_id, api_key, username)
675 'user_id:%s api_key:%s username:%s', user_id, api_key, username)
672 try:
676 try:
673 dbuser = None
677 dbuser = None
674 if user_id:
678 if user_id:
675 dbuser = self.get(user_id)
679 dbuser = self.get(user_id)
676 elif api_key:
680 elif api_key:
677 dbuser = self.get_by_auth_token(api_key)
681 dbuser = self.get_by_auth_token(api_key)
678 elif username:
682 elif username:
679 dbuser = self.get_by_username(username)
683 dbuser = self.get_by_username(username)
680
684
681 if not dbuser:
685 if not dbuser:
682 log.warning(
686 log.warning(
683 'Unable to lookup user by id:%s api_key:%s username:%s',
687 'Unable to lookup user by id:%s api_key:%s username:%s',
684 user_id, api_key, username)
688 user_id, token_obfuscate(api_key), username)
685 return False
689 return False
686 if not dbuser.active:
690 if not dbuser.active:
687 log.debug('User `%s:%s` is inactive, skipping fill data',
691 log.debug('User `%s:%s` is inactive, skipping fill data',
688 username, user_id)
692 username, user_id)
689 return False
693 return False
690
694
691 log.debug('AuthUser: filling found user:%s data', dbuser)
695 log.debug('AuthUser: filling found user:%s data', dbuser)
692 user_data = dbuser.get_dict()
696 user_data = dbuser.get_dict()
693
697
694 user_data.update({
698 user_data.update({
695 # set explicit the safe escaped values
699 # set explicit the safe escaped values
696 'first_name': dbuser.first_name,
700 'first_name': dbuser.first_name,
697 'last_name': dbuser.last_name,
701 'last_name': dbuser.last_name,
698 })
702 })
699
703
700 for k, v in user_data.items():
704 for k, v in user_data.items():
701 # properties of auth user we dont update
705 # properties of auth user we dont update
702 if k not in ['auth_tokens', 'permissions']:
706 if k not in ['auth_tokens', 'permissions']:
703 setattr(auth_user, k, v)
707 setattr(auth_user, k, v)
704
708
705 except Exception:
709 except Exception:
706 log.error(traceback.format_exc())
710 log.error(traceback.format_exc())
707 auth_user.is_authenticated = False
711 auth_user.is_authenticated = False
708 return False
712 return False
709
713
710 return True
714 return True
711
715
712 def has_perm(self, user, perm):
716 def has_perm(self, user, perm):
713 perm = self._get_perm(perm)
717 perm = self._get_perm(perm)
714 user = self._get_user(user)
718 user = self._get_user(user)
715
719
716 return UserToPerm.query().filter(UserToPerm.user == user)\
720 return UserToPerm.query().filter(UserToPerm.user == user)\
717 .filter(UserToPerm.permission == perm).scalar() is not None
721 .filter(UserToPerm.permission == perm).scalar() is not None
718
722
719 def grant_perm(self, user, perm):
723 def grant_perm(self, user, perm):
720 """
724 """
721 Grant user global permissions
725 Grant user global permissions
722
726
723 :param user:
727 :param user:
724 :param perm:
728 :param perm:
725 """
729 """
726 user = self._get_user(user)
730 user = self._get_user(user)
727 perm = self._get_perm(perm)
731 perm = self._get_perm(perm)
728 # if this permission is already granted skip it
732 # if this permission is already granted skip it
729 _perm = UserToPerm.query()\
733 _perm = UserToPerm.query()\
730 .filter(UserToPerm.user == user)\
734 .filter(UserToPerm.user == user)\
731 .filter(UserToPerm.permission == perm)\
735 .filter(UserToPerm.permission == perm)\
732 .scalar()
736 .scalar()
733 if _perm:
737 if _perm:
734 return
738 return
735 new = UserToPerm()
739 new = UserToPerm()
736 new.user = user
740 new.user = user
737 new.permission = perm
741 new.permission = perm
738 self.sa.add(new)
742 self.sa.add(new)
739 return new
743 return new
740
744
741 def revoke_perm(self, user, perm):
745 def revoke_perm(self, user, perm):
742 """
746 """
743 Revoke users global permissions
747 Revoke users global permissions
744
748
745 :param user:
749 :param user:
746 :param perm:
750 :param perm:
747 """
751 """
748 user = self._get_user(user)
752 user = self._get_user(user)
749 perm = self._get_perm(perm)
753 perm = self._get_perm(perm)
750
754
751 obj = UserToPerm.query()\
755 obj = UserToPerm.query()\
752 .filter(UserToPerm.user == user)\
756 .filter(UserToPerm.user == user)\
753 .filter(UserToPerm.permission == perm)\
757 .filter(UserToPerm.permission == perm)\
754 .scalar()
758 .scalar()
755 if obj:
759 if obj:
756 self.sa.delete(obj)
760 self.sa.delete(obj)
757
761
758 def add_extra_email(self, user, email):
762 def add_extra_email(self, user, email):
759 """
763 """
760 Adds email address to UserEmailMap
764 Adds email address to UserEmailMap
761
765
762 :param user:
766 :param user:
763 :param email:
767 :param email:
764 """
768 """
765
769
766 user = self._get_user(user)
770 user = self._get_user(user)
767
771
768 obj = UserEmailMap()
772 obj = UserEmailMap()
769 obj.user = user
773 obj.user = user
770 obj.email = email
774 obj.email = email
771 self.sa.add(obj)
775 self.sa.add(obj)
772 return obj
776 return obj
773
777
774 def delete_extra_email(self, user, email_id):
778 def delete_extra_email(self, user, email_id):
775 """
779 """
776 Removes email address from UserEmailMap
780 Removes email address from UserEmailMap
777
781
778 :param user:
782 :param user:
779 :param email_id:
783 :param email_id:
780 """
784 """
781 user = self._get_user(user)
785 user = self._get_user(user)
782 obj = UserEmailMap.query().get(email_id)
786 obj = UserEmailMap.query().get(email_id)
783 if obj and obj.user_id == user.user_id:
787 if obj and obj.user_id == user.user_id:
784 self.sa.delete(obj)
788 self.sa.delete(obj)
785
789
786 def parse_ip_range(self, ip_range):
790 def parse_ip_range(self, ip_range):
787 ip_list = []
791 ip_list = []
788
792
789 def make_unique(value):
793 def make_unique(value):
790 seen = []
794 seen = []
791 return [c for c in value if not (c in seen or seen.append(c))]
795 return [c for c in value if not (c in seen or seen.append(c))]
792
796
793 # firsts split by commas
797 # firsts split by commas
794 for ip_range in ip_range.split(','):
798 for ip_range in ip_range.split(','):
795 if not ip_range:
799 if not ip_range:
796 continue
800 continue
797 ip_range = ip_range.strip()
801 ip_range = ip_range.strip()
798 if '-' in ip_range:
802 if '-' in ip_range:
799 start_ip, end_ip = ip_range.split('-', 1)
803 start_ip, end_ip = ip_range.split('-', 1)
800 start_ip = ipaddress.ip_address(safe_unicode(start_ip.strip()))
804 start_ip = ipaddress.ip_address(safe_unicode(start_ip.strip()))
801 end_ip = ipaddress.ip_address(safe_unicode(end_ip.strip()))
805 end_ip = ipaddress.ip_address(safe_unicode(end_ip.strip()))
802 parsed_ip_range = []
806 parsed_ip_range = []
803
807
804 for index in xrange(int(start_ip), int(end_ip) + 1):
808 for index in xrange(int(start_ip), int(end_ip) + 1):
805 new_ip = ipaddress.ip_address(index)
809 new_ip = ipaddress.ip_address(index)
806 parsed_ip_range.append(str(new_ip))
810 parsed_ip_range.append(str(new_ip))
807 ip_list.extend(parsed_ip_range)
811 ip_list.extend(parsed_ip_range)
808 else:
812 else:
809 ip_list.append(ip_range)
813 ip_list.append(ip_range)
810
814
811 return make_unique(ip_list)
815 return make_unique(ip_list)
812
816
813 def add_extra_ip(self, user, ip, description=None):
817 def add_extra_ip(self, user, ip, description=None):
814 """
818 """
815 Adds ip address to UserIpMap
819 Adds ip address to UserIpMap
816
820
817 :param user:
821 :param user:
818 :param ip:
822 :param ip:
819 """
823 """
820
824
821 user = self._get_user(user)
825 user = self._get_user(user)
822 obj = UserIpMap()
826 obj = UserIpMap()
823 obj.user = user
827 obj.user = user
824 obj.ip_addr = ip
828 obj.ip_addr = ip
825 obj.description = description
829 obj.description = description
826 self.sa.add(obj)
830 self.sa.add(obj)
827 return obj
831 return obj
828
832
829 def delete_extra_ip(self, user, ip_id):
833 def delete_extra_ip(self, user, ip_id):
830 """
834 """
831 Removes ip address from UserIpMap
835 Removes ip address from UserIpMap
832
836
833 :param user:
837 :param user:
834 :param ip_id:
838 :param ip_id:
835 """
839 """
836 user = self._get_user(user)
840 user = self._get_user(user)
837 obj = UserIpMap.query().get(ip_id)
841 obj = UserIpMap.query().get(ip_id)
838 if obj and obj.user_id == user.user_id:
842 if obj and obj.user_id == user.user_id:
839 self.sa.delete(obj)
843 self.sa.delete(obj)
840
844
841 def get_accounts_in_creation_order(self, current_user=None):
845 def get_accounts_in_creation_order(self, current_user=None):
842 """
846 """
843 Get accounts in order of creation for deactivation for license limits
847 Get accounts in order of creation for deactivation for license limits
844
848
845 pick currently logged in user, and append to the list in position 0
849 pick currently logged in user, and append to the list in position 0
846 pick all super-admins in order of creation date and add it to the list
850 pick all super-admins in order of creation date and add it to the list
847 pick all other accounts in order of creation and add it to the list.
851 pick all other accounts in order of creation and add it to the list.
848
852
849 Based on that list, the last accounts can be disabled as they are
853 Based on that list, the last accounts can be disabled as they are
850 created at the end and don't include any of the super admins as well
854 created at the end and don't include any of the super admins as well
851 as the current user.
855 as the current user.
852
856
853 :param current_user: optionally current user running this operation
857 :param current_user: optionally current user running this operation
854 """
858 """
855
859
856 if not current_user:
860 if not current_user:
857 current_user = get_current_rhodecode_user()
861 current_user = get_current_rhodecode_user()
858 active_super_admins = [
862 active_super_admins = [
859 x.user_id for x in User.query()
863 x.user_id for x in User.query()
860 .filter(User.user_id != current_user.user_id)
864 .filter(User.user_id != current_user.user_id)
861 .filter(User.active == true())
865 .filter(User.active == true())
862 .filter(User.admin == true())
866 .filter(User.admin == true())
863 .order_by(User.created_on.asc())]
867 .order_by(User.created_on.asc())]
864
868
865 active_regular_users = [
869 active_regular_users = [
866 x.user_id for x in User.query()
870 x.user_id for x in User.query()
867 .filter(User.user_id != current_user.user_id)
871 .filter(User.user_id != current_user.user_id)
868 .filter(User.active == true())
872 .filter(User.active == true())
869 .filter(User.admin == false())
873 .filter(User.admin == false())
870 .order_by(User.created_on.asc())]
874 .order_by(User.created_on.asc())]
871
875
872 list_of_accounts = [current_user.user_id]
876 list_of_accounts = [current_user.user_id]
873 list_of_accounts += active_super_admins
877 list_of_accounts += active_super_admins
874 list_of_accounts += active_regular_users
878 list_of_accounts += active_regular_users
875
879
876 return list_of_accounts
880 return list_of_accounts
877
881
878 def deactivate_last_users(self, expected_users, current_user=None):
882 def deactivate_last_users(self, expected_users, current_user=None):
879 """
883 """
880 Deactivate accounts that are over the license limits.
884 Deactivate accounts that are over the license limits.
881 Algorithm of which accounts to disabled is based on the formula:
885 Algorithm of which accounts to disabled is based on the formula:
882
886
883 Get current user, then super admins in creation order, then regular
887 Get current user, then super admins in creation order, then regular
884 active users in creation order.
888 active users in creation order.
885
889
886 Using that list we mark all accounts from the end of it as inactive.
890 Using that list we mark all accounts from the end of it as inactive.
887 This way we block only latest created accounts.
891 This way we block only latest created accounts.
888
892
889 :param expected_users: list of users in special order, we deactivate
893 :param expected_users: list of users in special order, we deactivate
890 the end N ammoun of users from that list
894 the end N ammoun of users from that list
891 """
895 """
892
896
893 list_of_accounts = self.get_accounts_in_creation_order(
897 list_of_accounts = self.get_accounts_in_creation_order(
894 current_user=current_user)
898 current_user=current_user)
895
899
896 for acc_id in list_of_accounts[expected_users + 1:]:
900 for acc_id in list_of_accounts[expected_users + 1:]:
897 user = User.get(acc_id)
901 user = User.get(acc_id)
898 log.info('Deactivating account %s for license unlock', user)
902 log.info('Deactivating account %s for license unlock', user)
899 user.active = False
903 user.active = False
900 Session().add(user)
904 Session().add(user)
901 Session().commit()
905 Session().commit()
902
906
903 return
907 return
904
908
905 def get_user_log(self, user, filter_term):
909 def get_user_log(self, user, filter_term):
906 user_log = UserLog.query()\
910 user_log = UserLog.query()\
907 .filter(or_(UserLog.user_id == user.user_id,
911 .filter(or_(UserLog.user_id == user.user_id,
908 UserLog.username == user.username))\
912 UserLog.username == user.username))\
909 .options(joinedload(UserLog.user))\
913 .options(joinedload(UserLog.user))\
910 .options(joinedload(UserLog.repository))\
914 .options(joinedload(UserLog.repository))\
911 .order_by(UserLog.action_date.desc())
915 .order_by(UserLog.action_date.desc())
912
916
913 user_log = user_log_filter(user_log, filter_term)
917 user_log = user_log_filter(user_log, filter_term)
914 return user_log
918 return user_log
General Comments 0
You need to be logged in to leave comments. Login now