[#8393] For password recovery, resend account verification email if user is not yet confirmed
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 8e59949..ce43f12 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -222,14 +222,21 @@
         if not email:
             redirect('/')
 
-        user_record = M.User.by_email_address(email)
+        user_record = M.User.by_email_address(email, only_confirmed=False)
         allow_non_primary_email_reset = asbool(config.get('auth.allow_non_primary_email_password_reset', True))
 
         if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
             flash('Enter email in correct format!', 'error')
             redirect('/auth/forgotten_password')
 
-        if not allow_non_primary_email_reset:
+        if user_record and user_record.pending:
+            message = 'If the given email address is on record, '\
+                      'an email has been sent to the account\'s primary email address.'
+            email_record = M.EmailAddress.get(email=provider.get_primary_email_address(user_record=user_record),
+                                              confirmed=False)
+            provider.resend_verification_link(user_record.get_tool_data('sfx', 'userid'))
+
+        elif not allow_non_primary_email_reset:
             message = 'If the given email address is on record, '\
                       'a password reset email has been sent to the account\'s primary email address.'
             email_record = M.EmailAddress.get(email=provider.get_primary_email_address(user_record=user_record),
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index b257198..be930de 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -307,6 +307,9 @@
         '''
         raise NotImplementedError('set_password')
 
+    def resend_verification_link(em):
+        em.send_verification_link()
+
     def upload_sshkey(self, username, pubkey):
         '''
         Upload an SSH Key.  Providers do not necessarily need to implement this.
@@ -826,6 +829,9 @@
     def get_last_password_updated(self, user):
         return LocalAuthenticationProvider(None).get_last_password_updated(user)
 
+    def recover_password(self, user):
+        return super().recover_password(user)
+
 
 class ProjectRegistrationProvider(object):
     '''
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 01b6572..f696b7f 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -19,6 +19,7 @@
 from __future__ import absolute_import
 import logging
 import calendar
+from typing import ClassVar
 
 import six
 from markupsafe import Markup
@@ -650,9 +651,12 @@
         return u
 
     @classmethod
-    def by_email_address(cls, addr):
-        addrs = EmailAddress.find(dict(email=addr, confirmed=True))
-        users = [ea.claimed_by_user() for ea in addrs]
+    def by_email_address(cls, addr, only_confirmed=True):
+        q = dict(email=addr)
+        if only_confirmed:
+            q['confirmed'] = True
+        addrs = EmailAddress.find(q)
+        users = [ea.claimed_by_user(not only_confirmed) for ea in addrs]
         users = [u for u in users if u is not None]
         if len(users) > 1:
             log.warn('Multiple active users matching confirmed email %s %s. '
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index c581a96..05e11e2 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -1532,10 +1532,13 @@
         # so test-admin isn't automatically logged in for all requests
         self.app.extra_environ = {'disable_auth_magic': str('True')}
 
+    @patch('allura.model.User.send_password_reset_email')
+    @patch('allura.lib.plugin.LocalAuthenticationProvider.resend_verification_link')
     @patch('allura.tasks.mail_tasks.sendmail')
     @patch('allura.lib.helpers.gen_message_id')
-    def test_email_unconfirmed(self, gen_message_id, sendmail):
+    def test_email_unconfirmed(self, gen_message_id, sendmail, p_sendlink, p_sendpwd):
         user = M.User.query.get(username='test-admin')
+        user.pending = True
         email = M.EmailAddress.find(
             {'claimed_by_user_id': user._id}).first()
         email.confirmed = False
@@ -1546,6 +1549,8 @@
                                                        })
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         assert hash is None
+        p_sendlink.assert_called_once()
+        p_sendpwd.assert_not_called()
 
     @patch('allura.tasks.mail_tasks.sendmail')
     @patch('allura.lib.helpers.gen_message_id')
@@ -1649,7 +1654,7 @@
         with td.audits('Password changed \(through recovery process\)', user=True):
             # escape parentheses, so they would not be treated as regex group
             r = form.submit()
-            
+
         # verify 'Password Changed' email sent
         args, kwargs = sendsimplemail.post.call_args
         assert_equal(kwargs['toaddr'], user._id)