def password_reset_form(self, request, **kw): """Returns a form for resetting the password""" if 'key' in kw or 'error' in kw: # we have a key, let's display the key controlling form return render_mako('password_reset_form.mako', **kw) elif not request.POST and not request.GET: # asking for the first time return render_mako('password_ask_reset_form.mako') raise HTTPBadRequest()
def password_reset_form(self, request, **kw): """Returns a form for resetting the password""" request.response.headers.add('X-Frame-Options', 'DENY') urlgen = URLGenerator(self.app.mapper, request.environ) kw["url"] = urlgen(controller="user", action="password_reset_form") if 'key' in kw or 'error' in kw: # we have a key, let's display the key controlling form return render_mako('password_reset_form.mako', **kw) elif not request.POST and not request.GET: # asking for the first time return render_mako('password_ask_reset_form.mako', **kw) raise HTTPBadRequest()
def do_password_reset(self, request): """Do a password reset.""" if self.reset is None: logger.debug('reset attempted, but no resetcode library installed') raise HTTPServiceUnavailable() user_name = request.POST.get('username') if user_name is not None: user_name = extract_username(user_name) if request.POST.keys() == ['username']: # setting up a password reset # XXX add support for captcha here via **data request.user = User(user_name) try: self.password_reset(request) except (HTTPServiceUnavailable, HTTPJsonBadRequest), e: return render_mako('password_failure.mako', error=e.detail) else: return render_mako('password_key_sent.mako') raise HTTPJsonBadRequest()
def password_reset(self, request, **data): """Sends an e-mail for a password reset request.""" if self.reset is None: self.logger.debug('reset attempted, but no resetcode library ' 'installed') raise HTTPServiceUnavailable() request.response.headers.add('X-Frame-Options', 'DENY') user_id = self.auth.get_user_id(request.user) if user_id is None: # user not found raise HTTPJsonBadRequest(ERROR_INVALID_USER) self.auth.get_user_info(request.user, ['mail']) if request.user.get('mail') is None: raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS) self._check_captcha(request, data) try: # the request looks fine, let's generate the reset code code = self.reset.generate_reset_code(request.user) urlgen = URLGenerator(self.app.mapper, request.environ) data = {'user_name': request.user['username'], 'code': code, 'host': request.host_url, 'url': urlgen(controller="user", action="password_reset_form")} body = render_mako('password_reset_mail.mako', **data) sender = request.config['smtp.sender'] host = request.config['smtp.host'] port = int(request.config['smtp.port']) user = request.config.get('smtp.user') password = request.config.get('smtp.password') subject = 'Resetting your Services password' res, msg = send_email(sender, request.user['mail'], subject, body, host, port, user, password) if not res: raise HTTPServiceUnavailable(msg) except AlreadySentError: #backend handled the reset code email. Keep going pass return text_response('success')
def password_reset(self, request, **data): """Sends an e-mail for a password reset request.""" if self.reset is None: logger.debug('reset attempted, but no resetcode library installed') raise HTTPServiceUnavailable() user_id = self.auth.get_user_id(request.user) if user_id is None: # user not found raise HTTPJsonBadRequest(ERROR_INVALID_USER) self.auth.get_user_info(request.user, ['mail']) if request.user.get('mail') is None: raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS) self._check_captcha(request, data) try: # the request looks fine, let's generate the reset code code = self.reset.generate_reset_code(request.user) data = { 'host': request.host_url, 'user_name': request.user['username'], 'code': code } body = render_mako('password_reset_mail.mako', **data) sender = request.config['smtp.sender'] host = request.config['smtp.host'] port = int(request.config['smtp.port']) user = request.config.get('smtp.user') password = request.config.get('smtp.password') subject = 'Resetting your Services password' res, msg = send_email(sender, request.user['mail'], subject, body, host, port, user, password) if not res: raise HTTPServiceUnavailable(msg) except AlreadySentError: #backend handled the reset code email. Keep going pass return text_response('success')
def captcha_form(self, request): """Renders the captcha form""" if not self.app.config['captcha.use']: raise HTTPNotFound('No captcha configured') return render_mako('captcha.mako', captcha=self._captcha())
if not valid_password(user_name, password): return self._repost(request, 'Password should be at least 8 ' 'characters and not the same as your ' 'username') if not self.reset.verify_reset_code(user, key): return self._repost(request, 'Key does not match with username. ' 'Please request a new key.') # everything looks fine if not self.auth.admin_update_password(user, password): return self._repost(request, 'Password change failed ' 'unexpectedly.') self.reset.clear_reset_code(user) return render_mako('password_changed.mako') def delete_user(self, request): """Deletes the user.""" if not hasattr(request, 'user_password'): raise HTTPBadRequest() res = self.auth.delete_user(request.user, request.user_password) return text_response(int(res)) def _captcha(self): """Return HTML string for inserting recaptcha into a form.""" return captcha.displayhtml(self.app.config['captcha.public_key'], use_ssl=self.app.config['captcha.use_ssl'])
class UserController(object): def __init__(self, app): self.app = app self.strict_usernames = app.config.get('auth.strict_usernames', True) self.shared_secret = app.config.get('global.shared_secret') self.auth = self.app.auth.backend self.fallback_node = \ self.clean_location(app.config.get('nodes.fallback_node')) try: self.reset = load_and_configure(app.config, 'reset_codes') except Exception: logger.debug(traceback.format_exc()) logger.debug("No reset code library in place") self.reset = None def user_exists(self, request): if request.user.get('username') is None: raise HTTPNotFound() uid = self.auth.get_user_id(request.user) return text_response(int(uid is not None)) def return_fallback(self): if self.fallback_node is None: return json_response(None) return self.fallback_node def clean_location(self, location): if location is None: return None if not location.endswith('/'): location += '/' if not location.startswith('http'): location = 'https://%s' % location return location def user_node(self, request): """Returns the storage node root for the user""" # warning: # the client expects a string body not a json body # except when the node is 'null' # IF YOU ARE USING ACTUAL NODE ASSIGNMENT (odds are you're not) # There is now a separate assignment module: # http://hg.mozilla.org/services/server-node-assignment # Install that and point your server at it for # the node assignment call if request.user.get('username') is None: raise HTTPNotFound() if not self.auth.get_user_id(request.user): raise HTTPNotFound() return self.return_fallback() def password_reset(self, request, **data): """Sends an e-mail for a password reset request.""" if self.reset is None: logger.debug('reset attempted, but no resetcode library installed') raise HTTPServiceUnavailable() user_id = self.auth.get_user_id(request.user) if user_id is None: # user not found raise HTTPJsonBadRequest(ERROR_INVALID_USER) self.auth.get_user_info(request.user, ['mail']) if request.user.get('mail') is None: raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS) self._check_captcha(request, data) try: # the request looks fine, let's generate the reset code code = self.reset.generate_reset_code(request.user) data = { 'host': request.host_url, 'user_name': request.user['username'], 'code': code } body = render_mako('password_reset_mail.mako', **data) sender = request.config['smtp.sender'] host = request.config['smtp.host'] port = int(request.config['smtp.port']) user = request.config.get('smtp.user') password = request.config.get('smtp.password') subject = 'Resetting your Services password' res, msg = send_email(sender, request.user['mail'], subject, body, host, port, user, password) if not res: raise HTTPServiceUnavailable(msg) except AlreadySentError: #backend handled the reset code email. Keep going pass return text_response('success') def delete_password_reset(self, request, **data): """Forces a password reset clear""" if self.reset is None: logger.debug('reset attempted, but no resetcode library installed') raise HTTPServiceUnavailable() self._check_captcha(request, data) self.auth.get_user_id(request.user) self.reset.clear_reset_code(request.user) log_cef("User requested password reset clear", 9, request.environ, self.app.config, request.user.get('username'), PASSWD_RESET_CLR) return text_response('success') def _check_captcha(self, request, data): # check if captcha info are provided if not self.app.config['captcha.use']: return challenge = data.get('captcha-challenge') response = data.get('captcha-response') if challenge is not None and response is not None: resp = captcha.submit(challenge, response, self.app.config['captcha.private_key'], remoteip=request.remote_addr) if not resp.is_valid: raise HTTPJsonBadRequest(ERROR_INVALID_CAPTCHA) else: raise HTTPJsonBadRequest(ERROR_INVALID_CAPTCHA) def create_user(self, request): """Creates a user.""" if self.auth.get_user_id(request.user): raise HTTPJsonBadRequest(ERROR_INVALID_WRITE) username = request.user['username'] try: data = json.loads(request.body) except ValueError: raise HTTPJsonBadRequest(ERROR_MALFORMED_JSON) email = data.get('email') if email and not valid_email(email): raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS) # checking that the e-mail matches the username munged_email = extract_username(email) if munged_email != username and self.strict_usernames: raise HTTPJsonBadRequest(ERROR_USERNAME_EMAIL_MISMATCH) password = data.get('password') if not password: raise HTTPJsonBadRequest(ERROR_MISSING_PASSWORD) if not valid_password(username, password): raise HTTPJsonBadRequest(ERROR_WEAK_PASSWORD) # check if captcha info are provided or if we bypass it if (self.shared_secret is None or request.headers.get('X-Weave-Secret') != self.shared_secret): self._check_captcha(request, data) # all looks good, let's create the user if not self.auth.create_user(request.user['username'], password, email): raise HTTPInternalServerError('User creation failed.') return request.user['username'] def change_email(self, request): """Changes the user e-mail""" # the body is in plain text email = request.body if not valid_email(email): raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS) if not hasattr(request, 'user_password'): raise HTTPBadRequest() if not self.auth.update_field(request.user, request.user_password, 'mail', email): raise HTTPInternalServerError('User update failed.') return text_response(email) def change_password(self, request): """Changes the user's password Takes a classical authentication or a reset code """ # the body is in plain text utf8 string new_password = request.body.decode('utf8') if not valid_password(request.user.get('username'), new_password): raise HTTPBadRequest('Password should be at least 8 ' 'characters and not the same as your ' 'username') key = request.headers.get('X-Weave-Password-Reset') if key is not None: user_id = self.auth.get_user_id(request.user) if user_id is None: raise HTTPNotFound() if not self.reset.verify_reset_code(request.user, key): log_cef('Invalid Reset Code submitted', 5, request.environ, self.app.config, request.user['username'], 'InvalidResetCode', submitedtoken=key) raise HTTPJsonBadRequest(ERROR_INVALID_RESET_CODE) if not self.auth.admin_update_password(request.user, new_password, key): raise HTTPInternalServerError('Password change failed ' 'unexpectedly.') else: # classical auth self.app.auth.authenticate_user(request, self.app.config, request.user['username']) if request.user['userid'] is None: log_cef('User Authentication Failed', 5, request.environ, self.app.config, request.user['username'], AUTH_FAILURE) raise HTTPUnauthorized() if not self.auth.update_password( request.user, request.user_password, new_password): raise HTTPInternalServerError('Password change failed ' 'unexpectedly.') return text_response('success') def password_reset_form(self, request, **kw): """Returns a form for resetting the password""" if 'key' in kw or 'error' in kw: # we have a key, let's display the key controlling form return render_mako('password_reset_form.mako', **kw) elif not request.POST and not request.GET: # asking for the first time return render_mako('password_ask_reset_form.mako') raise HTTPBadRequest() def _repost(self, request, error): request.POST['error'] = error return self.password_reset_form(request, **dict(request.POST)) def do_password_reset(self, request): """Do a password reset.""" if self.reset is None: logger.debug('reset attempted, but no resetcode library installed') raise HTTPServiceUnavailable() user_name = request.POST.get('username') if user_name is not None: user_name = extract_username(user_name) if request.POST.keys() == ['username']: # setting up a password reset # XXX add support for captcha here via **data request.user = User(user_name) try: self.password_reset(request) except (HTTPServiceUnavailable, HTTPJsonBadRequest), e: return render_mako('password_failure.mako', error=e.detail) else: return render_mako('password_key_sent.mako') raise HTTPJsonBadRequest() # full form, the actual password reset password = request.POST.get('password') confirm = request.POST.get('confirm') key = request.POST.get('key') if key is None: raise HTTPJsonBadRequest() if user_name is None: return self._repost( request, 'Username not provided. Please check ' 'the link you used.') user = User(user_name) user_id = self.auth.get_user_id(user) if user_id is None: return self._repost(request, 'We are unable to locate your ' 'account') if password is None: return self._repost( request, 'Password not provided. ' 'Please check the link you used.') if password != confirm: return self._repost(request, 'Password and confirmation do ' 'not match') if not valid_password(user_name, password): return self._repost( request, 'Password should be at least 8 ' 'characters and not the same as your ' 'username') if not self.reset.verify_reset_code(user, key): return self._repost( request, 'Key does not match with username. ' 'Please request a new key.') # everything looks fine if not self.auth.admin_update_password(user, 'password', password): return self._repost(request, 'Password change failed ' 'unexpectedly.') self.reset.clear_reset_code(user) return render_mako('password_changed.mako')