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>
80 lines
3.3 KiB
Python
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,
|
|
})
|