def _forgotten_password(self): """Action to let the user request a password change. GET returns a form for emailing them the password change confirmation. POST checks the form and then creates a confirmation record: date, email_address, and a url_hash that is a hash of a combination of date, email_address, and a random nonce. The email address must exist in the person database. The second half of the password change operation happens in the ``confirm`` action. """ c.email = self.form_result['email_address'] c.person = Person.find_by_email(c.email) if c.person is not None: # Check if there is already a password recovery in progress reset = PasswordResetConfirmation.find_by_email(c.email) if reset is not None: return render('person/in_progress.mako') # Ok kick one off c.conf_rec = PasswordResetConfirmation(email_address=c.email) meta.Session.add(c.conf_rec) meta.Session.commit() email(c.email, render('person/confirmation_email.mako')) return render('person/password_confirmation_sent.mako')
def test_confirm(self): """Test confirmation of a password reset that should succeed""" # create a confirmation record email = '*****@*****.**' p = Person(email_address=email) self.dbsession.save(p) c = PasswordResetConfirmation(email_address=email) # set the timestamp to just under 24 hours ago c.timestamp = datetime.datetime.now() - datetime.timedelta(23, 59, 59) self.dbsession.save(c) self.dbsession.flush() pid = p.id cid = c.id resp = self.app.get( url_for(controller='person', action='reset_password', url_hash=c.url_hash)) # showing the email on the page resp.mustcontain(email) f = resp.form f['password'] = '******' f['password_confirm'] = 'test' resp = f.submit() # check for success resp.mustcontain("Your password has been updated") self.dbsession.clear() # conf rec should be gone c = self.dbsession.get(PasswordResetConfirmation, cid) self.assertEqual(None, c) # password should be set to 'test' p_hash = md5.new('test').hexdigest() p = self.dbsession.get(Person, pid) self.assertEqual(p_hash, p.password_hash) self.dbsession.delete(p) self.dbsession.flush()
def test_confirm(self): """Test confirmation of a password reset that should succeed""" # create a confirmation record email = '*****@*****.**' p = Person(email_address=email) self.dbsession.save(p) c = PasswordResetConfirmation(email_address=email) # set the timestamp to just under 24 hours ago c.timestamp = datetime.datetime.now() - datetime.timedelta(23, 59, 59) self.dbsession.save(c) self.dbsession.flush() pid = p.id cid = c.id resp = self.app.get(url_for(controller='person', action='reset_password', url_hash=c.url_hash)) # showing the email on the page resp.mustcontain(email) f = resp.form f['password'] = '******' f['password_confirm'] = 'test' resp = f.submit() # check for success resp.mustcontain("Your password has been updated") self.dbsession.clear() # conf rec should be gone c = self.dbsession.get(PasswordResetConfirmation, cid) self.assertEqual(None, c) # password should be set to 'test' p_hash = md5.new('test').hexdigest() p = self.dbsession.get(Person, pid) self.assertEqual(p_hash, p.password_hash) self.dbsession.delete(p) self.dbsession.flush()
def test_confirm_old_url_hash(self): """Test that old url_hashes are caught""" email = '*****@*****.**' stamp = datetime.datetime.now() - datetime.timedelta(24, 0, 1) c = PasswordResetConfirmation(email_address=email) c.timestamp = stamp self.dbsession.save(c) self.dbsession.flush() cid = c.id resp = self.app.get(url_for(controller='person', action='reset_password', url_hash=c.url_hash)) # check for warning resp.mustcontain("This password recovery session has expired") self.dbsession.clear() c = self.dbsession.get(PasswordResetConfirmation, cid) # record shouldn't exist anymore self.assertEqual(None, c)
def test_confirm_old_url_hash(self): """Test that old url_hashes are caught""" email = '*****@*****.**' stamp = datetime.datetime.now() - datetime.timedelta(24, 0, 1) c = PasswordResetConfirmation(email_address=email) c.timestamp = stamp self.dbsession.save(c) self.dbsession.flush() cid = c.id resp = self.app.get( url_for(controller='person', action='reset_password', url_hash=c.url_hash)) # check for warning resp.mustcontain("This password recovery session has expired") self.dbsession.clear() c = self.dbsession.get(PasswordResetConfirmation, cid) # record shouldn't exist anymore self.assertEqual(None, c)
def _reset_password(self, url_hash): """Confirm a password change request, and let the user change their password. `url_hash` is a hash of the email address, with which we can look up the confuirmation record in the database. If `url_hash` doesn't exist, 404. If `url_hash` exists and the date is older than 24 hours, warn the user, offer to send a new confirmation, and delete the confirmation record. GET returns a form for setting their password, with their email address already shown. POST checks that the email address (in the session, not in the form) is part of a valid person record (again). If the record exists, then update the password, hashed. Report success to the user. Delete the confirmation record. If the record doesn't exist, throw an error, delete the confirmation record. """ c.conf_rec = PasswordResetConfirmation.find_by_url_hash(url_hash) now = datetime.datetime.now(c.conf_rec.timestamp.tzinfo) delta = now - c.conf_rec.timestamp if delta > datetime.timedelta(hours=24): # this confirmation record has expired meta.Session.delete(c.conf_rec) meta.Session.commit() return render('person/expired.mako') person = Person.find_by_email(c.conf_rec.email_address) if person is None: raise RuntimeError, "Person doesn't exist %s" % c.conf_rec.email_address # set the password person.password = self.form_result['password'] # also make sure the person is activated person.activated = True # delete the conf rec meta.Session.delete(c.conf_rec) meta.Session.commit() return render('person/success.mako')
def reset_password(self, url_hash): c.conf_rec = PasswordResetConfirmation.find_by_url_hash(url_hash) return render('person/reset.mako')