Source code for evesrp.views.login
from __future__ import absolute_import
from base64 import urlsafe_b64decode
import binascii
from flask import render_template, url_for, abort, session, redirect, request,\
current_app, g, Blueprint
from flask.ext.login import login_required, logout_user, LoginManager
from six.moves import map
from sqlalchemy.orm.exc import NoResultFound
from .. import csrf
from ..auth.models import User, APIKey
from ..util import ensure_unicode
blueprint = Blueprint('login', __name__)
login_manager = LoginManager()
@login_manager.user_loader
[docs]def login_loader(userid):
"""Pull a user object from the database.
This is used for loading users from existing sessions.
"""
return User.query.get(int(userid))
@login_manager.request_loader
def apikey_loader(request):
api_key = ensure_unicode(request.values.get('apikey'))
if api_key and request.method == 'GET':
api_key = api_key.replace(u',', u'=')
try:
api_key = urlsafe_b64decode(api_key.encode('utf-8'))
except binascii.Error:
# If the api key is malformed, binascii throws an exception.
# Rejected.
return None
try:
key = APIKey.query.filter_by(key=api_key).one()
except NoResultFound:
pass
else:
return key.user
# returning None signifies failure for this method
return None
@blueprint.route('/login/', methods=['GET', 'POST'])
[docs]def login():
"""Presents the login form and processes responses from that form.
When a POST request is recieved, this function passes control to the
appropriate :py:meth:`login <evesrp.auth.AuthMethod.login>` method.
"""
# forms is a list of tuples. The tuples are
# (AuthMethod instance, AuthForm instance)
forms = []
for auth_method in current_app.auth_methods:
prefix = auth_method.safe_name
form = auth_method.form()
forms.append((auth_method, form(prefix=prefix)))
if request.method == 'POST':
# Find the form that was submitted. The unique prefix for each form
# means only one form.submit is going to be valid.
for auth_tuple in forms:
if auth_tuple[1].submit.data:
auth_method, form = auth_tuple
break
else:
abort(400)
if form.validate():
return auth_method.login(form)
return render_template('login.html', forms=forms)
login_manager.login_view = 'login.login'
# 302 redirects let the request method change to GET if it started as POST.
# By defining routes for both of these paths, the implicit redirect for the
# first route is skipped.
@blueprint.route('/login/<string:auth_method>', methods=['GET', 'POST'])
@blueprint.route('/login/<string:auth_method>/', methods=['GET', 'POST'])
[docs]def auth_method_login(auth_method):
"""Trampoline for :py:class:`~evesrp.auth.AuthMethod`\-specific views.
See :py:meth:`Authmethod.view <evesrp.auth.AuthMethod.view>` for more
details.
"""
method_map = dict(map((lambda m: (m.safe_name, m)),
current_app.auth_methods))
return method_map[auth_method].view()
@blueprint.route('/logout/')
@login_required
[docs]def logout():
"""Logs the current user out.
Redirects to :py:func:`.index`.
"""
logout_user()
return redirect(url_for('index'))