"""Authentication plugin, provides basic routes Allow management of authentication, login, logout, etc. """ from flask import Blueprint, request, jsonify from werkzeug.exceptions import Forbidden, BadRequest, Unauthorized from flaschengeist import logger from flaschengeist.plugins import Plugin from flaschengeist.utils.HTTP import no_content, created from flaschengeist.utils.decorators import login_required from flaschengeist.controller import sessionController, userController class AuthRoutePlugin(Plugin): id = "dev.flaschengeist.auth" blueprint = Blueprint("auth", __name__) @AuthRoutePlugin.blueprint.route("/auth", methods=["POST"]) def login(): """Login in an user and create a session Route: ``/auth`` | Method: ``POST`` POST-data: ``{userid: string, password: string}`` Returns: A JSON object with `flaschengeist.models.user.User` and created `flaschengeist.models.session.Session` or HTTP error """ logger.debug("Start log in.") data = request.get_json() try: userid = str(data["userid"]) password = str(data["password"]) except (KeyError, ValueError, TypeError): raise BadRequest("Missing parameter(s)") logger.debug(f"search user {userid} in database") user = userController.login_user(userid, password) if not user: raise Unauthorized session = sessionController.create(user, user_agent=request.user_agent) logger.debug(f"token is {session.token}") logger.info(f"User {userid} logged in.") # Lets cleanup the DB sessionController.clear_expired() return created(session) @AuthRoutePlugin.blueprint.route("/auth", methods=["GET"]) @login_required() def get_sessions(current_session, **kwargs): """Get all valid sessions of current user Route: ``/auth`` | Method: ``GET`` Returns: A JSON array of `flaschengeist.models.session.Session` or HTTP error """ sessions = sessionController.get_users_sessions(current_session.user_) return jsonify(sessions) @AuthRoutePlugin.blueprint.route("/auth/", methods=["DELETE"]) @login_required() def delete_session(token, current_session, **kwargs): """Delete a session aka "logout" Route: ``/auth/`` | Method: ``DELETE`` Returns: 200 Status (empty) or HTTP error """ logger.debug("Try to delete access token {{ {} }}".format(token)) session = sessionController.get_session(token, current_session.user_) if not session: logger.debug("Token not found in database!") # Return 403 error, so that users can not bruteforce tokens # Valid tokens from other users and invalid tokens now are looking the same raise Forbidden sessionController.delete_session(session) sessionController.clear_expired() return "" @AuthRoutePlugin.blueprint.route("/auth/", methods=["GET"]) @login_required() def get_session(token, current_session, **kwargs): """Retrieve information about a session Route: ``/auth/`` | Method: ``GET`` Attributes: token: Token identifying session to retrieve current_session: Session sent with Authorization Header Returns: JSON encoded `flaschengeist.models.session.Session` or HTTP error """ logger.debug("get token {{ {} }}".format(token)) session = sessionController.get_session(token, current_session.user_) if not session: # Return 403 error, so that users can not bruteforce tokens # Valid tokens from other users and invalid tokens now are looking the same raise Forbidden return jsonify(session) @AuthRoutePlugin.blueprint.route("/auth/", methods=["PUT"]) @login_required() def set_lifetime(token, current_session, **kwargs): """Set lifetime of a session Route: ``/auth/`` | Method: ``PUT`` POST-data: ``{value: int}`` Attributes: token: Token identifying the session current_session: Session sent with Authorization Header Returns: HTTP-204 or HTTP error """ session = sessionController.get_session(token, current_session.user_) if not session: # Return 403 error, so that users can not bruteforce tokens # Valid tokens from other users and invalid tokens now are looking the same raise Forbidden try: lifetime = request.get_json()["value"] logger.debug(f"set lifetime >{lifetime}< to access token >{token}<") sessionController.set_lifetime(session, lifetime) return jsonify(sessionController.get_session(token, current_session.user_)) except (KeyError, TypeError): raise BadRequest @AuthRoutePlugin.blueprint.route("/auth//user", methods=["GET"]) @login_required() def get_assocd_user(token, current_session, **kwargs): """Retrieve user owning a session Route: ``/auth//user`` | Method: ``GET`` Attributes: token: Token identifying the session current_session: Session sent with Authorization Header Returns: JSON encoded `flaschengeist.models.user.User` or HTTP error """ logger.debug("get token {{ {} }}".format(token)) session = sessionController.get_session(token, current_session.user_) if not session: # Return 403 error, so that users can not bruteforce tokens # Valid tokens from other users and invalid tokens now are looking the same raise Forbidden return jsonify(session.user_) @AuthRoutePlugin.blueprint.route("/auth/reset", methods=["POST"]) def reset_password(): data = request.get_json() if "userid" in data: user = userController.find_user(data["userid"]) if user: userController.request_reset(user) elif "password" in data and "token" in data: userController.reset_password(data["token"], data["password"]) else: raise BadRequest("Missing parameter(s)") return no_content()