-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
API/RPC Authentication Fails with "Expected singleton: res.remote()"
Module
base_remote
Describe the bug
The base_remote module breaks XML-RPC and JSON-RPC authentication, preventing external API clients (OdooRPC Python library, mobile apps using direct RPC, automated scripts, etc.) from authenticating to Odoo. Authentication fails with ValueError: Expected singleton: res.remote() while web browser authentication continues to work normally.
To Reproduce
Affected versions: 18.0.1.0.0 (likely affects earlier versions as well)
Steps to reproduce the behavior:
- Install the
base_remotemodule - Attempt to authenticate via XML-RPC or JSON-RPC from an external client:
import xmlrpc.client url = 'http://your-odoo-server:8069' common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common') uid = common.authenticate('database', 'username', 'password', {})
- Authentication fails with error:
ValueError: Expected singleton: res.remote()
Expected behavior
API/RPC authentication should succeed, just as web browser authentication does. External API clients should be able to authenticate and interact with Odoo programmatically.
Additional context
Root cause:
In models/base.py, the remote property gracefully handles missing HTTP context (which occurs during RPC calls) by returning an empty recordset:
@property
def remote(self):
try:
remote_addr = http.request.httprequest.remote_addr
except (KeyError, AttributeError, RuntimeError):
return self.env["res.remote"] # Returns empty recordset for RPC callsHowever, models/res_users.py unconditionally calls ensure_one() on this recordset:
@classmethod
def _auth_check_remote(cls, credential, method):
with cls.pool.cursor() as cr:
env = api.Environment(cr, SUPERUSER_ID, {})
remote = env["res.users"].remote
if not config["test_enable"]:
remote.ensure_one() # Crashes when remote is empty recordset- Web browser logins: Have HTTP context →
remotereturns 1 record →ensure_one()succeeds ✓ - API/RPC logins: No HTTP context →
remotereturns empty recordset →ensure_one()fails ❌
Proposed fix:
Change line 19 in models/res_users.py:
# Current:
if not config["test_enable"]:
remote.ensure_one()
# Fixed:
if not config["test_enable"] and remote:
remote.ensure_one()This allows the singleton check to be skipped when no HTTP context exists (RPC calls), while still enforcing device tracking for web browser connections (the module's primary purpose). This follows the same pattern already used for test mode and doesn't compromise the module's functionality.
Environment:
- Odoo 18.0
- Python 3.12
- Tested with OdooRPC library and direct XML-RPC calls