flaschengeist/flaschengeist/plugins/auth/__init__.py

178 lines
5.8 KiB
Python

"""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/<token>", methods=["DELETE"])
@login_required()
def delete_session(token, current_session, **kwargs):
"""Delete a session aka "logout"
Route: ``/auth/<token>`` | 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/<token>", methods=["GET"])
@login_required()
def get_session(token, current_session, **kwargs):
"""Retrieve information about a session
Route: ``/auth/<token>`` | 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/<token>", methods=["PUT"])
@login_required()
def set_lifetime(token, current_session, **kwargs):
"""Set lifetime of a session
Route: ``/auth/<token>`` | 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/<token>/user", methods=["GET"])
@login_required()
def get_assocd_user(token, current_session, **kwargs):
"""Retrieve user owning a session
Route: ``/auth/<token>/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()