def test_reset_password_with_unconfirmed_email_raise_validation_error_2(self): """ Com: um novo usuário (com email confirmado), Quando: 1. solicitamos recuperar senha. 2. obtemos o email com a url necessária para recuperação. 3. mudamos o usuário para ter seu email como NÃO confirmado. 4. e solicitamos uma nova senha, com o link (token) do email. Verificamos: - a pagina deve informar que é necessário confirmar o email. - a troca de senha não procede. - a pagina deve mostrar o template admin/auth/unconfirm_email.html """ # with reset_pwd_url = url_for('admin.reset') credentials = { 'email': '*****@*****.**', 'password': '******' } # when create_user(credentials['email'], credentials['password'], True) with mail.record_messages() as outbox: response = self.client.post( reset_pwd_url, data={'email': credentials['email']}, follow_redirects=True) # then self.assertEqual(1, len(outbox)) email_msg = outbox[0] # recupero os links do email links_found = reset_pwd_url_pattern.findall(email_msg.html) # tem pelo menos 1 link, e tem só um link para o reset/password com token self.assertGreaterEqual(1, len(links_found)) resert_url_with_token = [url for url in links_found if reset_pwd_url in url][0] # agora o usuário tem o email NÃO confirmado. user = get_user_by_email(credentials['email']) user.email_confirmed = False dbsql.session.add(user) dbsql.session.commit() # tentamos recuperar a senha com o link/token do email new_password = '******' response = self.client.post( resert_url_with_token, data={'password': new_password}, follow_redirects=True) self.assertStatus(response, 200) self.assertTemplateUsed('admin/auth/unconfirm_email.html') user = get_user_by_email(credentials['email']) self.assertTrue(user.is_correct_password(credentials['password']))
def test_reset_password_with_unconfirmed_email_shows_unconfirm_email_error(self): """ Com: um novo usuário (com email NÃO confirmado), Quando: 1. solicitamos recuperar senha. 2. obtemos o email com a url necessária para recuperação. 3. e solicitamos uma nova senha, com o link (token) do email. Verificamos: - a pagina deve informar que é necessário confirmar o email. - a troca de senha não procede. - a pagina deve mostrar o template admin/auth/unconfirm_email.html """ # with reset_pwd_url = url_for('admin.reset') credentials = { 'email': '*****@*****.**', 'password': '******' } # when create_user(credentials['email'], credentials['password'], False) with mail.record_messages() as outbox: response = self.client.post( reset_pwd_url, data={'email': credentials['email']}, follow_redirects=True) # then # no foi enviado nenhum email self.assertEqual(0, len(outbox)) self.assertStatus(response, 200) self.assertTemplateUsed('admin/auth/unconfirm_email.html') user = get_user_by_email(credentials['email']) self.assertTrue(user.is_correct_password(credentials['password']))
def test_reset_password_with_invalid_password_raise_validation_error(self): """ Com: um novo usuário (com email confirmado), Quando: 1. solicitamos recuperar senha. 2. obtemos o email com a url necessária para recuperação. 3. e solicitamos uma nova senha, com o link do email. 4. inserimos uma senha inválida ('') Verificamos: - a pagina deve informar de que senha é requerida - a senha do usuário não deve ser modificada """ # with reset_pwd_url = url_for('admin.reset') credentials = { 'email': '*****@*****.**', 'password': '******' } # when create_user(credentials['email'], credentials['password'], True) with mail.record_messages() as outbox: response = self.client.post( reset_pwd_url, data={'email': credentials['email']}, follow_redirects=True) # then self.assertEqual(1, len(outbox)) email_msg = outbox[0] # recupero os links do email links_found = reset_pwd_url_pattern.findall(email_msg.html) # tem pelo menos 1 link, e tem só um link para o reset/password com token self.assertGreaterEqual(1, len(links_found)) resert_url_with_token = [url for url in links_found if reset_pwd_url in url][0] invalid_password = '' response = self.client.post( resert_url_with_token, data={'password': invalid_password}, follow_redirects=True) self.assertStatus(response, 200) context_form = self.get_context_variable('form') expected_form_error = {'password': [u'This field is required.']} self.assertEqual(expected_form_error, context_form.errors) self.assertIn(expected_form_error['password'][0], response.data.decode('utf-8')) user = get_user_by_email(credentials['email']) self.assertFalse(user.is_correct_password(invalid_password))
def confirm_email(self, token): try: ts = get_timed_serializer() email = ts.loads(token, salt="email-confirm-key", max_age=current_app.config['TOKEN_MAX_AGE']) except Exception as e: # possiveis exceções: https://pythonhosted.org/itsdangerous/#exceptions # qualquer exeção invalida a operação de confirmação abort(404) # melhorar mensagem de erro para o usuário user = controllers.get_user_by_email(email=email) if not user: abort(404, _(u'Usuário não encontrado')) controllers.set_user_email_confirmed(user) flash(_(u'Email: %(email)s confirmado com sucesso!', email=user.email)) return redirect(url_for('.index'))
def login_view(self): # handle user login form = forms.LoginForm(request.form) if admin.helpers.validate_form_on_submit(form): user_email = form.data['email'] user = controllers.get_user_by_email(user_email) if not user.email_confirmed: return self.render('admin/auth/unconfirm_email.html') login.login_user(user) if login.current_user.is_authenticated: return redirect(url_for('.index')) self._template_args['form'] = form return self.render('admin/auth/login.html')
def test_link_sent_via_email_to_reset_password_works_fine(self): """ Com: um novo usuário (com email confirmado), Quando: 1. solicitamos recuperar senha. 2. obtemos o email com a url necessária para recuperação. 3. e solicitamos uma nova senha, com o link do email. 4. inserimos uma nova senha para o úsuario. Verificamos: - a pagina de recuperar senha tenha o form esperado. - a senha do usuário deve ser atualizada. """ # with reset_pwd_url = url_for('admin.reset') credentials = { 'email': '*****@*****.**', 'password': '******' } # when create_user(credentials['email'], credentials['password'], True) with mail.record_messages() as outbox: response = self.client.post( reset_pwd_url, data={'email': credentials['email']}, follow_redirects=True) # then self.assertEqual(1, len(outbox)) email_msg = outbox[0] # recupero os links do email links_found = reset_pwd_url_pattern.findall(email_msg.html) # tem pelo menos 1 link, e tem só um link para o reset/password com token self.assertGreaterEqual(1, len(links_found)) resert_url_with_token = [url for url in links_found if reset_pwd_url in url][0] new_password = '******' response = self.client.post( resert_url_with_token, data={'password': new_password}, follow_redirects=True) self.assertStatus(response, 200) # verificação da nova senha do usuario user = get_user_by_email(credentials['email']) self.assertTrue(user.is_correct_password(new_password))
def create_superuser(): """ Cria um novo usuário a partir dos dados inseridos na linha de comandos. Para criar um novo usuário é necessario preencher: - email (deve ser válido é único, se já existe outro usuário com esse email deve inserir outro); - senha (modo echo off) - e se o usuário tem email confirmado (caso sim, pode fazer logim, caso que não, deve verificar por email) """ user_email = None user_password = None while user_email is None: user_email = raw_input(u'Email: ').strip() if user_email == '': user_email = None print u'Email não pode ser vazio' else: form = EmailForm(data={'email': user_email}) if not form.validate(): user_email = None print u'Deve inserir um email válido!' elif controllers.get_user_by_email(user_email): user_email = None print u'Já existe outro usuário com esse email!' os.system("stty -echo") while user_password is None: user_password = raw_input(u'Senha: ').strip() if user_password == '': user_password = None print u'Senha não pode ser vazio' os.system("stty echo") email_confirmed = raw_input('\nEmail confirmado? [y/N]: ').strip() if email_confirmed.upper() in ('Y', 'YES'): email_confirmed = True else: email_confirmed = False print u'Deve enviar o email de confirmação pelo admin' # cria usuario utils.create_user(user_email, user_password, email_confirmed) print u'Novo usuário criado com sucesso!'
def reset_with_token(self, token): try: ts = get_timed_serializer() email = ts.loads(token, salt="recover-key", max_age=current_app.config['TOKEN_MAX_AGE']) except Exception as e: abort(404) form = forms.PasswordForm(request.form) if admin.helpers.validate_form_on_submit(form): user = controllers.get_user_by_email(email=email) if not user.email_confirmed: return self.render('admin/auth/unconfirm_email.html') controllers.set_user_password(user, form.password.data) flash(_(u'Nova senha salva com sucesso!!')) return redirect(url_for('.index')) self._template_args['form'] = form self._template_args['token'] = token return self.render('admin/auth/reset_with_token.html')
def reset(self): form = forms.EmailForm(request.form) if admin.helpers.validate_form_on_submit(form): user = controllers.get_user_by_email(email=form.data['email']) if not user: abort(404, _(u'Usuário não encontrado')) if not user.email_confirmed: return self.render('admin/auth/unconfirm_email.html') was_sent, error_msg = user.send_reset_password_email() if was_sent: flash(_(u'Enviamos as instruções para recuperar a senha para: %(email)s', email=user.email)) else: flash(_(u'Ocorreu um erro no envio das instruções por email para: %(email)s. Erro: %(error)s', email=user.email, error=error_msg), 'error') return redirect(url_for('.index')) self._template_args['form'] = form return self.render('admin/auth/reset.html')
def validate_password(self, field): user = get_user_by_email(self.email.data) if user is None: raise validators.ValidationError(_(u"Usuário inválido")) if not user.is_correct_password(self.password.data): raise validators.ValidationError(_(u"Senha inválida"))
def test_create_user_from_admin_page_creates_a_new_user(self): """ Com: - usuario administrador (com email confirmado) Quando: 1. acessamos /admin e cadastramos um novo usuário 2. acesssamos o link enviado por email Verificamos: - o usuário é criado. - o usuário administrador é notificodo do sucesso da operação. - o novo usuário não tem email confirmado. - o novo usuário é notificado por email para confirmar email. """ # with admin_user = { 'email': '*****@*****.**', 'password': '******', } create_user(admin_user['email'], admin_user['password'], True) new_user = { 'email': '*****@*****.**', 'password': '******' } login_url = url_for('admin.login_view') create_user_url = '/admin/user/new/' expected_msgs = [ u'Enviamos o email de confirmação para: %s' % new_user['email'], u'Registro criado com sucesso.', ] # when with mail.record_messages() as outbox: with self.client as client: # login do usuario admin login_response = client.post( login_url, data=admin_user, follow_redirects=True) self.assertStatus(login_response, 200) self.assertTemplateUsed('admin/index.html') self.assertTrue(current_user.is_authenticated) # requisição da ação para enviar email de confirmação create_user_response = client.post( create_user_url, data={'email': new_user['email']}, follow_redirects=True) # then self.assertStatus(create_user_response, 200) self.assertTemplateUsed('admin/model/list.html') for msg in expected_msgs: self.assertIn(msg, action_response.data.decode('utf-8')) # temos um email self.assertEqual(1, len(outbox)) email_msg = outbox[0] # pegamos o link com token links_found = email_confirm_url_pattern.findall(email_msg.html) # tem pelo menos 1 link, e tem só um link para o reset/password com token self.assertGreaterEqual(1, len(links_found)) email_confirmation_url_with_token = [url for url in links_found if '/admin/confirm/' in url] # temos a url com o token self.assertEqual(1, len(email_confirmation_url_with_token)) email_confirmation_url_with_token = email_confirmation_url_with_token[0] self.assertIsNotNone(email_confirmation_url_with_token) self.assertFalse(email_confirmation_url_with_token == '') # acessamos o link do email user = get_user_by_email(new_user['email']) confirmation_response = self.client.get(email_confirmation_url_with_token, follow_redirects=True) self.assertStatus(confirmation_response, 200) self.assertTemplateUsed('admin/index.html') # confirmação com sucesso self.assertIn(expected_msg, confirmation_response.data.decode('utf-8')) # confirmamos alteração do usuário self.assertTrue(user.email_confirmed)
def test_open_confirm_url_with_token_sent_via_email_open_the_correct_page(self): """ Com: - o usuário 'administrador' logado (email confirmado) - um novo usuário, com email NÃO confirmado Quando: 1. enviamos emails de confirmação (utilizando a ação do admin/user) 2. acesssamos o link enviado por email Verificamos: - que o email enviado contem um link para confirmar email. - após acessar o link, a página é a correta. - após acessar o link, a págian mostra a notificação de operação ok. - após acessar o link, o usuário tem seu email confirmado. """ # with admin_user = { 'email': '*****@*****.**', 'password': '******', } create_user(admin_user['email'], admin_user['password'], True) normal_user = { 'email': '*****@*****.**', 'password': '******' } create_user(normal_user['email'], normal_user['password'], False) login_url = url_for('admin.login_view') action_payload = { 'action': 'confirm_email', 'rowid': get_user_by_email(normal_user['email']).id, 'url': '/admin/user/' } expected_msg = u'Email: %s confirmado com sucesso!' % normal_user['email'] # when # login do usuario admin login_response = self.client.post( login_url, data=admin_user, follow_redirects=True) self.assertStatus(login_response, 200) # requisição da ação para enviar email de confirmação with mail.record_messages() as outbox: action_response = self.client.post( '/admin/user/action/', data=action_payload, follow_redirects=True) # then self.assertStatus(action_response, 200) # temos um email self.assertEqual(1, len(outbox)) email_msg = outbox[0] # pegamos o link com token links_found = email_confirm_url_pattern.findall(email_msg.html) # tem pelo menos 1 link, e tem só um link para o reset/password com token self.assertGreaterEqual(1, len(links_found)) email_confirmation_url_with_token = [url for url in links_found if '/admin/confirm/' in url] # temos a url com o token self.assertEqual(1, len(email_confirmation_url_with_token)) email_confirmation_url_with_token = email_confirmation_url_with_token[0] # acessamos o link do email confirmation_response = self.client.get(email_confirmation_url_with_token, follow_redirects=True) self.assertStatus(confirmation_response, 200) self.assertTemplateUsed('admin/index.html') # confirmação com sucesso self.assertIn(expected_msg, confirmation_response.data.decode('utf-8')) # confirmamos alteração do usuário user = get_user_by_email(normal_user['email']) self.assertTrue(user.email_confirmed)
def test_confirmation_email_send_email_with_token(self): """ Com: - o usuário 'administrador' logado (email confirmado) - um novo usuário, com email NÃO confirmado Quando: 1. enviamos emails de confirmação (utilizando a ação do admin/user) 2. Verificamos: - que o email enviado contem um link para confirmar email. - o email é enviado para o destinatario certo. - após a operação, a página é a correta. - as notifiação para usuário deve ser mostrada na página. """ # with admin_user = { 'email': '*****@*****.**', 'password': '******', } create_user(admin_user['email'], admin_user['password'], True) normal_user = { 'email': '*****@*****.**', 'password': '******' } create_user(normal_user['email'], normal_user['password'], False) login_url = url_for('admin.login_view') action_payload = { 'action': 'confirm_email', 'rowid': get_user_by_email(normal_user['email']).id, 'url': '/admin/user/' } expected_email_sent_notifications = [ u"Enviamos o email de confirmação para: %s" % normal_user['email'], u"1 usuários foram notificados com sucesso!", ] expected_email = { 'subject': u'Confirmação de email', 'recipients': [normal_user['email'], ], } # when # login do usuario admin login_response = self.client.post( login_url, data=admin_user, follow_redirects=True) self.assertStatus(login_response, 200) self.assertTemplateUsed('admin/index.html') # requisição da ação para enviar email de confirmação with mail.record_messages() as outbox: action_response = self.client.post( '/admin/user/action/', data=action_payload, follow_redirects=True) # then self.assertStatus(action_response, 200) self.assertTemplateUsed('admin/model/list.html') for msg in expected_email_sent_notifications: self.assertIn(msg, action_response.data.decode('utf-8')) # temos um email self.assertEqual(1, len(outbox)) email_msg = outbox[0] # email enviado ao destinatario certo, com assunto certo self.assertEqual(expected_email['recipients'], email_msg.recipients) self.assertEqual(expected_email['subject'], email_msg.subject.decode('utf-8')) # pegamos o link com token links_found = email_confirm_url_pattern.findall(email_msg.html) # tem pelo menos 1 link, e tem só um link para o reset/password com token self.assertGreaterEqual(1, len(links_found)) email_confirmation_url_with_token = [url for url in links_found if '/admin/confirm/' in url] # temos a url com o token self.assertEqual(1, len(email_confirmation_url_with_token)) email_confirmation_url_with_token = email_confirmation_url_with_token[0] self.assertIsNotNone(email_confirmation_url_with_token) self.assertFalse(email_confirmation_url_with_token == '')