Add customizable unauthorized URL. Fixes #23

This commit is contained in:
Matt Wright
2012-07-12 12:47:21 -04:00
parent 8d1bdca1de
commit dfcb3cdcc6
6 changed files with 47 additions and 13 deletions
+4
View File
@@ -106,6 +106,10 @@ def create_app(auth_config):
def admin_or_editor():
return render_template('index.html', content='Admin or Editor Page')
@app.route('/unauthorized')
def unauthorized():
return render_template('unauthorized.html')
return app
+3
View File
@@ -0,0 +1,3 @@
{% include "_messages.html" %}
{% include "_nav.html" %}
<h1>You are not allowed to access the requested resouce</h1>
+1
View File
@@ -42,6 +42,7 @@ _default_config = {
'RESET_PASSWORD_ERROR_VIEW': '/',
'POST_REGISTER_VIEW': None,
'POST_CONFIRM_VIEW': None,
'UNAUTHORIZED_VIEW': None,
'DEFAULT_ROLES': [],
'CONFIRMABLE': False,
'REGISTERABLE': False,
+26 -10
View File
@@ -11,7 +11,7 @@
from functools import wraps
from flask import current_app as app, Response, request, abort, redirect
from flask import current_app as app, Response, request, redirect
from flask.ext.login import login_required, login_url, current_user
from flask.ext.principal import RoleNeed, Permission
from werkzeug.local import LocalProxy
@@ -23,18 +23,26 @@ from . import utils
_security = LocalProxy(lambda: app.security)
_default_http_auth_msg = """
_default_unauthorized_txt = """
<h1>Unauthorized</h1>
<p>The server could not verify that you are authorized to access the URL
requested. You either supplied the wrong credentials (e.g. a bad password),
or your browser doesn't understand how to supply the credentials required.</p>
<p>In case you are allowed to request the document, please check your
user-id and password and try again.</p>
"""
def _check_token():
def _get_unauthorized_response(text=None, headers=None):
text = text or _default_unauthorized_txt
headers = headers or {}
return Response(_default_unauthorized_txt, 401, headers)
def _get_unauthorized_view():
cv = utils.get_url(utils.config_value('UNAUTHORIZED_VIEW'))
return (cv or request.referrer or '/')
def _check_token():
header_key = app.security.token_authentication_header
args_key = app.security.token_authentication_key
@@ -77,7 +85,7 @@ def http_auth_required(fn):
if _check_http_auth():
return fn(*args, **kwargs)
return Response(_default_http_auth_msg, 401, headers)
return _get_unauthorized_response(headers=headers)
return decorated
@@ -89,7 +97,7 @@ def auth_token_required(fn):
if _check_token():
return fn(*args, **kwargs)
abort(401)
return _get_unauthorized_response()
return decorated
@@ -111,6 +119,7 @@ def roles_required(*roles):
perms = [Permission(RoleNeed(role)) for role in roles]
def wrapper(fn):
@wraps(fn)
def decorated_view(*args, **kwargs):
if not current_user.is_authenticated():
@@ -120,10 +129,14 @@ def roles_required(*roles):
for perm in perms:
if not perm.can():
app.logger.debug('Identity does not provide the '
'roles: %s' % [r for r in roles])
return redirect(request.referrer or '/')
'roles: %s' % [r for r in roles])
return redirect(_get_unauthorized_view())
return fn(*args, **kwargs)
return decorated_view
return wrapper
@@ -144,6 +157,7 @@ def roles_accepted(*roles):
perm = Permission(*[RoleNeed(role) for role in roles])
def wrapper(fn):
@wraps(fn)
def decorated_view(*args, **kwargs):
if not current_user.is_authenticated():
@@ -162,6 +176,8 @@ def roles_accepted(*roles):
utils.do_flash('You do not have permission to '
'view this resource', 'error')
return redirect(request.referrer or '/')
return redirect(_get_unauthorized_view())
return decorated_view
return wrapper
@@ -1,6 +1,6 @@
{% include "security/messages.html" %}
<h1>Change password</h1>
<form action="{{ url_for('flask_security.reset_password', token=reset_token) }}" method="POST" name="reset_password_form">
<form action="{{ url_for('flask_security.reset_password', token=password_reset_token) }}" method="POST" name="reset_password_form">
{{ reset_password_form.hidden_tag() }}
{{ reset_password_form.password.label }} {{ reset_password_form.password }}<br/>
{{ reset_password_form.password_confirm.label }} {{ reset_password_form.password_confirm }}<br/>
+12 -2
View File
@@ -140,7 +140,8 @@ class ConfiguredURLTests(SecurityTest):
'SECURITY_LOGIN_VIEW': '/custom_login',
'SECURITY_POST_LOGIN_VIEW': '/post_login',
'SECURITY_POST_LOGOUT_VIEW': '/post_logout',
'SECURITY_POST_REGISTER_VIEW': '/post_register'
'SECURITY_POST_REGISTER_VIEW': '/post_register',
'SECURITY_UNAUTHORIZED_VIEW': '/unauthorized'
}
def test_login_view(self):
@@ -157,10 +158,19 @@ class ConfiguredURLTests(SecurityTest):
self.assertIn('Post Logout', r.data)
def test_register(self):
data = dict(email='dude@lp.com', password='password', password_confirm='password')
data = dict(email='dude@lp.com',
password='password',
password_confirm='password')
r = self.client.post('/register', data=data, follow_redirects=True)
self.assertIn('Post Register', r.data)
def test_unauthorized(self):
self.authenticate("joe@lp.com", endpoint="/custom_auth")
r = self._get("/admin", follow_redirects=True)
msg = 'You are not allowed to access the requested resouce'
self.assertIn(msg, r.data)
class RegisterableTests(SecurityTest):
AUTH_CONFIG = {