Files
tryton/trytond/security.py
T
Cédric Krier afdc884277 Return 429 status when too many login attempts
This prevents to consume too much resource by sleeping over a very long period.

issue6215
review29161002
2017-02-02 11:55:44 +01:00

85 lines
2.9 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.pool import Pool
from trytond.config import config
from trytond.transaction import Transaction
from trytond import backend
from trytond.exceptions import LoginException, RateLimitException
def _get_pool(dbname):
database_list = Pool.database_list()
pool = Pool(dbname)
if dbname not in database_list:
pool.init()
return pool
def login(dbname, loginname, parameters, cache=True, language=None):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
context = {'language': language}
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, 0, context=context) as transaction:
pool = _get_pool(dbname)
User = pool.get('res.user')
try:
user_id = User.get_login(loginname, parameters)
except DatabaseOperationalError:
if count:
continue
raise
except (LoginException, RateLimitException):
# Let's store any changes done
transaction.commit()
raise
break
if user_id:
if not cache:
return user_id
with Transaction().start(dbname, user_id):
Session = pool.get('ir.session')
session, = Session.create([{}])
return user_id, session.key
return
def logout(dbname, user, session):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, 0):
pool = _get_pool(dbname)
Session = pool.get('ir.session')
try:
sessions = Session.search([
('key', '=', session),
])
if not sessions:
return
session, = sessions
name = session.create_uid.login
Session.delete(sessions)
except DatabaseOperationalError:
if count:
continue
raise
return name
def check(dbname, user, session):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, user) as transaction:
pool = _get_pool(dbname)
Session = pool.get('ir.session')
try:
if not Session.check(user, session):
return
else:
return user
except DatabaseOperationalError:
if count:
continue
raise
finally:
transaction.commit()