Source code for api.base_controller

import logging

import flask
from flask import Response
from flask_babel import lazy_gettext as _

from .circulation_exceptions import *
from core.model import (
    Library,
    Loan,
    Patron,
    get_one,
)
from core.util.problem_detail import ProblemDetail
from .problem_details import *


[docs]class BaseCirculationManagerController(object): """Define minimal standards for a circulation manager controller, mainly around authentication. """ def __init__(self, manager): """:param manager: A CirculationManager object.""" self.manager = manager self._db = self.manager._db self.url_for = self.manager.url_for self.cdn_url_for = self.manager.cdn_url_for
[docs] def authorization_header(self): """Get the authentication header.""" # This is the basic auth header. header = flask.request.authorization # If we're using a token instead, flask doesn't extract it for us. if not header: if 'Authorization' in flask.request.headers: header = flask.request.headers['Authorization'] return header
@property def request_patron(self): """The currently authenticated patron for this request, if any. Most of the time you can use flask.request.patron, but sometimes it's not clear whether authenticated_patron_from_request() (which sets flask.request.patron) has been called, and authenticated_patron_from_request has a complicated return value. :return: A Patron, if one could be authenticated; None otherwise. """ if not hasattr(flask.request, 'patron'): # Call authenticated_patron_from_request for its side effect # of setting flask.request.patron self.authenticated_patron_from_request() return flask.request.patron
[docs] def authenticated_patron_from_request(self): """Try to authenticate a patron for the incoming request. When this method returns, flask.request.patron will be set, though the value it's set to may be None. :return: A Patron, if possible. If no authentication was provided, a Flask Response. If a problem occured during authentication, a ProblemDetail. """ # Start off by assuming authentication will not work. flask.request.patron = None header = self.authorization_header() if not header: # No credentials were provided. return self.authenticate() try: patron = self.authenticated_patron(header) except RemoteInitiatedServerError as e: return REMOTE_INTEGRATION_FAILED.detailed( _("Error in authentication service") ) if patron is None: # Credentials were provided but they turned out not # to identify anyone in particular. return self.authenticate() if isinstance(patron, Patron): flask.request.patron = patron return patron
[docs] def authenticated_patron(self, authorization_header): """Look up the patron authenticated by the given authorization header. The header could contain a barcode and pin or a token for an external service. If there's a problem, return a Problem Detail Document. If there's no problem, return a Patron object. """ patron = self.manager.auth.authenticated_patron( self._db, authorization_header ) if not patron: return INVALID_CREDENTIALS if isinstance(patron, ProblemDetail): return patron return patron
[docs] def authenticate(self): """Sends a 401 response that demands authentication.""" headers = self.manager.auth.create_authentication_headers() data = self.manager.authentication_for_opds_document return Response(data, 401, headers)
[docs] def library_through_external_loan_identifier(self, loan_external_identifier): """Look up the library the user is trying to access using a loan's external identifier. We assume that the external identifier is globally unique which is true, for example, in the case of using Readium LCP. :param loan_external_identifier: External identifier of the patron's loan :type loan_external_identifier: basestring :return: Library the patron is trying to access :rtype: Library """ self.manager.reload_settings_if_changed() loan = get_one(self._db, Loan, external_identifier=loan_external_identifier) if loan is None: return LOAN_NOT_FOUND library = loan.patron.library flask.request.library = library return library
[docs] def library_for_request(self, library_short_name): """Look up the library the user is trying to access. Since this is called on pretty much every request, it's also an appropriate time to check whether the site configuration has been changed and needs to be updated. """ self.manager.reload_settings_if_changed() if library_short_name: library = Library.lookup(self._db, short_name=library_short_name) else: library = Library.default(self._db) if not library: return LIBRARY_NOT_FOUND flask.request.library = library return library