diff --git a/website_require_login/README.rst b/website_require_login/README.rst index adcca320a6..2cdae0899b 100644 --- a/website_require_login/README.rst +++ b/website_require_login/README.rst @@ -7,7 +7,7 @@ Website Login Required !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:a0f16f0655f6b5b9eec2c2e621f35dbcc40c69a3c5353dec8b07ddfab1874313 + !! source digest: sha256:74ad683eba54803e4df9ebfe80d38fba6520b41c3d7ce6106be4aad28f2b2726 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -65,6 +65,9 @@ Contributors ~~~~~~~~~~~~ * Ooops404 +* `Aion Tech `_: + + * Simone Rubino Maintainers ~~~~~~~~~~~ diff --git a/website_require_login/models/ir_http.py b/website_require_login/models/ir_http.py index bcfea63b96..b0b0964770 100644 --- a/website_require_login/models/ir_http.py +++ b/website_require_login/models/ir_http.py @@ -1,4 +1,5 @@ # Copyright 2020 Advitus MB +# Copyright 2024 Simone Rubino - Aion Tech # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0). from pathlib import Path @@ -23,12 +24,45 @@ def _serve_fallback(cls): return res return super()._serve_fallback() + @classmethod + def _require_login_whitelist_paths(cls): + """List of paths that must always be available to all users.""" + return [ + # backend is already protected by login, + # also /web/login, /web/assets, /web/image and others + # are needed to correctly render the login page + "/web", + "/website/translations", + "/jsonrpc", + "/xmlrpc", + ] + + @classmethod + def _require_login_get_matching_path(cls, path, search_paths): + """Return which one of `search_paths` is a parent of `path`.""" + path_inst = Path(path) + for search_path in search_paths: + if search_path == path or Path(search_path) in path_inst.parents: + matching_path = search_path + break + else: + matching_path = None + return matching_path + @classmethod def _check_require_auth(cls): # if not website request - skip website = request.env["website"].sudo().get_current_website() if not website: return None + + # Skip whitelisted paths + path = request.httprequest.path + whitelist_paths = cls._require_login_whitelist_paths() + whitelist_path = cls._require_login_get_matching_path(path, whitelist_paths) + if whitelist_path: + return None + if request.uid and (request.uid != website.user_id.id): return None auth_paths = ( @@ -41,8 +75,7 @@ def _check_require_auth(cls): ) .mapped("path") ) - path = request.httprequest.path - for auth_path in auth_paths: - if auth_path == path or Path(auth_path) in Path(path).parents: - redirect_path = "/web/login?redirect=%s" % path - return request.redirect(redirect_path, code=302) + auth_path = cls._require_login_get_matching_path(path, auth_paths) + if auth_path: + redirect_path = "/web/login?redirect=%s" % path + return request.redirect(redirect_path, code=302) diff --git a/website_require_login/readme/CONTRIBUTORS.rst b/website_require_login/readme/CONTRIBUTORS.rst index b5f195b844..5e5c4c6059 100644 --- a/website_require_login/readme/CONTRIBUTORS.rst +++ b/website_require_login/readme/CONTRIBUTORS.rst @@ -1 +1,4 @@ * Ooops404 +* `Aion Tech `_: + + * Simone Rubino diff --git a/website_require_login/static/description/index.html b/website_require_login/static/description/index.html index 3d6268bacf..9408626de3 100644 --- a/website_require_login/static/description/index.html +++ b/website_require_login/static/description/index.html @@ -1,4 +1,3 @@ - @@ -9,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -367,7 +367,7 @@

Website Login Required

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:a0f16f0655f6b5b9eec2c2e621f35dbcc40c69a3c5353dec8b07ddfab1874313 +!! source digest: sha256:74ad683eba54803e4df9ebfe80d38fba6520b41c3d7ce6106be4aad28f2b2726 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: LGPL-3 OCA/website Translate me on Weblate Try me on Runboat

This module allows to restrict access to specific website pages to logged users.

@@ -410,12 +410,18 @@

Authors

Contributors

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

diff --git a/website_require_login/tests/test_ir_http.py b/website_require_login/tests/test_ir_http.py index ed172189b4..9de37182ca 100644 --- a/website_require_login/tests/test_ir_http.py +++ b/website_require_login/tests/test_ir_http.py @@ -1,3 +1,6 @@ +# Copyright 2024 Simone Rubino - Aion Tech +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0). + from odoo.tests import HttpCase @@ -35,3 +38,34 @@ def test_dispatch_authorized(self): 200, "Expected the response status code to be 200 which means no redirection", ) + + def test_authorize_everything(self): + """Requiring "/" for authorization always redirects to login page.""" + # Arrange + self.env["website.auth.url"].unlink() + root_path = "/" + self.env["website.auth.url"].create( + {"website_id": self.website.id, "path": root_path} + ) + self.env["ir.qweb"]._pregenerate_assets_bundles() + asset_attachment = self.env["ir.attachment"].search( + [ + ("url", "like", "/web/assets/%"), + ], + limit=1, + ) + + redirection_path_map = { + "/": "/web/login?redirect=/", + "/contactus": "/web/login?redirect=/contactus", + asset_attachment.url: asset_attachment.url, + "/web/login": "/web/login", + "/jsonrpc": "/jsonrpc", + "/xmlrpc/2/common": "/xmlrpc/2/common", + "/xmlrpc/2/object": "/xmlrpc/2/object", + } + + # Assert + for requested_path, expected_redirected_path in redirection_path_map.items(): + response = self.url_open(requested_path) + self.assertTrue(response.url.endswith(expected_redirected_path))