##// END OF EJS Templates
auth/security: enforce that external users cannot reset their password.
marcink -
r3258:e5497c9f default
parent child Browse files
Show More
@@ -185,7 +185,7 b' class AdminUsersView(BaseAppView, DataGr'
185 185 def users_new(self):
186 186 _ = self.request.translate
187 187 c = self.load_default_context()
188 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
188 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
189 189 self._set_personal_repo_group_template_vars(c)
190 190 return self._get_template_context(c)
191 191
@@ -198,7 +198,7 b' class AdminUsersView(BaseAppView, DataGr'
198 198 def users_create(self):
199 199 _ = self.request.translate
200 200 c = self.load_default_context()
201 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
201 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
202 202 user_model = UserModel()
203 203 user_form = UserForm(self.request.translate)()
204 204 try:
@@ -32,6 +32,7 b' from pyramid.view import view_config'
32 32
33 33 from rhodecode.apps._base import BaseAppView
34 34 from rhodecode.authentication.base import authenticate, HTTP_TYPE
35 from rhodecode.authentication.plugins import auth_rhodecode
35 36 from rhodecode.events import UserRegistered, trigger
36 37 from rhodecode.lib import helpers as h
37 38 from rhodecode.lib import audit_logger
@@ -367,15 +368,24 b' class LoginView(BaseAppView):'
367 368 # matching emails
368 369 msg = _('If such email exists, a password reset link was sent to it.')
369 370
371 def default_response():
372 log.debug('faking response on invalid password reset')
373 # make this take 2s, to prevent brute forcing.
374 time.sleep(2)
375 h.flash(msg, category='success')
376 return HTTPFound(self.request.route_path('reset_password'))
377
370 378 if self.request.POST:
371 379 if h.HasPermissionAny('hg.password_reset.disabled')():
372 380 _email = self.request.POST.get('email', '')
373 381 log.error('Failed attempt to reset password for `%s`.', _email)
374 h.flash(_('Password reset has been disabled.'),
375 category='error')
382 h.flash(_('Password reset has been disabled.'), category='error')
376 383 return HTTPFound(self.request.route_path('reset_password'))
377 384
378 385 password_reset_form = PasswordResetForm(self.request.translate)()
386 description = u'Generated token for password reset from {}'.format(
387 datetime.datetime.now().isoformat())
388
379 389 try:
380 390 form_result = password_reset_form.to_python(
381 391 self.request.POST)
@@ -395,10 +405,14 b' class LoginView(BaseAppView):'
395 405 # Generate reset URL and send mail.
396 406 user = User.get_by_email(user_email)
397 407
408 # only allow rhodecode based users to reset their password
409 # external auth shouldn't allow password reset
410 if user and user.extern_type != auth_rhodecode.RhodeCodeAuthPlugin.uid:
411 log.warning('User %s with external type `%s` tried a password reset. '
412 'This try was rejected', user, user.extern_type)
413 return default_response()
414
398 415 # generate password reset token that expires in 10 minutes
399 description = u'Generated token for password reset from {}'.format(
400 datetime.datetime.now().isoformat())
401
402 416 reset_token = UserModel().add_auth_token(
403 417 user=user, lifetime_minutes=10,
404 418 role=UserModel.auth_token_role.ROLE_PASSWORD_RESET,
@@ -411,15 +425,14 b' class LoginView(BaseAppView):'
411 425 _query={'key': reset_token.api_key})
412 426 UserModel().reset_password_link(
413 427 form_result, password_reset_url)
414 # Display success message and redirect.
415 h.flash(msg, category='success')
416 428
417 429 action_data = {'email': user_email,
418 430 'user_agent': self.request.user_agent}
419 431 audit_logger.store_web(
420 432 'user.password.reset_request', action_data=action_data,
421 433 user=self._rhodecode_user, commit=True)
422 return HTTPFound(self.request.route_path('reset_password'))
434
435 return default_response()
423 436
424 437 except formencode.Invalid as errors:
425 438 template_context.update({
@@ -434,11 +447,7 b' class LoginView(BaseAppView):'
434 447 # case of failed captcha
435 448 return self._get_template_context(c, **template_context)
436 449
437 log.debug('faking response on invalid password reset')
438 # make this take 2s, to prevent brute forcing.
439 time.sleep(2)
440 h.flash(msg, category='success')
441 return HTTPFound(self.request.route_path('reset_password'))
450 return default_response()
442 451
443 452 return self._get_template_context(c, **template_context)
444 453
@@ -103,11 +103,12 b''
103 103 </div>
104 104 <div class="field">
105 105 <div class="label-text">
106 ${_('Source of Record')}:
106 ${_('Authentication type')}:
107 107 </div>
108 108 <div class="input">
109 109 <p>${c.extern_type}</p>
110 110 ${h.hidden('extern_type', readonly="readonly")}
111 <p class="help-block">${_('User was created using an external source. He is bound to authentication using this method.')}</p>
111 112 </div>
112 113 </div>
113 114 <div class="field">
@@ -127,7 +128,7 b''
127 128 ## allowed_languages is defined in the users.py
128 129 ## c.language comes from base.py as a default language
129 130 ${h.select('language', c.language, c.allowed_languages)}
130 <p class="help-block">${h.literal(_('Help translate %(rc_link)s into your language.') % {'rc_link': h.link_to('RhodeCode Enterprise', h.route_url('rhodecode_translations'))})}</p>
131 <p class="help-block">${h.literal(_('User interface language. Help translate %(rc_link)s into your language.') % {'rc_link': h.link_to('RhodeCode Enterprise', h.route_url('rhodecode_translations'))})}</p>
131 132 </div>
132 133 </div>
133 134 <div class="buttons">
General Comments 0
You need to be logged in to leave comments. Login now