From 75aa8126e7c22254165100234a76ab469df81e93 Mon Sep 17 00:00:00 2001 From: Ross Patterson Date: Tue, 28 Dec 2021 11:27:15 -0800 Subject: [PATCH] fix(auth): Install to arbitrary ZODB OFS hierarchy Don't assume that all Plone portals will be installed directly into the Zope root or that all ancestors above the Plone portal will have `./acl_users`. I don't have a case for this, I just noticed it when I was reading the code while working on Zope root auth issues. Also clarify the PAS install plugin process with comments. --- src/plone/restapi/setuphandlers.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/plone/restapi/setuphandlers.py b/src/plone/restapi/setuphandlers.py index 7e0453ac13..1bc174d40c 100644 --- a/src/plone/restapi/setuphandlers.py +++ b/src/plone/restapi/setuphandlers.py @@ -33,8 +33,15 @@ def getNonInstallableProducts(self): # pragma: no cover def install_pas_plugin(context): uf_parent = aq_inner(context) while True: - uf = getToolByName(uf_parent, "acl_users") - if IPluggableAuthService.providedBy(uf) and "jwt_auth" not in uf: + uf = getToolByName(uf_parent, "acl_users", default=None) + + # Skip ancestor contexts to which we don't/can't apply + if uf is None or not IPluggableAuthService.providedBy(uf): + uf_parent = aq_parent(uf_parent) + continue + + # Add the API token plugin if not already installed at this level + if "jwt_auth" not in uf: plugin = JWTAuthenticationPlugin("jwt_auth") uf._setObject(plugin.getId(), plugin) plugin = uf["jwt_auth"] @@ -46,6 +53,8 @@ def install_pas_plugin(context): "ICredentialsResetPlugin", ], ) + + # Go up one more level if uf_parent is uf_parent.getPhysicalRoot(): break uf_parent = aq_parent(uf_parent)