Skip to content

Commit 8da1504

Browse files
committed
Merge PR #888 into 16.0
Signed-off-by bguillot
2 parents e6f6111 + 6d21460 commit 8da1504

File tree

6 files changed

+51
-11
lines changed

6 files changed

+51
-11
lines changed

cross_connect_client/controllers/cross_connect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ def cross_connect(
2222
if not server:
2323
raise UserError(_("Server not found"))
2424

25-
url = server._get_cross_connect_url(request.params.get("redirect_url"))
25+
url = server._get_cross_connect_url(**params)
2626
return request.redirect(url, local=False)

cross_connect_client/models/cross_connect_server.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
# @author Florian Mounier <florian.mounier@akretion.com>
33
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
44

5+
from urllib.parse import urlencode
6+
57
import requests
68

79
from odoo import _, api, fields, models
@@ -98,7 +100,7 @@ def _request(self, method, url, headers=None, data=None):
98100
response.raise_for_status()
99101
return response.json()
100102

101-
def _get_cross_connect_url(self, redirect_url=None):
103+
def _get_cross_connect_url(self, **params):
102104
self.ensure_one()
103105
groups = self.env.user.groups_id & self.group_ids
104106
if not groups:
@@ -115,16 +117,18 @@ def _get_cross_connect_url(self, redirect_url=None):
115117
"lang": self.env.user.lang,
116118
"groups": [group.cross_connect_server_group_id for group in groups],
117119
}
118-
if redirect_url:
119-
data["redirect_url"] = redirect_url
120120

121121
response = self._request("POST", "/access", data=data)
122122
client_id = response.get("client_id")
123123
token = response.get("token")
124124
if not token:
125125
raise UserError(_("Missing token"))
126126

127-
return self._absolute_url_for(f"login/{client_id}/{token}")
127+
url = f"login/{client_id}/{token}"
128+
if params:
129+
url += "?" + urlencode(params)
130+
131+
return self._absolute_url_for(url)
128132

129133
def _sync_groups(self):
130134
self.ensure_one()

cross_connect_server/models/cross_connect_client.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright 2024 Akretion (http://www.akretion.com).
22
# @author Florian Mounier <florian.mounier@akretion.com>
33
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
import re
45
from datetime import datetime, timedelta, timezone
56
from secrets import token_urlsafe
67

@@ -34,6 +35,14 @@ class CrossConnectClient(models.Model):
3435
related="endpoint_id.cross_connect_allowed_group_ids",
3536
)
3637

38+
bypass_user_mail_re = fields.Char(
39+
string="Bypass Users Email Regexes",
40+
help=(
41+
"If set, users with an email matching one of these regex will bypass "
42+
"the token user/login creation. The regexes are comma separated."
43+
),
44+
)
45+
3746
group_ids = fields.Many2many(
3847
"res.groups",
3948
string="Groups",
@@ -64,6 +73,12 @@ def _compute_user_count(self):
6473
record.user_count = len(record.user_ids)
6574

6675
def _request_access(self, access_request):
76+
if self.bypass_user_mail_re and any(
77+
re.search(mail_re.strip(), access_request.email)
78+
for mail_re in self.bypass_user_mail_re.split(",")
79+
):
80+
return "bypass"
81+
6782
# check groups
6883
groups = self.env["res.groups"].browse(access_request.groups)
6984
if groups - self.group_ids or not groups.exists():
@@ -72,6 +87,13 @@ def _request_access(self, access_request):
7287
user = self.user_ids.filtered(
7388
lambda u: u.cross_connect_client_user_id == access_request.id
7489
)
90+
91+
# Fallback to default lang if not installed
92+
if access_request.lang not in [
93+
code for code, _name in self.env["res.lang"].get_installed()
94+
]:
95+
access_request.lang = "en_US"
96+
7597
vals = {
7698
"login": f"{self.id}_{access_request.id}_{access_request.login}",
7799
"email": access_request.email,
@@ -94,7 +116,6 @@ def _request_access(self, access_request):
94116
"exp": datetime.now(tz=timezone.utc) + timedelta(minutes=2),
95117
"aud": str(self.id),
96118
"id": user.id,
97-
"redirect_url": access_request.redirect_url or "/web",
98119
},
99120
self.endpoint_id.cross_connect_secret_key,
100121
algorithm="HS256",
@@ -117,4 +138,10 @@ def _log_from_token(self, token):
117138
if not user:
118139
raise AccessDenied(_("Invalid Token"))
119140

120-
return user, obj["redirect_url"]
141+
return user
142+
143+
def _get_final_redirect_url(self, **params):
144+
"""Get the final redirect url after login.
145+
Override this method to customize the local landing action.
146+
"""
147+
return "/web"

cross_connect_server/routers/cross_connect.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from typing import Annotated
66

7-
from fastapi import APIRouter, Depends
7+
from fastapi import APIRouter, Depends, Request
88
from fastapi.responses import RedirectResponse
99

1010
from odoo import _, api
@@ -49,12 +49,19 @@ async def login(
4949
client_id: int,
5050
token: str,
5151
env: Annotated[api.Environment, Depends(odoo_env)],
52+
request: Request,
5253
) -> RedirectResponse:
5354
"""Log user and redirect to odoo index."""
5455
cross_connect_client = env["cross.connect.client"].sudo().browse(client_id)
5556
if not cross_connect_client:
5657
raise MissingError(_("Client not found"))
57-
user, redirect_url = cross_connect_client.sudo()._log_from_token(token)
58+
params = request.query_params
59+
if token == "bypass":
60+
return RedirectResponse(
61+
url=cross_connect_client._get_final_redirect_url(bypass=True, **params)
62+
)
63+
64+
user = cross_connect_client.sudo()._log_from_token(token)
5865
user = user.with_user(user)
5966
user._update_last_login()
6067
env = env(user=user.id)
@@ -68,7 +75,9 @@ async def login(
6875
session.session_token = user._compute_session_token(session.sid)
6976
root.session_store.save(session)
7077
# Redirect after login
71-
response = RedirectResponse(url=redirect_url)
78+
response = RedirectResponse(
79+
url=cross_connect_client._get_final_redirect_url(**params)
80+
)
7281
response.set_cookie(
7382
"session_id",
7483
session.sid,

cross_connect_server/schemas.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ class AccessRequest(StrictExtendableBaseModel, extra="ignore"):
3535
email: str
3636
lang: str
3737
groups: list[int]
38-
redirect_url: str = None
3938

4039

4140
class AccessResponse(StrictExtendableBaseModel):

cross_connect_server/views/fastapi_endpoint_views.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
widget="many2many_tags"
3737
options="{'no_create': True}"
3838
/>
39+
<field name="bypass_user_mail_re" />
3940
<field name="user_count" />
4041
</tree>
4142
</field>

0 commit comments

Comments
 (0)