Merge pull request #73 from apahomov/multiple-auth-mechanisms

Multiple auth mechanisms
This commit is contained in:
Matt Wright
2013-01-16 19:37:55 -08:00
3 changed files with 56 additions and 1 deletions
+32
View File
@@ -48,6 +48,8 @@ def _check_token():
args_key = _security.token_authentication_key
header_token = request.headers.get(header_key, None)
token = request.args.get(args_key, header_token)
if request.json:
token = request.json.get(args_key, token)
serializer = _security.remember_token_serializer
try:
@@ -113,6 +115,36 @@ def auth_token_required(fn):
return decorated
def auth_required(*auth_methods):
"""
Decorator that protects enpoints through multiple mechanisms
Example::
@app.route('/dashboard')
@auth_required('token', 'session')
def dashboard():
return 'Dashboard'
:param auth_methods: Specified mechanisms.
"""
login_mechanisms = {
'token': lambda: _check_token(),
'basic': lambda: _check_http_auth(),
'session': lambda: current_user.is_authenticated()
}
def wrapper(fn):
@wraps(fn)
def decorated_view(*args, **kwargs):
mechanisms = [login_mechanisms.get(method) for method in auth_methods]
for mechanism in mechanisms:
if mechanism and mechanism():
return fn(*args, **kwargs)
return _get_unauthorized_response()
return decorated_view
return wrapper
def roles_required(*roles):
"""Decorator which specifies that a user must have all the specified roles.
Example::
+18
View File
@@ -169,6 +169,24 @@ class DefaultSecurityTests(SecurityTest):
self.assertEquals('Basic realm="My Realm"',
r.headers['WWW-Authenticate'])
def test_multi_auth_basic(self):
r = self._get('/multi_auth', headers={
'Authorization': 'Basic ' + base64.b64encode("joe@lp.com:password")
})
self.assertIn('Basic', r.data)
def test_multi_auth_token(self):
r = self.json_authenticate()
data = json.loads(r.data)
token = data['response']['user']['authentication_token']
r = self._get('/multi_auth?auth_token=' + token)
self.assertIn('Token', r.data)
def test_multi_auth_session(self):
self.authenticate()
r = self._get('/multi_auth')
self.assertIn('Session', r.data)
def test_user_deleted_during_session_reverts_to_anonymous_user(self):
self.authenticate()
+6 -1
View File
@@ -4,7 +4,7 @@ from flask import Flask, render_template, current_app
from flask.ext.mail import Mail
from flask.ext.security import login_required, roles_required, roles_accepted
from flask.ext.security.decorators import http_auth_required, \
auth_token_required
auth_token_required, auth_required
from flask.ext.security.utils import encrypt_password
from werkzeug.local import LocalProxy
@@ -50,6 +50,11 @@ def create_app(config):
def token():
return render_template('index.html', content='Token Authentication')
@app.route('/multi_auth')
@auth_required('session', 'token', 'basic')
def multi_auth():
return render_template('index.html', content='Session, Token, Basic auth')
@app.route('/post_logout')
def post_logout():
return render_template('index.html', content='Post Logout')