mirror of
https://github.com/wassname/flask-security.git
synced 2026-08-18 12:00:35 +08:00
Cleanup and some more messaging additions
This commit is contained in:
@@ -69,8 +69,8 @@ _default_config = {
|
||||
'DEFAULT_HTTP_AUTH_REALM': 'Login Required'
|
||||
}
|
||||
|
||||
#: Default Flask-Security flash messages
|
||||
_default_flash_messages = {
|
||||
#: Default Flask-Security messages
|
||||
_default_messages = {
|
||||
'UNAUTHORIZED': ('You do not have permission to view this resource.', 'error'),
|
||||
'EMAIL_CONFIRMED': ('Your email has been confirmed. You may now log in.', 'success'),
|
||||
'ALREADY_CONFIRMED': ('Your email has already been confirmed', 'info'),
|
||||
@@ -78,12 +78,14 @@ _default_flash_messages = {
|
||||
'PASSWORD_RESET_REQUEST': ('Instructions to reset your password have been sent to %(email)s.', 'info'),
|
||||
'PASSWORD_RESET_EXPIRED': ('You did not reset your password within %(within)s. New instructions have been sent to %(email)s.', 'error'),
|
||||
'INVALID_RESET_PASSWORD_TOKEN': ('Invalid reset password token', 'error'),
|
||||
'CONFIRMATION_REQUIRED': ('Email requires confirmation', 'error'),
|
||||
'CONFIRMATION_REQUEST': ('A new confirmation code has been sent to %(email)s.', 'info'),
|
||||
'CONFIRMATION_EXPIRED': ('You did not confirm your email within %(within)s. New instructions to confirm your email have been sent to %(email)s.', 'error'),
|
||||
'LOGIN_EXPIRED': ('You did not login within %(within)s. New instructions to login to your account have been sent to %(email)s.', 'error'),
|
||||
'LOGIN_EMAIL_SENT': ('Instructions to log in to your account have been sent to %(email)s', 'success'),
|
||||
'INVALID_LOGIN_TOKEN': ('Invalid login token', 'error'),
|
||||
'DISABLED_ACCOUNT': ('Account is disabled', 'error')
|
||||
'DISABLED_ACCOUNT': ('Account is disabled', 'error'),
|
||||
'PASSWORDLESS_LOGIN_SUCCESSFUL': ('You have successfuly logged in', 'success')
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +235,7 @@ class Security(object):
|
||||
for key, value in _default_config.items():
|
||||
app.config.setdefault('SECURITY_' + key, value)
|
||||
|
||||
for key, value in _default_flash_messages.items():
|
||||
for key, value in _default_messages.items():
|
||||
app.config.setdefault('SECURITY_MSG_' + key, value)
|
||||
|
||||
identity_loaded.connect_via(app)(_on_identity_loaded)
|
||||
|
||||
@@ -92,9 +92,7 @@ class LoginForm(Form, EmailFormMixin, PasswordFormMixin):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LoginForm, self).__init__(*args, **kwargs)
|
||||
|
||||
if request.method == 'GET':
|
||||
self.next.data = request.args.get('next', None)
|
||||
self.next.data = request.args.get('next', None)
|
||||
|
||||
|
||||
class RegisterForm(Form,
|
||||
|
||||
@@ -15,6 +15,7 @@ from werkzeug.datastructures import MultiDict
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
from flask_security.confirmable import confirm_by_token, reset_confirmation_token
|
||||
from flask_security.core import current_user
|
||||
from flask_security.decorators import login_required
|
||||
from flask_security.exceptions import ConfirmationError, BadCredentialsError, \
|
||||
ResetPasswordError, PasswordlessLoginError
|
||||
@@ -138,16 +139,17 @@ def send_login():
|
||||
|
||||
if user.is_active():
|
||||
send_login_instructions(user, form.next.data)
|
||||
msg, cat = get_message('LOGIN_EMAIL_SENT', email=user.email)
|
||||
do_flash(get_message('LOGIN_EMAIL_SENT', email=user.email))
|
||||
else:
|
||||
msg, cat = get_message('DISABLED_ACCOUNT')
|
||||
|
||||
do_flash(msg, cat)
|
||||
do_flash(get_message('DISABLED_ACCOUNT'))
|
||||
|
||||
return render_template('security/logins/passwordless.html', login_form=form)
|
||||
|
||||
|
||||
def token_login(token):
|
||||
if current_user.is_authenticated():
|
||||
return redirect(_security.post_login_view)
|
||||
|
||||
try:
|
||||
user, next = login_by_token(token)
|
||||
|
||||
@@ -161,6 +163,8 @@ def token_login(token):
|
||||
|
||||
return redirect(request.referrer or _security.login_manager.login_view)
|
||||
|
||||
do_flash(get_message('PASSWORDLESS_LOGIN_SUCCESSFUL'))
|
||||
|
||||
return redirect(next or _security.post_login_view)
|
||||
|
||||
|
||||
@@ -196,10 +200,6 @@ def confirm_email(token):
|
||||
if e.user:
|
||||
reset_confirmation_token(e.user)
|
||||
|
||||
msg, cat = get_message('CONFIRMATION_EXPIRED',
|
||||
within=_security.confirm_email_within,
|
||||
email=e.user.email)
|
||||
|
||||
do_flash(msg, cat)
|
||||
|
||||
return redirect(get_url(_security.confirm_error_view))
|
||||
|
||||
@@ -71,3 +71,6 @@ class SecurityTest(TestCase):
|
||||
return TestCase.assertIsNotNone(self, obj, msg)
|
||||
|
||||
return self.assertTrue(obj is not None)
|
||||
|
||||
def get_message(self, key, **kwargs):
|
||||
return self.app.config['SECURITY_MSG_' + key][0] % kwargs
|
||||
|
||||
@@ -101,7 +101,7 @@ class DefaultSecurityTests(SecurityTest):
|
||||
|
||||
def test_unauthenticated_role_required(self):
|
||||
r = self._get('/admin', follow_redirects=True)
|
||||
self.assertIn('You do not have permission to view this resource', r.data)
|
||||
self.assertIn(self.get_message('UNAUTHORIZED'), r.data)
|
||||
|
||||
def test_multiple_role_required(self):
|
||||
for user in ("matt@lp.com", "joe@lp.com"):
|
||||
@@ -270,7 +270,7 @@ class ConfirmableTests(SecurityTest):
|
||||
e = 'dude@lp.com'
|
||||
self.register(e)
|
||||
r = self.authenticate(email=e)
|
||||
self.assertIn('Email requires confirmation', r.data)
|
||||
self.assertIn(self.get_message('CONFIRMATION_REQUIRED'), r.data)
|
||||
|
||||
def test_register_sends_confirmation_email(self):
|
||||
e = 'dude@lp.com'
|
||||
@@ -397,7 +397,8 @@ class RecoverableTests(SecurityTest):
|
||||
'password': 'newpassword',
|
||||
'password_confirm': 'newpassword'
|
||||
}, follow_redirects=True)
|
||||
self.assertIn('Invalid reset password token', r.data)
|
||||
|
||||
self.assertIn(self.get_message('INVALID_RESET_PASSWORD_TOKEN'), r.data)
|
||||
|
||||
def test_reset_password_twice_flashes_invalid_token_msg(self):
|
||||
with capture_reset_password_requests() as requests:
|
||||
@@ -412,7 +413,7 @@ class RecoverableTests(SecurityTest):
|
||||
url = '/reset/' + t
|
||||
r = self.client.post(url, data=data, follow_redirects=True)
|
||||
r = self.client.post(url, data=data, follow_redirects=True)
|
||||
self.assertIn('Invalid reset password token', r.data)
|
||||
self.assertIn(self.get_message('INVALID_RESET_PASSWORD_TOKEN'), r.data)
|
||||
|
||||
|
||||
class ExpiredResetPasswordTest(SecurityTest):
|
||||
@@ -492,7 +493,7 @@ class PasswordlessTests(SecurityTest):
|
||||
self.assertIn(msg, r.data)
|
||||
|
||||
r = self.client.get('/auth/' + token, follow_redirects=True)
|
||||
self.assertIn('Hello ' + e, r.data)
|
||||
self.assertIn(self.get_message('PASSWORDLESS_LOGIN_SUCCESSFUL'), r.data)
|
||||
|
||||
r = self.client.get('/profile')
|
||||
self.assertIn('Profile Page', r.data)
|
||||
@@ -502,6 +503,17 @@ class PasswordlessTests(SecurityTest):
|
||||
r = self._get('/auth/bogus', follow_redirects=True)
|
||||
self.assertIn(msg, r.data)
|
||||
|
||||
def test_token_login_forwards_to_post_login_view_when_already_authenticated(self):
|
||||
with capture_passwordless_login_requests() as requests:
|
||||
self.client.post('/auth', data=dict(email='matt@lp.com'), follow_redirects=True)
|
||||
token = requests[0]['login_token']
|
||||
|
||||
r = self.client.get('/auth/' + token, follow_redirects=True)
|
||||
self.assertIn(self.get_message('PASSWORDLESS_LOGIN_SUCCESSFUL'), r.data)
|
||||
|
||||
r = self.client.get('/auth/' + token, follow_redirects=True)
|
||||
self.assertNotIn(self.get_message('PASSWORDLESS_LOGIN_SUCCESSFUL'), r.data)
|
||||
|
||||
|
||||
class ExpiredLoginTokenTests(SecurityTest):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user