Files
odoo_source/addons/auth_totp/controllers/home.py
T
Olivier Dony 038cdc66b9 [IMP] auth_totp: add trusted device method to validate user
Adds a variant `_check_credentials_for_uid()` for auth_totp.device's
`_check_credentials()`. The new method will directly verify the device
key matches the given uid.

This spares the redundant uid comparison on the caller side, and
allows extension modules to customise the user/device matching logic.

closes odoo/odoo#94365

X-original-commit: 0e266eb3c73409950d1eb160c41eb6668d439856
Signed-off-by: Olivier Dony <odo@odoo.com>
2022-06-23 02:05:42 +02:00

80 lines
3.3 KiB
Python

# -*- coding: utf-8 -*-
import re
from odoo import http, _
from odoo.exceptions import AccessDenied
from odoo.http import request
from odoo.addons.web.controllers import home as web_home
TRUSTED_DEVICE_COOKIE = 'td_id'
TRUSTED_DEVICE_AGE = 90*86400 # 90 days expiration
class Home(web_home.Home):
@http.route(
'/web/login/totp',
type='http', auth='public', methods=['GET', 'POST'], sitemap=False,
website=True, multilang=False # website breaks the login layout...
)
def web_totp(self, redirect=None, **kwargs):
if request.session.uid:
return request.redirect(self._login_redirect(request.session.uid, redirect=redirect))
if not request.session.pre_uid:
return request.redirect('/web/login')
error = None
user = request.env['res.users'].browse(request.session.pre_uid)
if user and request.httprequest.method == 'GET':
cookies = request.httprequest.cookies
key = cookies.get(TRUSTED_DEVICE_COOKIE)
if key:
user_match = request.env['auth_totp.device']._check_credentials_for_uid(
scope="browser", key=key, uid=user.id)
if user_match:
request.session.finalize(request.env)
return request.redirect(self._login_redirect(request.session.uid, redirect=redirect))
elif user and request.httprequest.method == 'POST' and kwargs.get('totp_token'):
try:
with user._assert_can_auth(user=user.id):
user._totp_check(int(re.sub(r'\s', '', kwargs['totp_token'])))
except AccessDenied as e:
error = str(e)
except ValueError:
error = _("Invalid authentication code format.")
else:
request.session.finalize(request.env)
request.update_env(user=request.session.uid)
request.update_context(**request.session.context)
response = request.redirect(self._login_redirect(request.session.uid, redirect=redirect))
if kwargs.get('remember'):
name = _("%(browser)s on %(platform)s",
browser=request.httprequest.user_agent.browser.capitalize(),
platform=request.httprequest.user_agent.platform.capitalize(),
)
geoip = request.geoip
if geoip:
name += " (%s, %s)" % (geoip['city'], geoip['country_name'])
key = request.env['auth_totp.device']._generate("browser", name)
response.set_cookie(
key=TRUSTED_DEVICE_COOKIE,
value=key,
max_age=TRUSTED_DEVICE_AGE,
httponly=True,
samesite='Lax'
)
# Crapy workaround for unupdatable Odoo Mobile App iOS (Thanks Apple :@)
request.session.touch()
return response
# Crapy workaround for unupdatable Odoo Mobile App iOS (Thanks Apple :@)
request.session.touch()
return request.render('auth_totp.auth_totp_form', {
'user': user,
'error': error,
'redirect': redirect,
})