Repository: plone/Products.CMFPlone

Issue:
Login user after password reset notify events with Anonymous User
## BUG/PROBLEM REPORT

The option **Login user after password reset** allows a user that just performed a password reset to automatically log in after the .process is complete.

One of the two events (**UserLoggedInEvent**, **UserInitialLoginInEvent**) is triggered by this process, but with the Anonymous User instead of the user that just performed the password request.

### What I did:

- Newly created Plone site (no addons)
- **Login user after password reset** selected on */@@security-controlpanel*
- Create a new user
- Request a reset user password
- Follow the generated link

### What I expect to happen:

**UserLoggedInEvent** or **UserInitialLoginInEvent** should be triggered with the newly logged in user.

### What actually happened:

**UserLoggedInEvent** and **UserInitialLoginInEvent** are triggrered with **<SpecialUser 'Anonymous User'>**.

### What version of Plone/ Addons I am using:

* Plone 5.2
* No addons



Discussion:

Resolving patch:
diff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py
--- 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,7 +90,8 @@ class PasswordResetView(BrowserView):
     subpath = None
 
     def _auto_login(self, userid, password):
-        aclu = getToolByName(self.context, 'acl_users')
+        context = self.context
+        aclu = getToolByName(context, 'acl_users')
         for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin):
             plugin.updateCredentials(
                 self.request,
@@ -97,7 +99,16 @@ def _auto_login(self, userid, password):
                 userid,
                 password
             )
-        user = getSecurityManager().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))


Test patch:
diff --git a/Products/CMFPlone/tests/pwreset_browser.rst b/Products/CMFPlone/tests/pwreset_browser.rst
--- 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,12 +432,24 @@ 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
+  <PloneUser 'bsmith'>
+
 Log out again:
 
   >>> browser.getLink('Log out').click()
   >>> "You are now logged out" in browser.contents
   True
 
+Remove got_user_logged_in_event registration:
+
+  >>> gsm.unregisterHandler(got_user_logged_in_event)
+  True
+
 
 2B. Administrator adds user with email validation enabled
 ---------------------------------------------------------