Repository: modoboa/modoboa (language: python)

Issue:
An internal error occured - KeyError at /webmail/ 'password'
# Impacted versions

* OS Type: Proxmox 8.2.1
* OS Version: Debian 12
* Database Type: PostgreSQL
* Database version: 16+261.pgdg120+1
* Modoboa: 2.3.0
* installer used: Yes
* Webserver: Nginx
# Steps to reproduce
Step 1: Create a Debian 12 LXC container in Proxmox 8.2.1.
Step 2: Install Modoboa according to the instructions
Step 3: Create a simple user
# Current behavior
If you now log in with this user everything seems to work but if you click on webmail you get this error message: 

![modoboa 5](https://github.com/user-attachments/assets/e17fbc4f-76bb-47d6-a1da-11bea0dc0d99)
"Sorry An internal error occured."

An image of the error message with Debug True:

![modoboa 3](https://github.com/user-attachments/assets/1d620122-449a-40a3-82a5-e568d5a212e0)
"KeyError at /webmail/          'password'"

This message appears during setup: 

![modoboa 1](https://github.com/user-attachments/assets/ca02f5b1-088e-419d-b7e4-0a61d9a3932e)
"User dovocot already exists, skipping creation but please make sure the /srv/vmail directory exists."

When I try to delete a user, I get this error message:

![modoboa 4](https://github.com/user-attachments/assets/01f28f13-897a-4ae0-a6a2-9af6085731fd)



<!--

  Explain the behavior you're seeing that you think is a bug, and explain how you
  think things should behave instead.

-->

# Expected behavior
The webmail interface should work without errors.
Deleting accounts should also work without errors.
There should not already be a user with the name dovocot. 





Discussion / hints:
same error
Hi
debian 11 , clean install (postwhite is not installed)
Database Type: PostgreSQL
Modoboa: 2.3.0
installer used: Yes
Webserver: Nginx


same error 
calendar and contacts are ok
Getting similar error.  Install seems OK.  After creating a domain and user in admin, when switching to added user, the webmail errors - first with a generic problem.  I switched into debug and got this.  I had read something a while back about no default session variable being set, but it was from 2015.  

<html><body>
<!--StartFragment--><h1>KeyError
       at /webmail/</h1>
  <pre class="exception_value">'password'</pre>
  
Request Method: | GET
-- | --
https://mail.manysparrows.io/webmail/
4.2.15
KeyError
'password'
/srv/modoboa/env/lib/python3.10/site-packages/django/contrib/sessions/backends/base.py, line 53, in __getitem__
modoboa_webmail.views.index
/usr/bin/uwsgi-core
3.10.12
['.',  '',  '/usr/lib/python310.zip',  '/usr/lib/python3.10',  '/usr/lib/python3.10/lib-dynload',  '/srv/modoboa/env/lib/python3.10/site-packages',  '/srv/modoboa/env/lib/python3.10/site-packages/setuptools/_vendor']
Tue, 13 Aug 2024 16:28:25 -0400

<!--EndFragment-->
</body>
</html>
Same error as donhalloway
Same versions. other pages all appear fine. 

`<html>
<body>
<!--StartFragment-->
Name | Installed version | Last version | Description
-- | -- | -- | --
Modoboa | 2.3.0 | 2.2.4 | The core part of Modoboa
Amavis frontend | 1.5.1 | 1.5.0 | Simple amavis management frontend
Contacts | 1.1.2 | 1.1.2 | Address book
Radicale management | 1.7.2 | 1.7.2 | Management frontend for Radicale, a simple calendar and contact server.
Webmail | 1.9.0 | 1.9.0 | Simple IMAP webmail

<!--EndFragment-->
</body>
</html>`
That makes me confident that we can solve the problem.

The message in the setup that a Dovecot user already exists is irrelevant. I named the user differently in the setup. The message did not appear but the result was the same.

Whether MariaDB or Postresql is used makes no difference.

Can someone tell me if modoboa supports ipv6 only?
By the way, connecting external clients doesn't work either. Who has the same thing?

And file2ban service starts with an error
The password thing on the webmail is logic, we need to push an update for webmail since we've added oauth2 login.
@VladislavGatsenko the external client should work though. Can you add detail on this error ?
Excellent news.  Is there a way that I can update the webmail code once it is finished?  (or can I be a tester?)
The update will be fairly easy to apply.
I think that the hotfix will consist in asking the user password the first time you open the webmail for the session before we've got time to fully implement oauth2 flow (unless @tonioo gets more time to work on that :D ). I'll have time to work on this hotfix this weekend.
Thanks,  I have been a longtime django user, new to modoboa, so am anxious to start using it.
Ok can those affected by the issue try this : 
 - make sure you have modoboa 2.3.0 fully updated and working
 - `sudo -u modoboa -i bash`
 - `/srv/modoboa/env/bin/pip install modoboa-webmail==1.9.1b1`
 - as root : `systemctl restart uwsgi`

To revert do all the steps but instead of 1.9.1b1 put 1.9.0 :) 
Same issue here I believe. I am also on Debian 12, used the run.py --upgrade script to update my installation. After the upgrade, I've noticed the new interface is used as default, however I can't log in (Internal Server Error when I enter my login data). Also can't send any emails from an external client.

![image](https://github.com/user-attachments/assets/95961d09-a17d-450a-8898-4210aca40d61)

![image](https://github.com/user-attachments/assets/e0903699-6526-48e4-8657-86ff4285ccf0)


> Ok can those affected by the issue try this :
> 
>     * make sure you have modoboa 2.3.0 fully updated and working
> 
>     * `sudo -u modoboa -i bash`
> 
>     * `/srv/modoboa/env/bin/pip install modoboa-webmail==1.9.1b1`
> 
>     * as root : `systemctl restart uwsgi`
> 
> 
> To revert do all the steps but instead of 1.9.1b1 put 1.9.0 :)

Tried it, didn't help, unfortunately.
This is not the same issue. This issue is about strictly the webmail. 
[Please check the specific upgrade instructions for 2.3.0](https://modoboa.readthedocs.io/en/latest/upgrade.html#version-2-3-0)

Fix patch:
diff --git a/modoboa/admin/handlers.py b/modoboa/admin/handlers.py
index a3f402e4b..f2c7a686e 100644
--- a/modoboa/admin/handlers.py
+++ b/modoboa/admin/handlers.py
@@ -319,10 +319,10 @@ def user_menu(sender, location, user, **kwargs):
 
 
 @receiver(core_signals.user_login)
-def user_logged_in(sender, username, password, **kwargs):
+def user_logged_in(sender, user, password, **kwargs):
     """Store user password in session."""
     request = lib_signals.get_request()
-    if hasattr(request.user, "mailbox"):
+    if hasattr(user, "mailbox"):
         request.session["password"] = encrypt(password)
 
 
diff --git a/modoboa/core/signals.py b/modoboa/core/signals.py
index ca5118f35..7fd8f7063 100644
--- a/modoboa/core/signals.py
+++ b/modoboa/core/signals.py
@@ -24,5 +24,5 @@
 initial_data_loaded = django.dispatch.Signal()  # Provides extname
 register_postfix_maps = django.dispatch.Signal()
 user_can_set_role = django.dispatch.Signal()  # Provides user, role, account
-user_login = django.dispatch.Signal()  # Provides username, password
+user_login = django.dispatch.Signal()  # Provides user, password
 user_logout = django.dispatch.Signal()
diff --git a/modoboa/core/views/auth.py b/modoboa/core/views/auth.py
index 9b6fb0198..058603293 100644
--- a/modoboa/core/views/auth.py
+++ b/modoboa/core/views/auth.py
@@ -57,7 +57,11 @@ def get_user(self):
             return None
 
     def login(self, user, rememberme):
+        encrypted_password = self.request.session.pop("password", None)
         login(self.request, user)
+        # FIXME: remove ASAP
+        if encrypted_password:
+            self.request.session["password"] = encrypted_password
         if not rememberme:
             self.request.session.set_expiry(0)
 
@@ -119,8 +123,8 @@ def form_valid(self, form):
         self.check_password_hash(user, form)
         # FIXME: remove ASAP
         signals.user_login.send(
-            sender="dologin",
-            username=user.username,
+            sender="LoginView",
+            user=user,
             password=form.cleaned_data["password"],
         )
         if user.tfa_enabled:


Test patch:
diff --git a/modoboa/core/tests/test_authentication.py b/modoboa/core/tests/test_authentication.py
index 621650e77..9b0e4e306 100644
--- a/modoboa/core/tests/test_authentication.py
+++ b/modoboa/core/tests/test_authentication.py
@@ -39,9 +39,15 @@ class AuthenticationTestCase(ModoTestCase):
     def setUpTestData(cls):  # NOQA:N802
         """Create test data."""
         super(AuthenticationTestCase, cls).setUpTestData()
-        cls.account = factories.UserFactory(
-            username="user@test.com", groups=("SimpleUsers",)
+        from modoboa.admin.factories import MailboxFactory
+
+        mailbox = MailboxFactory(
+            address="user",
+            domain__name="test.com",
+            user__username="user@test.com",
+            user__groups=("SimpleUsers",),
         )
+        cls.account = mailbox.user
 
     def test_authentication(self):
         """Validate simple case."""
@@ -50,6 +56,8 @@ def test_authentication(self):
         response = self.client.post(reverse("core:login"), data)
         self.assertEqual(response.status_code, 302)
         self.assertTrue(response.url.endswith(reverse("core:user_index")))
+        session = self.client.session
+        self.assertIn("password", session)
 
         response = self.client.post(reverse("core:logout"), {})
         self.assertEqual(response.status_code, 302)
@@ -58,6 +66,8 @@ def test_authentication(self):
         response = self.client.post(reverse("core:login"), data)
         self.assertEqual(response.status_code, 302)
         self.assertTrue(response.url.endswith(reverse("core:dashboard")))
+        session = self.client.session
+        self.assertNotIn("password", session)
 
     @mock.patch("django_otp.match_token")
     @mock.patch("django_otp.login")
@@ -77,6 +87,8 @@ def test_authentication_with_2fa(self, login_mock, match_mock):
         self.assertContains(response, "This code is invalid")
         response = self.client.post(url, data)
         self.assertEqual(response.status_code, 302)
+        session = self.client.session
+        self.assertIn("password", session)
 
     def test_open_redirect(self):
         """Check that open redirect is not allowed."""