diff --git a/auth_oidc/README.rst b/auth_oidc/README.rst index c4bac3fb3c..df52d5a34a 100644 --- a/auth_oidc/README.rst +++ b/auth_oidc/README.rst @@ -7,7 +7,7 @@ Authentication OpenID Connect !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:71510d7bf0aa7f001922c23a7610ad556deef38538d265989fb70ddc010547d6 + !! source digest: sha256:c0b511a2aa2ce3715f6c903369015852d573c98a028d2d9919c6b789578e2d21 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/auth_oidc/static/description/index.html b/auth_oidc/static/description/index.html index 744d414d9c..fbe5ac27f1 100644 --- a/auth_oidc/static/description/index.html +++ b/auth_oidc/static/description/index.html @@ -366,7 +366,7 @@

Authentication OpenID Connect

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:71510d7bf0aa7f001922c23a7610ad556deef38538d265989fb70ddc010547d6 +!! source digest: sha256:c0b511a2aa2ce3715f6c903369015852d573c98a028d2d9919c6b789578e2d21 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/server-auth Translate me on Weblate Try me on Runboat

This module allows users to login through an OpenID Connect provider using the diff --git a/auth_saml/models/auth_saml_provider.py b/auth_saml/models/auth_saml_provider.py index ccd36b1e92..85f6e316b9 100644 --- a/auth_saml/models/auth_saml_provider.py +++ b/auth_saml/models/auth_saml_provider.py @@ -9,13 +9,17 @@ import tempfile import urllib.parse +import requests + # dependency name is pysaml2 # pylint: disable=W7936 import saml2 import saml2.xmldsig as ds from saml2.client import Saml2Client from saml2.config import Config as Saml2Config +from saml2.sigver import SignatureError from odoo import api, fields, models +from odoo.exceptions import UserError _logger = logging.getLogger(__name__) @@ -42,6 +46,14 @@ class AuthSamlProvider(models.Model): ), required=True, ) + idp_metadata_url = fields.Char( + string="Identity Provider Metadata URL", + help="Some SAML providers, notably Office365 can have a metadata " + "document which changes over time, and they provide a URL to the " + "document instead. When this field is set, the metadata can be " + "fetched from the provided URL.", + ) + sp_baseurl = fields.Text( string="Override Base URL", help="""Base URL sent to Odoo with this, rather than automatically @@ -282,11 +294,24 @@ def _validate_auth_response(self, token: str, base_url: str = None): self.ensure_one() client = self._get_client_for_provider(base_url) - response = client.parse_authn_request_response( - token, - saml2.entity.BINDING_HTTP_POST, - self._get_outstanding_requests_dict(), - ) + try: + response = client.parse_authn_request_response( + token, + saml2.entity.BINDING_HTTP_POST, + self._get_outstanding_requests_dict(), + ) + except SignatureError: + # we have a metadata url: try to refresh the metadata document + if self.idp_metadata_url: + self.action_refresh_metadata_from_url() + # retry: if it fails again, we let the exception flow + response = client.parse_authn_request_response( + token, + saml2.entity.BINDING_HTTP_POST, + self._get_outstanding_requests_dict(), + ) + else: + raise matching_value = None if self.matching_attribute == "subject.nameId": @@ -370,3 +395,28 @@ def _hook_validate_auth_response(self, response, matching_value): vals[attribute.field_name] = attribute_value return {"mapped_attrs": vals} + + def action_refresh_metadata_from_url(self): + providers = self.search( + [("idp_metadata_url", "ilike", "http%"), ("id", "in", self.ids)] + ) + if not providers: + return False + # lock the records we might update, so that multiple simultaneous login + # attempts will not cause concurrent updates + self.env.cr.execute( + "SELECT id FROM auth_saml_provider WHERE id in %s FOR UPDATE", + (list(providers.ids),), + ) + updated = False + for provider in providers: + document = requests.get(provider.idp_metadata_url) + if document.status_code != 200: + raise UserError( + f"Unable to download the metadata for {provider.name}: {document.reason}" + ) + if document.text != provider.idp_metadata: + provider.idp_metadata = document.text + _logger.info("Updated provider metadata for %s", provider.name) + updated = True + return updated diff --git a/auth_saml/views/auth_saml.xml b/auth_saml/views/auth_saml.xml index 960905213b..c9c5926cec 100644 --- a/auth_saml/views/auth_saml.xml +++ b/auth_saml/views/auth_saml.xml @@ -76,6 +76,15 @@ +

+ +