From 0e4c29c26957f65e4ba776349a05d07e01fa200d Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 19 Aug 2023 16:35:22 +0200 Subject: [PATCH] Clarify further, use the API suggested by ghostwheel42 in (b) --- core/admin/mailu/api/v1/user.py | 2 +- core/admin/mailu/manage.py | 2 +- core/admin/mailu/models.py | 11 +++++++---- core/admin/mailu/sso/views/base.py | 4 ++-- core/admin/mailu/ui/views/users.py | 4 ++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/admin/mailu/api/v1/user.py b/core/admin/mailu/api/v1/user.py index 4f04659c..d9195e3d 100644 --- a/core/admin/mailu/api/v1/user.py +++ b/core/admin/mailu/api/v1/user.py @@ -199,7 +199,7 @@ class User(Resource): return {'code': 404, 'message': f'User {email} cannot be found'}, 404 if 'raw_password' in data: - user_found.set_password(data['raw_password'], keep_only_session='') + user_found.set_password(data['raw_password']) if 'comment' in data: user_found.comment = data['comment'] if 'quota_bytes' in data: diff --git a/core/admin/mailu/manage.py b/core/admin/mailu/manage.py index 511de17c..ef5dae7f 100644 --- a/core/admin/mailu/manage.py +++ b/core/admin/mailu/manage.py @@ -122,7 +122,7 @@ def password(localpart, domain_name, password): email = f'{localpart}@{domain_name}' user = models.User.query.get(email) if user: - user.set_password(password, keep_only_session='') + user.set_password(password) user.change_pw_next_login=True else: print(f'User {email} not found.') diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py index 1212ef17..555cc6c5 100644 --- a/core/admin/mailu/models.py +++ b/core/admin/mailu/models.py @@ -624,13 +624,16 @@ in clear-text regardless of the presence of the cache. self._credential_cache[self.get_id()] = (self.password.split('$')[3], passlib.hash.pbkdf2_sha256.using(rounds=1).hash(password)) return result - def set_password(self, password, raw=False, keep_only_session=None): - """ Set password for user + def set_password(self, password, raw=False, keep_sessions=None): + """ Set password for user and destroy all web sessions except those in keep_sessions @password: plain text password to encrypt (or, if raw is True: the hash itself) + @keep_sessions: True if all the sessions should be preserved, otherwise a +set() containing the sessions to keep """ self.password = password if raw else User.get_password_context().hash(password) - if keep_only_session is not None: - utils.MailuSessionExtension.prune_sessions(uid=self.email, keep=keep_only_session) + if keep_sessions is True: + return + utils.MailuSessionExtension.prune_sessions(uid=self.email, keep=keep_sessions) def get_managed_domains(self): """ return list of domains this user can manage """ diff --git a/core/admin/mailu/sso/views/base.py b/core/admin/mailu/sso/views/base.py index f91c7a06..33d4d4f4 100644 --- a/core/admin/mailu/sso/views/base.py +++ b/core/admin/mailu/sso/views/base.py @@ -92,7 +92,7 @@ def pw_change(): if user: flask.session.regenerate() flask_login.login_user(user) - user.set_password(form.pw.data, keep_only_session=flask.session) + user.set_password(form.pw.data, keep_sessions=set(flask.session)) user.change_pw_next_login = False models.db.session.commit() flask.current_app.logger.info(f'Forced password change by {user} from: {client_ip}/{client_port}: success: password: {form.pwned.data}') @@ -165,7 +165,7 @@ def _proxy(): flask.current_app.logger.warning('Too many users for domain %s' % domain) return flask.abort(500, 'Too many users in (domain=%s)' % domain) user = models.User(localpart=localpart, domain=domain) - user.set_password(secrets.token_urlsafe(), keep_only_session=flask.session) + user.set_password(secrets.token_urlsafe(), keep_sessions=set(flask.session)) models.db.session.add(user) models.db.session.commit() flask.session.regenerate() diff --git a/core/admin/mailu/ui/views/users.py b/core/admin/mailu/ui/views/users.py index 5259bd30..b0a945ad 100644 --- a/core/admin/mailu/ui/views/users.py +++ b/core/admin/mailu/ui/views/users.py @@ -75,7 +75,7 @@ def user_edit(user_email): domain=user.domain, max_quota_bytes=max_quota_bytes) form.populate_obj(user) if form.pw.data: - user.set_password(form.pw.data, keep_only_session=flask.session) + user.set_password(form.pw.data, keep_sessions=set(flask.session)) models.db.session.commit() flask.flash('User %s updated' % user) return flask.redirect( @@ -114,7 +114,7 @@ def _process_password_change(form, user_email): flask.flash(msg, "error") return flask.render_template('user/password.html', form=form, user=user) flask.session.regenerate() - user.set_password(form.pw.data, keep_only_session=flask.session) + user.set_password(form.pw.data, keep_sessions=set(flask.session)) models.db.session.commit() flask.flash('Password updated for %s' % user) if user_email: