Files
odoo_source/addons/website/tests/test_get_current_website.py
T
Julien (jula) af67d5223c [FIX] website: fix login with RPC on website domain
__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>
2024-03-12 15:08:28 +00:00

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())