Skip to content

Commit cb66205

Browse files
committed
[ADD] webservice_base_oauth
1 parent 166b3bf commit cb66205

File tree

16 files changed

+1170
-0
lines changed

16 files changed

+1170
-0
lines changed

webservice_base_oauth/README.rst

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
=================================
2+
OAUth support for WebService Base
3+
=================================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:d31af855b383e1b4377ce1a4b848c05c8f9241bc0a3f1525de0e12aa8abaf552
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Production/Stable
16+
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
18+
:alt: License: LGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb--api-lightgray.png?logo=github
20+
:target: https://github.com/OCA/web-api/tree/18.0/webservice_base_oauth
21+
:alt: OCA/web-api
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/web-api-18-0/web-api-18-0-webservice_base_oauth
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/web-api&target_branch=18.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
Extends the Webservice framework to add OAuth support.
32+
33+
**Table of contents**
34+
35+
.. contents::
36+
:local:
37+
38+
Bug Tracker
39+
===========
40+
41+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web-api/issues>`_.
42+
In case of trouble, please check there if your issue has already been reported.
43+
If you spotted it first, help us to smash it by providing a detailed and welcomed
44+
`feedback <https://github.com/OCA/web-api/issues/new?body=module:%20webservice_base_oauth%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
45+
46+
Do not contact contributors directly about support or help with technical issues.
47+
48+
Credits
49+
=======
50+
51+
Authors
52+
-------
53+
54+
* Creu Blanca
55+
* Camptocamp
56+
57+
Contributors
58+
------------
59+
60+
- Enric Tobella <etobella@creublanca.es>
61+
- Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
62+
- Daniel Reis <dreis@opensourceintegrators.com>
63+
64+
Maintainers
65+
-----------
66+
67+
This module is maintained by the OCA.
68+
69+
.. image:: https://odoo-community.org/logo.png
70+
:alt: Odoo Community Association
71+
:target: https://odoo-community.org
72+
73+
OCA, or the Odoo Community Association, is a nonprofit organization whose
74+
mission is to support the collaborative development of Odoo features and
75+
promote its widespread use.
76+
77+
.. |maintainer-etobella| image:: https://github.com/etobella.png?size=40px
78+
:target: https://github.com/etobella
79+
:alt: etobella
80+
81+
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
82+
83+
|maintainer-etobella|
84+
85+
This module is part of the `OCA/web-api <https://github.com/OCA/web-api/tree/18.0/webservice_base_oauth>`_ project on GitHub.
86+
87+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

webservice_base_oauth/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import controllers
2+
from . import models
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright 2020 Creu Blanca
2+
# Copyright 2022 Camptocamp SA
3+
# @author Simone Orsi <simahawk@gmail.com>
4+
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
5+
6+
{
7+
"name": "OAUth support for WebService Base",
8+
"summary": "Adds OAuth support to webservice backends",
9+
"version": "18.0.1.1.0",
10+
"license": "LGPL-3",
11+
"development_status": "Production/Stable",
12+
"maintainers": ["etobella"],
13+
"author": "Creu Blanca, Camptocamp, Odoo Community Association (OCA)",
14+
"website": "https://github.com/OCA/web-api",
15+
"depends": ["webservice_base"],
16+
"external_dependencies": {"python": ["requests-oauthlib", "oauthlib", "responses"]},
17+
"data": ["views/webservice_backend.xml"],
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import oauth2
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2024 Camptocamp SA
2+
# @author Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
3+
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
4+
import json
5+
import logging
6+
7+
from oauthlib.oauth2.rfc6749 import errors
8+
from werkzeug.urls import url_encode
9+
10+
from odoo import http
11+
from odoo.http import request
12+
13+
_logger = logging.getLogger(__name__)
14+
15+
16+
class OAuth2Controller(http.Controller):
17+
@http.route(
18+
"/webservice/<int:backend_id>/oauth2/redirect",
19+
type="http",
20+
auth="public",
21+
csrf=False,
22+
)
23+
def redirect(self, backend_id, **params):
24+
backend = request.env["webservice.backend"].browse(backend_id).sudo()
25+
if backend.auth_type != "oauth2" or backend.oauth2_flow != "web_application":
26+
_logger.error("unexpected backed config for backend %d", backend_id)
27+
raise errors.MismatchingRedirectURIError()
28+
expected_state = backend.oauth2_state
29+
state = params.get("state")
30+
if state != expected_state:
31+
_logger.error("unexpected state: %s", state)
32+
raise errors.MismatchingStateError()
33+
code = params.get("code")
34+
adapter = (
35+
backend._get_adapter()
36+
) # we expect an adapter that supports web_application
37+
token = adapter.fetch_token_from_authorization(code)
38+
backend.write(
39+
{
40+
"oauth2_token": json.dumps(token),
41+
"oauth2_state": False,
42+
}
43+
)
44+
# after saving the token, redirect to the backend form view
45+
uid = request.session.uid
46+
user = request.env["res.users"].sudo().browse(uid)
47+
cids = request.httprequest.cookies.get("cids", str(user.company_id.id))
48+
cids = [int(cid) for cid in cids.split(",")]
49+
record_action = backend._get_access_action()
50+
url_params = {
51+
"model": backend._name,
52+
"id": backend.id,
53+
"active_id": backend.id,
54+
"action": record_action.get("id"),
55+
}
56+
view_id = backend.get_formview_id()
57+
if view_id:
58+
url_params["view_id"] = view_id
59+
60+
if cids:
61+
url_params["cids"] = ",".join([str(cid) for cid in cids])
62+
url = f"/web?#{url_encode(url_params)}"
63+
return request.redirect(url)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import webservice_backend_oauth
2+
from . import webservice_request_adapter_oauth
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Copyright 2020 Creu Blanca
2+
# Copyright 2022 Camptocamp SA
3+
# @author Simone Orsi <simahawk@gmail.com>
4+
# @author Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
5+
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
6+
import logging
7+
8+
from odoo import api, fields, models
9+
from odoo.tools import config
10+
11+
_logger = logging.getLogger(__name__)
12+
13+
14+
class WebserviceBackend(models.Model):
15+
_inherit = "webservice.backend"
16+
17+
auth_type = fields.Selection(selection_add=[("oauth2", "OAuth2")])
18+
oauth2_flow = fields.Selection(
19+
[
20+
("backend_application", "Backend Application (Client Credentials Grant)"),
21+
("web_application", "Web Application (Authorization Code Grant)"),
22+
],
23+
)
24+
oauth2_clientid = fields.Char(string="Client ID", auth_type="oauth2")
25+
oauth2_client_secret = fields.Char(string="Client Secret", auth_type="oauth2")
26+
oauth2_token_url = fields.Char(string="Token URL", auth_type="oauth2")
27+
oauth2_authorization_url = fields.Char(string="Authorization URL")
28+
oauth2_audience = fields.Char(
29+
string="Audience"
30+
# no auth_type because not required
31+
)
32+
oauth2_scope = fields.Char(help="scope of the the authorization")
33+
oauth2_token = fields.Char(help="the OAuth2 token (serialized JSON)")
34+
redirect_url = fields.Char(
35+
compute="_compute_redirect_url",
36+
help="The redirect URL to be used as part of the OAuth2 authorisation flow",
37+
)
38+
oauth2_state = fields.Char(
39+
help="random key generated when authorization flow starts "
40+
"to ensure that no CSRF attack happen"
41+
)
42+
43+
def _get_adapter_protocol(self):
44+
protocol = super()._get_adapter_protocol()
45+
if self.auth_type.startswith("oauth2"):
46+
protocol += f"+{self.auth_type}-{self.oauth2_flow}"
47+
return protocol
48+
49+
@api.depends("auth_type", "oauth2_flow")
50+
def _compute_redirect_url(self):
51+
get_param = self.env["ir.config_parameter"].sudo().get_param
52+
base_url = get_param("web.base.url")
53+
if base_url.startswith("http://") and not config["test_enable"]:
54+
_logger.warning(
55+
"web.base.url is configured in http. Oauth2 requires using https"
56+
)
57+
base_url = base_url[len("http://") :]
58+
if not base_url.startswith("https://"):
59+
base_url = f"https://{base_url}"
60+
for rec in self:
61+
if rec.auth_type == "oauth2" and rec.oauth2_flow == "web_application":
62+
rec.redirect_url = f"{base_url}/webservice/{rec.id}/oauth2/redirect"
63+
else:
64+
rec.redirect_url = False
65+
66+
def button_authorize(self):
67+
_logger.info("Button OAuth2 Authorize")
68+
authorize_url = self._get_adapter().redirect_to_authorize()
69+
_logger.info("Redirecting to %s", authorize_url)
70+
return {
71+
"type": "ir.actions.act_url",
72+
"url": authorize_url,
73+
"target": "self",
74+
}

0 commit comments

Comments
 (0)