Allow resetting password of user via RPC

Closes #10629
This commit is contained in:
Cédric Krier
2023-11-07 16:52:06 +01:00
parent 6702732826
commit e6736aaed7
3 changed files with 53 additions and 0 deletions
+1
View File
@@ -1,3 +1,4 @@
* Allow resetting password of user via RPC
* Support cached_property on object with __slots__
* Allow creating indexes concurrently
* Allow skipping index creation
+19
View File
@@ -36,6 +36,7 @@ def rpc(request, database_name):
methods = {
'common.db.login': login,
'common.db.logout': logout,
'common.db.reset_password': reset_password,
'system.listMethods': list_method,
'system.methodHelp': help_method,
'system.methodSignature': lambda *a: 'signatures not supported',
@@ -72,6 +73,24 @@ def logout(request, database_name):
context={'_request': request.context})
def reset_password(request, database_name, user, language=None):
authentications = config.get(
'session', 'authentications', default='password').split(',')
if not any('password' in m.split('+') for m in authentications):
abort(HTTPStatus.FORBIDDEN)
context = {
'language': language,
'_request': request.context,
}
try:
security.reset_password(database_name, user, context=context)
except backend.DatabaseOperationalError:
logger.error('fail to connect to %s', database_name, exc_info=True)
abort(HTTPStatus.NOT_FOUND)
except RateLimitException:
abort(HTTPStatus.TOO_MANY_REQUESTS)
@app.route('/', methods=['POST'])
def root(request, *args):
methods = {
+33
View File
@@ -1,6 +1,9 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import logging
import random
import time
from trytond import backend
from trytond.config import config
@@ -76,6 +79,36 @@ def logout(dbname, user, session, context=None):
user, _get_remote_addr(context), dbname)
def reset_password(dbname, user, context=None):
now = dt.datetime.now()
# Prevent guessing code execution path
time.sleep(random.random())
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, 0, context=context):
pool = _get_pool(dbname)
User = pool.get('res.user')
try:
users = User.search([
('login', '=', user),
])
if not users:
logger.info("Reset password for unknown user: %s", user)
break
else:
user, = users
if user.password_reset and user.password_reset_expire > now:
logger.info(
"Password reset already exists for user: %s", user)
else:
user.reset_password()
logger.info("Password reset for user: %s", user)
break
except backend.DatabaseOperationalError:
if count:
continue
raise
def check(dbname, user, session, context=None):
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, user, context=context) as transaction: