Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

16.0 add fastapi auth #404

Open
wants to merge 49 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7eca760
[REF] refactor, introduce partner auth and directory auth
sebastienbeau Dec 11, 2020
ad6789f
[WIP] still continue to refactor new auth
sebastienbeau Dec 12, 2020
81f8d19
[IMP] continue to implement auth
sebastienbeau Dec 13, 2020
5c27d78
[FIX] fix missing security rule
sebastienbeau Dec 14, 2020
71811a3
[IMP] add sign out
sebastienbeau Dec 17, 2020
8c8b906
[MIG] Migration to 14.0
sebastienbeau Dec 19, 2020
d767962
[IMP] add reset password
sebastienbeau Jan 8, 2021
938d648
[IMP] Big cleanup and use OCA Copier template
kevinkhao Jan 14, 2021
3bfc475
[FIX] fix dependency
sebastienbeau Jan 21, 2021
98a8795
[UPD] new rest api (datamodel)
Jan 18, 2021
5964bbb
[FIX] login is required
sebastienbeau Jan 28, 2021
fcb3db6
[FIX] fix issue with sql constraint
sebastienbeau Jan 29, 2021
b218e34
[IMP] Add send invitation email functionality, add tests, misc. minor…
kevinkhao Jan 31, 2021
9ed2c6f
[FIX] Add salt_size option on hash tokens
kevinkhao Jan 31, 2021
99d56eb
[FIX] reverting encryption and token changes
kevinkhao Jan 31, 2021
7f75716
[IMP] finish generating token
sebastienbeau Feb 1, 2021
d84d39d
[IMP] update copier
sebastienbeau Oct 6, 2021
90790ac
[FIX] duplicate labels
Kev-Roche Jan 16, 2022
0cefa8e
partner_auth: refactor implementation
sebastienbeau May 13, 2023
b44545a
partner_auth: update api naming finish register
sebastienbeau May 15, 2023
286eb03
partner_auth: add inherit _create_partner_auth, fix cookie duration
sebastienbeau Jun 12, 2023
4872c73
partner_auth: refactor code in order to use fastapi
sebastienbeau Aug 16, 2023
4c15079
fastapi_partner_auth: rename module
sebastienbeau Aug 16, 2023
93469f8
fastapi_auth_partner: Improve test, add dependencies
sebastienbeau Aug 31, 2023
d555452
fastapi_auth_partner: Finish first version of the module
sebastienbeau Sep 6, 2023
43d6750
fastapi_auth_partner: rename endpoint for request_reset_password
sebastienbeau Sep 6, 2023
5c387fd
fastapi_auth_partner: clean test and add missing index
sebastienbeau Sep 6, 2023
9f3a488
fastapi_auth_partner: better field naming
sebastienbeau Sep 11, 2023
45e9fce
fastapi_auth_partner: migrate to pydantic 2
sebastienbeau Oct 29, 2023
6fb2a1e
fastapi_auth_partner: update AuthPartnerResponse
sebastienbeau Nov 2, 2023
aa1d8c7
fastapi_auth_partner: fix view
sebastienbeau Nov 5, 2023
a3c861d
fastapi_auth_partner: fix access right
sebastienbeau Dec 15, 2023
53135d1
fastapi_auth_partner: Migration to V16
sebastienbeau Dec 15, 2023
1befb10
fastapi_auth_partner: run pre-commit
sebastienbeau Dec 15, 2023
44a9786
fastapi_auth_partner: force send mail as we use it in a job
sebastienbeau Dec 17, 2023
e7741c7
fix model on security rule
kevinkhao Jan 22, 2024
bad9ebe
use selection_add instead of redefining selection
kevinkhao Jan 22, 2024
ebef97e
FIX fastapi_auth_partner: remove partner_ids
bealdav Jan 22, 2024
1ed21b3
fastapi_auth_partner: manager should be allowed to read directory auth
sebastienbeau Feb 25, 2024
b7a14e0
[IMP] fastapi_auth_partner: Add impersonations
paradoxxxzero Jun 18, 2024
0f695ae
[FIX] fastapi_auth_partner: Fix impersonate redirect url
paradoxxxzero Sep 19, 2024
49372da
[IMP] fastapi_auth_partner: Add mail verification
paradoxxxzero Apr 25, 2024
f6d9267
[FIX] fastapi_auth_partner: Add default templates
paradoxxxzero May 13, 2024
874d23c
fastapi_auth_partner: raise the right http code when cookies is invalid
sebastienbeau Jun 27, 2024
99ab493
fastapi_auth_partner: add the option "sliding_session" so session exp…
sebastienbeau Jun 27, 2024
90f9030
[FIX] fastapi_auth_partner: Fix tests
paradoxxxzero Sep 19, 2024
5ea75ac
set login in lowercase to avoir mixing upper case and lower case
bguillot Sep 24, 2024
e388aa4
Check if mail is verified for login
bguillot Sep 24, 2024
052e15f
[FIX] fastapi_auth_partner: Fix directory acl read issue
paradoxxxzero Oct 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fastapi_auth_partner/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
todo
4 changes: 4 additions & 0 deletions fastapi_auth_partner/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import models
from . import routers
from . import schemas
from . import wizards
38 changes: 38 additions & 0 deletions fastapi_auth_partner/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2020 Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Partner Auth",
"summary": """
Implements the base features for a authenticable partner""",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Akretion,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/rest-framework",
"depends": [
"extendable_fastapi",
"mail",
"queue_job",
],
"data": [
"security/res_group.xml",
"security/ir.model.access.csv",
"security/ir_rule.xml",
"data/email_data.xml",
"views/fastapi_endpoint_view.xml",
"views/fastapi_auth_partner_view.xml",
"views/fastapi_auth_directory_view.xml",
"views/res_partner_view.xml",
"wizards/wizard_partner_auth_reset_password_view.xml",
"wizards/wizard_partner_auth_impersonate_view.xml",
],
"demo": [
"demo/fastapi_auth_directory_demo.xml",
"demo/res_partner_demo.xml",
"demo/fastapi_auth_partner_demo.xml",
"demo/fastapi_endpoint_demo.xml",
],
"external_dependencies": {
"python": ["itsdangerous"],
},
}
67 changes: 67 additions & 0 deletions fastapi_auth_partner/data/email_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo noupdate="1">
<record id="email_request_reset_password" model="mail.template">
<field name="name">FastApi Auth Directory: Reset Password</field>
<field name="email_from">[email protected]</field>
<field name="subject">Reset Password</field>
<field name="partner_to">{{object.partner_id.id}}</field>
<field name="model_id" ref="model_fastapi_auth_partner" />
<field name="auto_delete" eval="True" />
<field name="lang">${object.partner_id.lang}</field>
<field name="body_html" type="html">
<div>
Hi <t t-out="object.partner_id.name or ''" />
Click on the following link to reset your password
<a
t-attf-href="https://example.org/password/reset?token={{ object.env.context['token']}}"
target="_blank"
style="color:#FFFFFF; text-decoration:none;"
>Reset Password</a>
</div>
</field>
</record>

<record id="email_invite_set_password" model="mail.template">
<field name="name">FastApi Auth Directory: Set Password</field>
<field name="email_from">[email protected]</field>
<field name="subject">Welcome</field>
<field name="partner_to">{{object.partner_id.id}}</field>
<field name="model_id" ref="model_fastapi_auth_partner" />
<field name="auto_delete" eval="True" />
<field name="lang">{{object.partner_id.lang}}</field>
<field name="body_html" type="html">
<div>
Hi <t t-out="object.partner_id.name or ''" />
Welcome, your account have been created
Click on the following link to set your password
<a
t-attf-href="https://example.org/password/reset?token={{ object.env.context['token']}}"
target="_blank"
style="color:#FFFFFF; text-decoration:none;"
>Set Password</a>
</div>
</field>
</record>

<record id="email_invite_validate_email" model="mail.template">
<field name="name">FastApi Auth Directory: Validate Email</field>
<field name="email_from">[email protected]</field>
<field name="subject">Welcome</field>
<field name="partner_to">{{object.partner_id.id}}</field>
<field name="model_id" ref="model_fastapi_auth_partner" />
<field name="auto_delete" eval="True" />
<field name="lang">{{object.partner_id.lang}}</field>
<field name="body_html" type="html">
<div>
Hi <t t-out="object.partner_id.name or ''" />
Welcome to the site, please click on the following link to verify your email
<a
t-attf-href="https://example.org/email/validate?token={{ object.env.context['token']}}"
target="_blank"
style="color:#FFFFFF; text-decoration:none;"
>Validate Email</a>
</div>
</field>
</record>

</odoo>
16 changes: 16 additions & 0 deletions fastapi_auth_partner/demo/fastapi_auth_directory_demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="demo_directory" model="fastapi.auth.directory">
<field name="name">Demo Auth Directory</field>
<field
name="request_reset_password_template_id"
ref="email_request_reset_password"
/>
<field name="invite_set_password_template_id" ref="email_invite_set_password" />
<field
name="invite_validate_email_template_id"
ref="email_invite_validate_email"
/>
<field name="cookie_secret_key">SuperSecret</field>
</record>
</odoo>
8 changes: 8 additions & 0 deletions fastapi_auth_partner/demo/fastapi_auth_partner_demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="partner_auth_demo" model="fastapi.auth.partner">
<field name="partner_id" ref="res_partner_auth_demo" />
<field name="directory_id" ref="demo_directory" />
<field name="password">Super-secret$1</field>
</record>
</odoo>
20 changes: 20 additions & 0 deletions fastapi_auth_partner/demo/fastapi_endpoint_demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="fastapi.endpoint" id="fastapi_endpoint_demo">
<field name="name">Fastapi Auth Partner Demo Endpoint</field>
<field
name="description"
><![CDATA[
# A Dummy FastApi Partner Auth Demo

This demo endpoint has been created by inhering from "fastapi.endpoint", registering
a new app into the app selection field and implementing the `_get_fastapi_routers`
methods. See documentation to learn more about how to create a new app.
]]></field>
<field name="app">demo</field>
<field name="root_path">/fastapi_auth_partner_demo</field>
<field name="demo_auth_method">auth_partner</field>
<field name="user_id" ref="fastapi.my_demo_app_user" />
<field name="directory_id" ref="demo_directory" />
</record>
</odoo>
9 changes: 9 additions & 0 deletions fastapi_auth_partner/demo/res_partner_demo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>

<record id="res_partner_auth_demo" model="res.partner">
<field name="name">Demo auth partner</field>
<field name="email">[email protected]</field>
</record>

</odoo>
73 changes: 73 additions & 0 deletions fastapi_auth_partner/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright 2023 Akretion (https://www.akretion.com).
# @author Sébastien BEAU <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import logging
import sys
from typing import Any, Dict, Union

from itsdangerous import URLSafeTimedSerializer
from starlette.status import HTTP_401_UNAUTHORIZED

from odoo.api import Environment

from odoo.addons.base.models.res_partner import Partner
from odoo.addons.fastapi.dependencies import fastapi_endpoint, odoo_env
from odoo.addons.fastapi.models import FastapiEndpoint

from fastapi import Cookie, Depends, HTTPException, Request, Response

if sys.version_info >= (3, 9):
from typing import Annotated
else:
from typing_extensions import Annotated

Check warning on line 23 in fastapi_auth_partner/dependencies.py

View check run for this annotation

Codecov / codecov/patch

fastapi_auth_partner/dependencies.py#L23

Added line #L23 was not covered by tests

_logger = logging.getLogger(__name__)


Payload = Dict[str, Any]


class AuthPartner:
def __init__(self, allow_unauthenticated: bool = False):
self.allow_unauthenticated = allow_unauthenticated

def __call__(
self,
request: Request,
response: Response,
env: Annotated[
Environment,
Depends(odoo_env),
],
endpoint: Annotated[FastapiEndpoint, Depends(fastapi_endpoint)],
fastapi_auth_partner: Annotated[Union[str, None], Cookie()] = None,
) -> Partner:
if not fastapi_auth_partner and self.allow_unauthenticated:
return env["res.partner"].with_user(env.ref("base.public_user")).browse()

elif fastapi_auth_partner:
directory = endpoint.sudo().directory_id
try:
vals = URLSafeTimedSerializer(directory.cookie_secret_key).loads(
fastapi_auth_partner, max_age=directory.cookie_duration * 60
)
except Exception as e:
_logger.error("Invalid cookies error %s", e)
raise HTTPException(status_code=HTTP_401_UNAUTHORIZED) from e

Check warning on line 57 in fastapi_auth_partner/dependencies.py

View check run for this annotation

Codecov / codecov/patch

fastapi_auth_partner/dependencies.py#L55-L57

Added lines #L55 - L57 were not covered by tests
if vals["did"] == directory.id and vals["pid"]:
partner = env["res.partner"].browse(vals["pid"]).exists()
if partner:
auth = partner.sudo().auth_partner_ids.filtered(
lambda s: s.directory_id == directory
)
if auth:
if directory.sliding_session:
auth._set_auth_cookie(response)

Check warning on line 66 in fastapi_auth_partner/dependencies.py

View check run for this annotation

Codecov / codecov/patch

fastapi_auth_partner/dependencies.py#L66

Added line #L66 was not covered by tests
return partner
_logger.info("Could not determine partner from 'fastapi_auth_partner' cookie.")
raise HTTPException(status_code=HTTP_401_UNAUTHORIZED)


auth_partner_authenticated_partner = AuthPartner()
auth_partner_optionally_authenticated_partner = AuthPartner(allow_unauthenticated=True)
4 changes: 4 additions & 0 deletions fastapi_auth_partner/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import fastapi_auth_directory
from . import fastapi_auth_partner
from . import res_partner
from . import fastapi_endpoint
96 changes: 96 additions & 0 deletions fastapi_auth_partner/models/fastapi_auth_directory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright 2020 Akretion
# Copyright 2020 Odoo SA (some code have been inspired from res_users code)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).


from odoo import fields, models


class FastApiAuthDirectory(models.Model):
_name = "fastapi.auth.directory"
_description = "FastApi Auth Directory"

name = fields.Char(required=True)
set_password_token_duration = fields.Integer(
default=1440, help="In minute, default 1440 minutes => 24h", required=True
)
impersonating_token_duration = fields.Integer(
default=1, help="In minute, default 1 minute", required=True
)
request_reset_password_template_id = fields.Many2one(
"mail.template",
"Mail Template Forget Password",
required=True,
default=lambda self: self.env.ref(
"fastapi_auth_partner.email_request_reset_password",
raise_if_not_found=False,
),
)
invite_set_password_template_id = fields.Many2one(
"mail.template",
"Mail Template New Password",
required=True,
default=lambda self: self.env.ref(
"fastapi_auth_partner.email_invite_set_password",
raise_if_not_found=False,
),
)
invite_validate_email_template_id = fields.Many2one(
"mail.template",
"Mail Template Validate Email",
required=True,
default=lambda self: self.env.ref(
"fastapi_auth_partner.email_invite_validate_email",
raise_if_not_found=False,
),
)
cookie_secret_key = fields.Char(
required=True,
groups="base.group_system",
)
cookie_duration = fields.Integer(
default=525600,
help="In minute, default 525600 minutes => 1 year",
required=True,
)
count_partner = fields.Integer(compute="_compute_count_partner")

fastapi_endpoint_ids = fields.One2many(
"fastapi.endpoint",
"directory_id",
string="FastAPI Endpoints",
)
impersonating_user_ids = fields.Many2many(
"res.users",
"fastapi_auth_directory_impersonating_user_rel",
"directory_id",
"user_id",
string="Impersonating Users",
help="These odoo users can impersonate any partner of this directory",
default=lambda self: (
self.env.ref("base.user_root") | self.env.ref("base.user_admin")
).ids,
groups="fastapi_auth_partner.group_partner_auth_manager",
)
sliding_session = fields.Boolean()
force_verified_email = fields.Boolean(
help="If checked, email must be verified to be able to log in"
)

def _compute_count_partner(self):
data = self.env["fastapi.auth.partner"].read_group(

Check warning on line 81 in fastapi_auth_partner/models/fastapi_auth_directory.py

View check run for this annotation

Codecov / codecov/patch

fastapi_auth_partner/models/fastapi_auth_directory.py#L81

Added line #L81 was not covered by tests
[
("directory_id", "in", self.ids),
],
["directory_id"],
groupby=["directory_id"],
lazy=False,
)
res = {item["directory_id"][0]: item["__count"] for item in data}

for record in self:
record.count_partner = res.get(record.id, 0)

Check warning on line 92 in fastapi_auth_partner/models/fastapi_auth_directory.py

View check run for this annotation

Codecov / codecov/patch

fastapi_auth_partner/models/fastapi_auth_directory.py#L92

Added line #L92 was not covered by tests

@property
def _server_env_fields(self):
return {"cookie_secret_key": {}}

Check warning on line 96 in fastapi_auth_partner/models/fastapi_auth_directory.py

View check run for this annotation

Codecov / codecov/patch

fastapi_auth_partner/models/fastapi_auth_directory.py#L96

Added line #L96 was not covered by tests
Loading
Loading