Files
odoo_source/addons/web/controllers/session.py
T
Julien Castiaux 5502313853 [FIX] web, *: multi-db /web/session/authenticate
*: base_setup, hr_timesheet, mail, partner_autocomplete, web_tour

Start odoo without -d and with a --dbfilter that allows multiple
databases. Via JSON-RPC access the /web/session/authenticate route
providing a non-filtered database and valid credentials. Traceback,
`request.env` is None.

Since httpocalypse the initialization of the ORM (cursor, registry,
environment) is greedy. It means that the connection to the database is
established very early during the request routing or skip altogether in
case no dbname was known at that time. This contrast with prepocalypse
where the various ORM thingies were lazily setup the first time they
were accessed.

This changement has an important implication regarding authentication.

In prepocalypse, thanks to the lazy approache, a cursor/registry/env
would be setup on the database you just login upon using the
`request.env` for the first time. This was very nice in this regard but
had other problems.

Since httpocalypse such operation is no more possible. Devs must
initialize and use their own cursor/registry/env in case they
authenticate on another database than the one `request.cr` is (maybe)
connected to.

The `/web/session/authenticate` controller is an example of such case.
It crates its own cr/registry/environment after authentication. The
problem the controller uses `ir.http.session_info` and that not all
overrides were updated to use `self.env` (=the env created in the web
controller) instead of `request.env` (=the missing env of the request).

closes odoo/odoo#108063

X-original-commit: 7b9bd9d37731fae724dc5d91da656dab70aa9ad4
Related: odoo/enterprise#35012
Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-12-15 15:45:07 +01:00

88 lines
3.5 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import logging
import operator
from werkzeug.urls import url_encode
import odoo
import odoo.modules.registry
from odoo import http
from odoo.modules import module
from odoo.exceptions import AccessError, UserError, AccessDenied
from odoo.http import request
from odoo.tools.translate import _
_logger = logging.getLogger(__name__)
class Session(http.Controller):
@http.route('/web/session/get_session_info', type='json', auth="user")
def get_session_info(self):
# Crapy workaround for unupdatable Odoo Mobile App iOS (Thanks Apple :@)
request.session.touch()
return request.env['ir.http'].session_info()
@http.route('/web/session/authenticate', type='json', auth="none")
def authenticate(self, db, login, password, base_location=None):
if not http.db_filter([db]):
raise AccessError("Database not found.")
pre_uid = request.session.authenticate(db, login, password)
if pre_uid != request.session.uid:
# Crapy workaround for unupdatable Odoo Mobile App iOS (Thanks Apple :@) and Android
# Correct behavior should be to raise AccessError("Renewing an expired session for user that has multi-factor-authentication is not supported. Please use /web/login instead.")
return {'uid': None}
request.session.db = db
registry = odoo.modules.registry.Registry(db)
with registry.cursor() as cr:
env = odoo.api.Environment(cr, request.session.uid, request.session.context)
if not request.db and not request.session.is_explicit:
# request._save_session would not update the session_token
# as it lacks an environment, rotating the session myself
http.root.session_store.rotate(request.session, env)
request.future_response.set_cookie(
'session_id', request.session.sid,
max_age=http.SESSION_LIFETIME, httponly=True
)
return env['ir.http'].session_info()
@http.route('/web/session/get_lang_list', type='json', auth="none")
def get_lang_list(self):
try:
return http.dispatch_rpc('db', 'list_lang', []) or []
except Exception as e:
return {"error": e, "title": _("Languages")}
@http.route('/web/session/modules', type='json', auth="user")
def modules(self):
# return all installed modules. Web client is smart enough to not load a module twice
return list(request.env.registry._init_modules.union([module.current_test] if module.current_test else []))
@http.route('/web/session/check', type='json', auth="user")
def check(self):
return # ir.http@_authenticate does the job
@http.route('/web/session/account', type='json', auth="user")
def account(self):
ICP = request.env['ir.config_parameter'].sudo()
params = {
'response_type': 'token',
'client_id': ICP.get_param('database.uuid') or '',
'state': json.dumps({'d': request.db, 'u': ICP.get_param('web.base.url')}),
'scope': 'userinfo',
}
return 'https://accounts.odoo.com/oauth2/auth?' + url_encode(params)
@http.route('/web/session/destroy', type='json', auth="user")
def destroy(self):
request.session.logout()
@http.route('/web/session/logout', type='http', auth="none")
def logout(self, redirect='/web'):
request.session.logout(keep_db=True)
return request.redirect(redirect, 303)