fix(users): Fix deleting users

Remove all internal references, e.g. sessions, attributes, password reset requests.

Add hook for plugins.

If not deletable remove at least all personal data
This commit is contained in:
Ferdinand Thiessen 2021-12-02 21:27:59 +01:00
parent 50fa39be4f
commit d0674e8876
5 changed files with 45 additions and 13 deletions

View File

@ -1,5 +1,6 @@
import secrets
from io import BytesIO
from sqlalchemy import exc
from flask import current_app
from datetime import datetime, timedelta, timezone
from flask.helpers import send_file
@ -168,11 +169,34 @@ def find_user(uid_mail):
return user
def delete(user):
@Hook
def delete_user(user: User):
"""Delete given user"""
# First let the backend delete the user, as this might fail
current_app.config["FG_AUTH_BACKEND"].delete_user(user)
# Clear all easy relationships
user.avatar_ = None
user._attributes.clear()
user.roles_.clear()
user.sessions_.clear()
user.reset_requests_.clear()
db.session.commit()
try:
# Delete the user
db.session.delete(user)
db.session.commit()
except exc.IntegrityError:
logger.error("Delete of user failed, there might be ForeignKey contraits from disabled plugins", exec_info=True)
# Remove at least all personal data
user.userid = f"__deleted_user__{user.id_}"
user.display_name = "DELETED USER"
user.firstname = ""
user.lastname = ""
user.birthday = None
user.mail = None
db.session.commit()
def register(data):

View File

@ -5,10 +5,9 @@ from typing import Optional
from datetime import date, datetime
from sqlalchemy.orm.collections import attribute_mapped_collection
from flaschengeist.models.image import Image
from ..database import db
from . import ModelSerializeMixin, UtcDateTime, Serial
from .image import Image
association_table = db.Table(

View File

@ -27,6 +27,11 @@ before_update_user = HookBefore("update_user")
Args:
user: User object
"""
before_delete_user = HookBefore("delete_user")
"""Hook decorator,this is called before an user gets deleted.
Args:
user: User object
"""
class Plugin:

View File

@ -6,8 +6,7 @@ Flaschengeist database (as User attribute)
import os
import hashlib
import binascii
from werkzeug.exceptions import BadRequest, NotFound
from werkzeug.exceptions import BadRequest
from flaschengeist.plugins import AuthPlugin
from flaschengeist.models.user import User, Role, Permission
from flaschengeist.database import db
@ -18,6 +17,8 @@ class AuthPlain(AuthPlugin):
def post_install(self):
if User.query.first() is None:
logger.info("Installing admin user")
role = Role.query.filter(Role.name == "Superuser").first()
if role is None:
role = Role(name="Superuser", permissions=Permission.query.all())
admin = User(
userid="admin",

View File

@ -2,18 +2,17 @@
Provides routes used to manage users
"""
from io import BytesIO
from http.client import NO_CONTENT, CREATED
from flask import Blueprint, request, jsonify, make_response, Response, send_file
from flask import Blueprint, request, jsonify, make_response
from werkzeug.exceptions import BadRequest, Forbidden, MethodNotAllowed, NotFound
from . import permissions
from flaschengeist import logger
from flaschengeist.config import config
from flaschengeist.plugins import Plugin
from flaschengeist.models.user import User, _Avatar
from flaschengeist.models.user import User
from flaschengeist.utils.decorators import login_required, extract_session, headers
from flaschengeist.controller import userController, imageController as image_controller
from flaschengeist.controller import userController
from flaschengeist.utils.HTTP import created, no_content
from flaschengeist.utils.datetime import from_iso_format
@ -23,6 +22,10 @@ class UsersPlugin(Plugin):
blueprint = Blueprint(name, __name__)
permissions = permissions.permissions
def install(self):
userController.install()
return super().install()
@UsersPlugin.blueprint.route("/users", methods=["POST"])
def register():
@ -144,7 +147,7 @@ def delete_avatar(userid, current_session):
if userid != current_session.user_.userid and not current_session.user_.has_permission(permissions.EDIT):
raise Forbidden
userController.delete_avatar(user)
return "", NO_CONTENT
return no_content()
@UsersPlugin.blueprint.route("/users/<userid>", methods=["DELETE"])
@ -163,8 +166,8 @@ def delete_user(userid, current_session):
"""
logger.debug("Delete user {{ {} }}".format(userid))
user = userController.get_user(userid)
userController.delete(user)
return "", NO_CONTENT
userController.delete_user(user)
return no_content()
@UsersPlugin.blueprint.route("/users/<userid>", methods=["PUT"])
@ -217,7 +220,7 @@ def edit_user(userid, current_session):
userController.modify_user(user, password, new_password)
userController.update_user(user)
return "", NO_CONTENT
return no_content()
@UsersPlugin.blueprint.route("/notifications", methods=["GET"])