From 33220101a1092f85d636274cf7b7d23bec101aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 12:48:29 +0100 Subject: [PATCH 1/6] Test if events fired after auto login have the correct principal --- Products/CMFPlone/tests/pwreset_browser.rst | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Products/CMFPlone/tests/pwreset_browser.rst b/Products/CMFPlone/tests/pwreset_browser.rst index 922468f087..37ce689837 100644 --- a/Products/CMFPlone/tests/pwreset_browser.rst +++ b/Products/CMFPlone/tests/pwreset_browser.rst @@ -343,6 +343,19 @@ What we do here is quite similiar to 1A, but instead of typing in the password ourselves, we will be sent an e-mail with the URL to set our password. +We will setup an adapter to capture IUserLoggedInEvent events: + + >>> from zope.component import adapter + >>> from Products.PluggableAuthService.interfaces.events import IUserLoggedInEvent + >>> from zope.component import getGlobalSiteManager + >>> events_fired = [] + >>> @adapter(IUserLoggedInEvent) + ... def got_user_logged_in_event(event): + ... events_fired.append(event) + >>> gsm = getGlobalSiteManager() + >>> gsm.registerHandler(got_user_logged_in_event) + + First off, we need to set ``validate_mail`` to False: >>> browser.open('http://nohost/plone/login') @@ -389,6 +402,10 @@ We should have received an e-mail at this point: 3 >>> msg = str(mailhost.messages[-1]) +Let's clear the events storage: + + >>> events_fired = [] + Now that we have the message, we want to look at its contents, and then we extract the address that lets us reset our password: @@ -415,6 +432,13 @@ Now that we have the address, we will reset our password: >>> "Password reset successful, you are logged in now!" in browser.contents True +User is logged in, let's check the event fired for the correct user: + + >>> len(events_fired) == 1 + True + >>> events_fired[0].principal + + Log out again: >>> browser.getLink('Log out').click() From 3894e94345d2a6e7e1fdefa6eaf4494613b34094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 12:48:42 +0100 Subject: [PATCH 2/6] At this point the user is not logged in yet, so we get it from the membership_tool. --- Products/CMFPlone/browser/login/password_reset.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py index c56810c857..60a33ff56f 100644 --- a/Products/CMFPlone/browser/login/password_reset.py +++ b/Products/CMFPlone/browser/login/password_reset.py @@ -90,6 +90,7 @@ class PasswordResetView(BrowserView): def _auto_login(self, userid, password): aclu = getToolByName(self.context, 'acl_users') + membership_tool = getToolByName(self.context, 'portal_membership') for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin): plugin.updateCredentials( self.request, @@ -97,7 +98,7 @@ def _auto_login(self, userid, password): userid, password ) - user = getSecurityManager().getUser() + user = membership_tool.getMemberById(userid).getUser() login_time = user.getProperty('login_time', None) if login_time is None: notify(UserInitialLoginInEvent(user)) From cf12cb772ec167d9c05fe876705e04e09ecf4fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 12:52:49 +0100 Subject: [PATCH 3/6] Update changelog --- news/2993.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/2993.bugfix diff --git a/news/2993.bugfix b/news/2993.bugfix new file mode 100644 index 0000000000..f4be72869c --- /dev/null +++ b/news/2993.bugfix @@ -0,0 +1,2 @@ +Correctly fire events when user autologin after the password has been reset. +[ericof] From 310cecafd17641116f27648dd3d97704d612ada8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 14:00:21 +0100 Subject: [PATCH 4/6] Remove adapter registration for IUserLoggedInEvent --- Products/CMFPlone/tests/pwreset_browser.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Products/CMFPlone/tests/pwreset_browser.rst b/Products/CMFPlone/tests/pwreset_browser.rst index 37ce689837..7e0663cdd0 100644 --- a/Products/CMFPlone/tests/pwreset_browser.rst +++ b/Products/CMFPlone/tests/pwreset_browser.rst @@ -445,6 +445,10 @@ Log out again: >>> "You are now logged out" in browser.contents True +Remove got_user_logged_in_event registration: + + >> gsm.unregisterHandler(got_user_logged_in_event) + 2B. Administrator adds user with email validation enabled --------------------------------------------------------- From de929c46d8c13b37e4195ed5b2b6445a68040aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 15:30:55 +0100 Subject: [PATCH 5/6] Fix unregistering of adapter --- Products/CMFPlone/tests/pwreset_browser.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Products/CMFPlone/tests/pwreset_browser.rst b/Products/CMFPlone/tests/pwreset_browser.rst index 7e0663cdd0..65bd1d1315 100644 --- a/Products/CMFPlone/tests/pwreset_browser.rst +++ b/Products/CMFPlone/tests/pwreset_browser.rst @@ -447,7 +447,8 @@ Log out again: Remove got_user_logged_in_event registration: - >> gsm.unregisterHandler(got_user_logged_in_event) + >>> gsm.unregisterHandler(got_user_logged_in_event) + True 2B. Administrator adds user with email validation enabled From 34b83b2a28fefa85dd5f353251bfc912dde8929d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 17:11:39 +0100 Subject: [PATCH 6/6] Deal with cases where username/email where not the userid --- .../CMFPlone/browser/login/password_reset.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py index 60a33ff56f..54610c2f28 100644 --- a/Products/CMFPlone/browser/login/password_reset.py +++ b/Products/CMFPlone/browser/login/password_reset.py @@ -10,6 +10,7 @@ from Products.CMFPlone.interfaces.controlpanel import IMailSchema from Products.CMFPlone.PasswordResetTool import ExpiredRequestError from Products.CMFPlone.PasswordResetTool import InvalidRequestError +from Products.CMFPlone.RegistrationTool import get_member_by_login_name from Products.CMFPlone.utils import safe_unicode from Products.CMFPlone.utils import safeToInt from Products.Five import BrowserView @@ -89,8 +90,8 @@ class PasswordResetView(BrowserView): subpath = None def _auto_login(self, userid, password): - aclu = getToolByName(self.context, 'acl_users') - membership_tool = getToolByName(self.context, 'portal_membership') + context = self.context + aclu = getToolByName(context, 'acl_users') for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin): plugin.updateCredentials( self.request, @@ -98,7 +99,16 @@ def _auto_login(self, userid, password): userid, password ) - user = membership_tool.getMemberById(userid).getUser() + + member = get_member_by_login_name(context, userid, False) + + if member: + user = member.getUser() + else: + # Fallback in case we cannot find a user + # with the given userid + user = getSecurityManager().getUser() + login_time = user.getProperty('login_time', None) if login_time is None: notify(UserInitialLoginInEvent(user))