Repository navigation
Conversation
|
Hi @simahawk, |
There was a problem hiding this comment.
Building route_group allow/deny lists via raw f-string interpolation into SQL text is not safe here and according to the Odoo documentation: https://www.odoo.com/documentation/19.0/developer/reference/backend/security.html?highlight=sql%20queries#sql-injections
"The best way to be safe is to never, NEVER use Python string concatenation (+) or string parameters interpolation (%) to pass variables to a SQL query string."
Looking closely, I think the method signature in https://github.com/OCA/web-api/blob/19.0/endpoint_route_handler/registry.py#L176 could be updated in the following way perhaps
def get_rules(self, keys=None, where=None, where_params=None):
There was a problem hiding this comment.
@Ricardoalso I do agree that in general, using this shouldn't be an option, however, let me share some extra things:
1- The possible injected parameters come from the server configuration, they are not user inputs. If the attacker is in the server, probably this parameters are the less important part (they could open the shell and do the queries directly)
2- The right way to solve this would be to use proper Odoo SQL generator to do this, however, that might break current databases.
3- Your change of signature could affect other modules (even outside OCA scope). I think it is not a good idea in a stable version.
There was a problem hiding this comment.
I agree the signature change is probably not the best option for a stable version. However, it was the first option that came to my mind when looking at the code
Just raising a recommendation flag in here; thanks for the provided explanation
This module allows FastAPI-based endpoints (built on top of
fastapi/
OCA/rest-framework) to be selectively registered depending on theOdoo process that is running, instead of always being exposed on
every worker regardless of which port it listens on.
This makes it possible to run two (or more) Odoo processes against the
same database:
internal endpoints, and
trusted network (VPN, internal VLAN, firewall rule), that does
register them.
The module does not implement any authentication, authorization, or
network restriction itself — that is left to the FastAPI endpoint's own
auth mechanism (API key, JWT, etc.) and to your reverse proxy / firewall
configuration. It only controls route existence per process.
Use Cases / Context
Odoo serves all registered controllers — standard web controllers as
well as any FastAPI endpoints mounted via
fastapi.endpoint— througha single WSGI application, regardless of which port (
http_port/longpolling port) a given worker process is listening on. There is no
built-in mechanism to say "these routes exist only on port X."
In practice this means that once a FastAPI endpoint is installed, it is
reachable from every process and every port Odoo happens to be running
on, including the main public-facing one. Restricting access to it then
falls entirely on network-level controls (reverse proxy IP allowlists,
firewall rules), which:
route exists on every process, and
from an allowed network (e.g. a compromised internal host).
For internal, technical, or automation-only endpoints — where the goal
is to expose a narrow set of actions to internal systems without
enlarging the attack surface of the main public Odoo instance — it is
preferable that the routes simply do not exist on the public process at
all.
This module addresses that by making route registration conditional on a
process-local setting (not a database value, since
ir.config_parameteris shared across all processes and workersconnected to the same database and would not allow differentiating
between them). This allows a deployment pattern of two Odoo processes,
same codebase and database, started with different configuration:
(public, e.g. port 8069),
e.g. port 8070, restricted at the network layer to trusted sources).
Network-level restriction (firewall/reverse proxy) and endpoint-level
authentication (JWT/API key on the FastAPI app) remain necessary and are
complementary to this module, not replaced by it. This module removes
one layer of exposure (route existence on the public process); it does
not replace access control on the internal one.
Configuration
The module reads a single process-local setting to decide whether to
register the internal endpoint routes. It does not read this setting
from
ir.config_parameter, since that table is shared by everyprocess and worker connected to the same database and would not allow
two processes to behave differently.
Choose one of the two mechanisms below, matching what the code
implements.
Option A — Environment variable
Set ODOO_ENDPOINT_ROUTE_HANDLER_FILTER_GROUP for setting the allowed
route groups.
Set ODOO_ENDPOINT_ROUTE_HANDLER_FILTER_IGNORE to ignore some route
groups.
Option B — Config file key
Add
odoo_endpoint_route_handler_ignoreandodoo_endpoint_route_handler_filterunder[options]in the configfile used to start the internal process only. Odoo's config loader
accepts undeclared keys from the config file (it just won't accept them
as CLI flags), so no changes to Odoo core are required.
.. code:: ini
; odoo_public.conf
[options]
http_port = 8069
odoo_endpoint_route_handler_ignore = internal,my_other_route ; internal and my_other_route are not accepted
; odoo_internal.conf
[options]
http_port = 8070
odoo_endpoint_route_handler_filter = internal,my_other_route ; Only internal and my_other_route are accepted
Notes
--workers=N, all N workerprocesses inherit the same setting — this is expected and desired.
map. It does not grant or restrict any permission by itself.