__Current behavior before commit:__ When the field `website_id` of a user is set, this user should only be able to login via this website (cfr. [this method][1]). This means that he can only login if [`get_current_website`][2] returns the same website as `website_id`. The issue is that when login with RPC, `dispatch_rpc` is making a [`borrow_request`][3] which hides the `request` object from the RPC layer. This has the consequence that `get_current_website` is not able to retrieve the website based on the url of the request. Thus preventing a user to login via RPC even if the domain used corresponds to the website set in its `website_id` field. __Description of the fix:__ Add the possibility to retrieve the current website via `threading.current_thread().url` (which is set [here][4]). This way it is possible to know the current website even if `borrow_request` has been used. __Steps tor reproduce:__ - Install `website` - Go to Website > Configuration > Websites - Set the domain of the first website (e.g. `http://localhost:8069/`) - Go to Marc Demo" res.partner form view - In Sales & Purchase tab set **Website** to "My Website" Then run this script in another terminal: ```python #!/usr/bin/env python3 import json import urllib.request url = "http://localhost:8069/jsonrpc" dbname = "db-16.0" def rpc_login_user_demo(): """ Login with demo using JSON-RPC :return: the user's id or False if login failed """ req = urllib.request.Request(url=url, data=json.dumps({ "params": { "service": "common", "method": "login", "args": [dbname, 'demo', 'demo'] }, }).encode(), headers={"Content-Type": "application/json"}) response = json.loads(urllib.request.urlopen(req).read().decode('UTF-8')) if response.get("error"): raise Exception(response["error"]) return response['result'] uid = rpc_login_user_demo() if uid: print("Login success") else: print("Login failed") ``` The login will fail but it should succeed since we sent the request with the same host than the website domain. opw-3742591 [1]: https://github.com/odoo/odoo/blob/0f7cbf2969b3c4b6c496e5b54814c4a9b3081af4/addons/website/models/res_users.py#L40 [2]: https://github.com/odoo/odoo/blob/0f7cbf2969b3c4b6c496e5b54814c4a9b3081af4/addons/website/models/website.py#L944 [3]: https://github.com/odoo/odoo/blob/0f7cbf2969b3c4b6c496e5b54814c4a9b3081af4/odoo/http.py#L361 [4]: https://github.com/odoo/odoo/blob/0f7cbf2969b3c4b6c496e5b54814c4a9b3081af4/odoo/http.py#L2037 closes odoo/odoo#157372 X-original-commit: b8bc400909012dd04d383287a1850bfc96dd0c5c Signed-off-by: Julien Castiaux (juc) <juc@odoo.com> Signed-off-by: Julien Launois (jula) <jula@odoo.com>
111 lines
4.5 KiB
Python
111 lines
4.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import json
|
|
|
|
from odoo.tests import tagged
|
|
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestGetCurrentWebsite(HttpCaseWithUserDemo):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.website = cls.env.ref('website.default_website')
|
|
|
|
def test_01_get_current_website_id(self):
|
|
"""Make sure `_get_current_website_id works`."""
|
|
|
|
Website = self.env['website']
|
|
|
|
# clean initial state
|
|
website1 = self.website
|
|
website1.domain = False
|
|
|
|
website2 = Website.create({'name': 'My Website 2'})
|
|
|
|
# CASE: no domain: get first
|
|
self.assertEqual(Website._get_current_website_id(''), website1.id)
|
|
|
|
# setup domain
|
|
website1.domain = 'my-site-1.fr'
|
|
website2.domain = 'https://my2ndsite.com:80'
|
|
|
|
# CASE: domain set: get matching domain
|
|
self.assertEqual(Website._get_current_website_id('my-site-1.fr'), website1.id)
|
|
|
|
# CASE: domain set: get matching domain (scheme and port supported)
|
|
self.assertEqual(Website._get_current_website_id('my-site-1.fr:8069'), website1.id)
|
|
|
|
self.assertEqual(Website._get_current_website_id('my2ndsite.com:80'), website2.id)
|
|
self.assertEqual(Website._get_current_website_id('my2ndsite.com:8069'), website2.id)
|
|
self.assertEqual(Website._get_current_website_id('my2ndsite.com'), website2.id)
|
|
|
|
# CASE: domain set, wrong domain: get first
|
|
self.assertEqual(Website._get_current_website_id('test.com'), website1.id)
|
|
|
|
# CASE: subdomain: not supported
|
|
self.assertEqual(Website._get_current_website_id('www.my2ndsite.com'), website1.id)
|
|
|
|
# CASE: domain set: get by domain in priority
|
|
self.assertEqual(Website._get_current_website_id('my2ndsite.com'), website2.id)
|
|
self.assertEqual(Website._get_current_website_id('my-site-1.fr'), website1.id)
|
|
|
|
# CASE: overlapping domain: get exact match
|
|
website1.domain = 'site-1.com'
|
|
website2.domain = 'even-better-site-1.com'
|
|
self.assertEqual(Website._get_current_website_id('site-1.com'), website1.id)
|
|
self.assertEqual(Website._get_current_website_id('even-better-site-1.com'), website2.id)
|
|
|
|
# CASE: case insensitive
|
|
website1.domain = 'Site-1.com'
|
|
website2.domain = 'Even-Better-site-1.com'
|
|
self.assertEqual(Website._get_current_website_id('sitE-1.com'), website1.id)
|
|
self.assertEqual(Website._get_current_website_id('even-beTTer-site-1.com'), website2.id)
|
|
|
|
# CASE: same domain, different port
|
|
website1.domain = 'site-1.com:80'
|
|
website2.domain = 'site-1.com:81'
|
|
self.assertEqual(Website._get_current_website_id('site-1.com:80'), website1.id)
|
|
self.assertEqual(Website._get_current_website_id('site-1.com:81'), website2.id)
|
|
self.assertEqual(Website._get_current_website_id('site-1.com:82'), website1.id)
|
|
self.assertEqual(Website._get_current_website_id('site-1.com'), website1.id)
|
|
|
|
def test_02_signup_user_website_id(self):
|
|
website = self.website
|
|
website.specific_user_account = True
|
|
|
|
user = self.env['res.users'].create({'website_id': website.id, 'login': 'sad@mail.com', 'name': 'Hope Fully'})
|
|
self.assertTrue(user.website_id == user.partner_id.website_id == website)
|
|
|
|
def test_03_rpc_signin_user_website_id(self):
|
|
def rpc_login_user_demo():
|
|
"""
|
|
Login with demo using JSON-RPC
|
|
:return: the user's id or False if login failed
|
|
"""
|
|
response = self.url_open('/jsonrpc', data=json.dumps({
|
|
"params": {
|
|
"service": "common",
|
|
"method": "login",
|
|
"args": [self.env.cr.dbname, 'demo', 'demo']
|
|
},
|
|
}), headers={"Content-Type": "application/json"})
|
|
return response.json()['result']
|
|
|
|
website1 = self.website
|
|
website1.domain = self.base_url()
|
|
|
|
website2 = self.env['website'].create({'name': 'My Website 2'})
|
|
website2.domain = False
|
|
|
|
# It should login successfully since the host used in the RPC call is
|
|
# the same as the website set on the user.
|
|
self.user_demo.website_id = website1
|
|
self.assertTrue(rpc_login_user_demo())
|
|
|
|
# It should not login since the website set on the user has no domain.
|
|
self.user_demo.website_id = website2
|
|
self.assertFalse(rpc_login_user_demo())
|