mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge pull request #3593 from modoboa/fix/for.2.4.2
Some fixes for 2.4.1
This commit is contained in:
@@ -72,6 +72,7 @@ specific part, here are the steps you must follow:
|
||||
manual_installation/dovecot
|
||||
manual_installation/postfix
|
||||
manual_installation/opendkim
|
||||
manual_installation/radicale
|
||||
|
||||
Extensions
|
||||
----------
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
.. _radicale:
|
||||
|
||||
#######
|
||||
Radicale
|
||||
#######
|
||||
|
||||
This page is currently being written.
|
||||
|
||||
.. _radicale_oauth2:
|
||||
|
||||
OAuth 2 authentication
|
||||
======================
|
||||
|
||||
.. note::
|
||||
|
||||
These steps are automatic if you use an up-to-date modoboa-installer to install/upgrade.
|
||||
|
||||
Installing radicale oauth plugin
|
||||
--------------------------------
|
||||
|
||||
You need to install ``radicale-modoboa-auth-oauth2`` python package inside radicale venv.
|
||||
If you used the installer you can use the following commands:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
> sudo -u radicale -i bash
|
||||
> cd ~
|
||||
> env/bin/pip install radicale-modoboa-auth-oauth2
|
||||
|
||||
Oauth application creation
|
||||
--------------------------
|
||||
|
||||
You first need to register Radicale as an authorized consumer of the
|
||||
OAuth2 authentication service provided by Modoboa. To do so, create an
|
||||
application with the following commands:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
> cd <modoboa_instance_path>
|
||||
> python manage.py createapplication --name=Radicale --skip-authorization --client-id=radicale confidential client-credentials
|
||||
|
||||
On success, you should see an output similar to::
|
||||
|
||||
New application Radicale created successfully.
|
||||
client_secret: XXXX
|
||||
|
||||
To enable OAuth2 authentication in Radicale, edit the :file:`/etc/radicale/config`
|
||||
file and update the `type` in `[auth]` to::
|
||||
|
||||
type = radicale_modoboa_auth_oauth2
|
||||
|
||||
Then, add the following line in `[auth]`::
|
||||
|
||||
oauth2_introspection_endpoint = https://radical:<client_secret>@<hostname of your server>/api/o/introspect/
|
||||
|
||||
|
||||
Replace ``<client_secret>`` with the value you obtained earlier.
|
||||
+12
-21
@@ -85,24 +85,6 @@ If some error appears, you may try this:
|
||||
|
||||
> git reset --hard origin/master
|
||||
|
||||
|
||||
New-admin interface
|
||||
*******************
|
||||
|
||||
.. note::
|
||||
You don't need to perform these actions if you use the installer to upgrade your instance.
|
||||
|
||||
New admin interface won't update by itself. Run the following commands to update it:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
> sudo -u <modoboa_user> -i bash
|
||||
> cd <modoboa_instance_dir>
|
||||
> cp frontend/config.json ./
|
||||
> rm -rf frontend
|
||||
> cp -R <virtuenv_path>/lib/pythonX.X/site-packages/modoboa/frontend_dist/ frontend/
|
||||
> cp ./config.json frontend/config.json
|
||||
|
||||
Extensions
|
||||
**********
|
||||
|
||||
@@ -195,8 +177,9 @@ Required changes to :file:`settings.py`
|
||||
- ``modoboa_contacts`` -> ``modoboa.contacts``
|
||||
- ``modoboa_radicale`` -> ``modoboa.calendars``
|
||||
- ``modoboa_webmail`` -> ``modoboa.webmail``
|
||||
- ``modoboa_rspamd`` -> ``modoboa.rspamd``
|
||||
|
||||
- Remove configuration blocks related to ``modoboa_contacts`` and ``modoboa_radicale`` plugins
|
||||
- Remove configuration blocks related to ``modoboa_contacts`` and ``modoboa_radicale`` plugins (these should be at the end of the file)
|
||||
|
||||
- Remove ``AjaxLoginRedirect`` from ``MIDDLEWARE`` variable:
|
||||
|
||||
@@ -217,14 +200,20 @@ Required changes to :file:`settings.py`
|
||||
'modoboa.lib.middleware.RequestCatcherMiddleware',
|
||||
)
|
||||
|
||||
- Remove ``NEW_ADMIN_URL`` variable
|
||||
- Remove ``NEW_ADMIN_URL`` variable if found
|
||||
|
||||
- Remove ``new_admin_url`` and ``top_notifications`` context processors
|
||||
|
||||
- Remove ``ckeditor`` related apps from ``INSTALLED_APPS`` variable
|
||||
- Remove ``ckeditor`` related apps from ``INSTALLED_APPS`` variable and ``CKEDITOR_*`` settings
|
||||
|
||||
- Remove ``STATICFILE_DIRS`` variable
|
||||
|
||||
Radicale configuration changes
|
||||
-----------------------------
|
||||
|
||||
You must enable oauth2 authentication in Radicale to make the calendar
|
||||
and contact feature work. Follow this :ref:`guide <radicale_oauth2>`.
|
||||
|
||||
Post update
|
||||
-----------
|
||||
|
||||
@@ -236,6 +225,8 @@ Post update
|
||||
|
||||
- Remove ``autoreply`` service definition from postfix`s :file:`master.cf` file if you were using it
|
||||
|
||||
- Make sure :file:`/etc/uwsgi/sites-enabled/<modoboa_conf_file>` contains `max-requests=5000` and that `process` is superior or equal to 4. Don't forget to restart uwsgi service after the configuration change.
|
||||
|
||||
- Then proceed with regular upgrade instructions
|
||||
|
||||
Version 2.3.3
|
||||
|
||||
+48
-3
@@ -1,8 +1,10 @@
|
||||
from django.db.utils import ProgrammingError, OperationalError
|
||||
from django.core.checks import register, Info, Warning
|
||||
from django.core.checks import register, Info, Warning, Error
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from oauth2_provider.models import get_application_model
|
||||
|
||||
from modoboa.core.utils import (
|
||||
check_for_deprecated_password_schemes,
|
||||
generate_rsa_private_key,
|
||||
@@ -15,14 +17,41 @@ W001 = Warning(
|
||||
"twice due to clock change)."
|
||||
),
|
||||
hint=_("Set `USE_TZ = True` in settings.py"),
|
||||
id="modoboa.W001",
|
||||
id="modoboa.core.W001",
|
||||
)
|
||||
W002 = Warning(
|
||||
_("The password scheme you are using is deprecated."),
|
||||
hint=_("Upgrade your password scheme to a stronger one"),
|
||||
id="modoboa.W002",
|
||||
id="modoboa.core.W002",
|
||||
)
|
||||
|
||||
E001 = Error(
|
||||
_(
|
||||
"Oauth2 application for dovecot has not been found."
|
||||
" Webmail and some other features won't be available."
|
||||
),
|
||||
hint=_(
|
||||
"Visit : https://modoboa.readthedocs.io/en/latest/manual_installation/dovecot.html#dovecot-oauth2"
|
||||
),
|
||||
id="modoboa.core.E001",
|
||||
)
|
||||
|
||||
E002 = Error(
|
||||
_(
|
||||
"Oauth2 application for radicale has not been found."
|
||||
" Calendar and some other features won't be available."
|
||||
),
|
||||
hint=_(
|
||||
"Visit : https://modoboa.readthedocs.io/en/latest/manual_installation/radicale.html#radicale-oauth2"
|
||||
),
|
||||
id="modoboa.core.E002",
|
||||
)
|
||||
|
||||
|
||||
def oauth_app_exists(app_name):
|
||||
oauth_application = get_application_model().objects.filter(name=app_name)
|
||||
return oauth_application.exists()
|
||||
|
||||
|
||||
@register(deploy=True)
|
||||
def check_use_tz_enabled(app_configs, **kwargs):
|
||||
@@ -59,3 +88,19 @@ def check_password_hasher(app_configs, **kwargs):
|
||||
if hasher:
|
||||
msgs.append(W002)
|
||||
return msgs
|
||||
|
||||
|
||||
@register(deploy=True)
|
||||
def check_dovecot_oauth_app(*args, **kwargs):
|
||||
error = []
|
||||
if not oauth_app_exists("Dovecot"):
|
||||
error.append(E001)
|
||||
return error
|
||||
|
||||
|
||||
@register(deploy=True)
|
||||
def check_radicale_oauth_app(*args, **kwargs):
|
||||
error = []
|
||||
if not oauth_app_exists("Radicale"):
|
||||
error.append(E002)
|
||||
return error
|
||||
|
||||
@@ -106,15 +106,18 @@ class Command(BaseCommand):
|
||||
|
||||
app_model = get_application_model()
|
||||
allowed_host = getattr(settings, "ALLOWED_HOSTS", None)
|
||||
if allowed_host is not None:
|
||||
allowed_host = allowed_host[0]
|
||||
else:
|
||||
if allowed_host is None:
|
||||
allowed_host = input("What will be the hostname used to access Modoboa? ")
|
||||
if not allowed_host:
|
||||
allowed_host = "localhost"
|
||||
allowed_host = [allowed_host]
|
||||
frontend_application = app_model.objects.filter(name="modoboa_frontend")
|
||||
base_uri = f"https://{allowed_host}"
|
||||
redirect_uri = f"{base_uri}/login/logged"
|
||||
# TODO : improve support for multiple allowed_host for frontend
|
||||
base_uris_list = [f"https://{host}" for host in allowed_host]
|
||||
base_uris = " ".join(base_uris_list)
|
||||
base_uri = base_uris_list[0]
|
||||
redirect_uris = " ".join([f"{uri}/login/logged" for uri in base_uris_list])
|
||||
redirect_uri = redirect_uris.split(" ")[0]
|
||||
client_id = ""
|
||||
if not frontend_application.exists():
|
||||
if options["dev"]:
|
||||
@@ -126,18 +129,18 @@ class Command(BaseCommand):
|
||||
call_command(
|
||||
"createapplication",
|
||||
"--algorithm=RS256",
|
||||
f"--redirect-uris={redirect_uri}",
|
||||
f"--redirect-uris={redirect_uris}",
|
||||
"--name=modoboa_frontend",
|
||||
f"--client-id={client_id}",
|
||||
f"--post-logout-redirect-uris={base_uri}",
|
||||
f"--post-logout-redirect-uris={base_uris}",
|
||||
"--skip-authorization",
|
||||
"public",
|
||||
"authorization-code",
|
||||
)
|
||||
else:
|
||||
app = frontend_application.first()
|
||||
app.redirect_uris = redirect_uri
|
||||
app.post_logout_redirect_urls = base_uri
|
||||
app.redirect_uris = redirect_uris
|
||||
app.post_logout_redirect_uris = base_uris
|
||||
app.save()
|
||||
client_id = app.client_id
|
||||
|
||||
@@ -150,9 +153,11 @@ class Command(BaseCommand):
|
||||
os.makedirs(frontend_target_dir, exist_ok=True)
|
||||
for entry in os.scandir(base_frontend_dir):
|
||||
if entry.name != "config.json":
|
||||
os.symlink(f"{base_frontend_dir}/{entry.name}",
|
||||
f"{frontend_target_dir}/{entry.name}",
|
||||
target_is_directory=entry.is_dir())
|
||||
os.symlink(
|
||||
f"{base_frontend_dir}/{entry.name}",
|
||||
f"{frontend_target_dir}/{entry.name}",
|
||||
target_is_directory=entry.is_dir(),
|
||||
)
|
||||
with open(f"{frontend_target_dir}/config.json", "w") as fp:
|
||||
fp.write(
|
||||
f"""{{
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from oauth2_provider.models import get_application_model
|
||||
|
||||
from modoboa.core import checks
|
||||
from modoboa.lib.tests import SimpleModoTestCase
|
||||
|
||||
|
||||
class CheckSessionCookieSecureTest(SimpleModoTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.workdir = tempfile.mkdtemp()
|
||||
|
||||
@@ -35,3 +38,37 @@ class CheckSessionCookieSecureTest(SimpleModoTestCase):
|
||||
os.environ["OIDC_RSA_PRIVATE_KEY"] = "KEY"
|
||||
msgs = checks.check_rsa_private_key_exists(None)
|
||||
self.assertEqual(len(msgs), 0)
|
||||
|
||||
def test_dovecot_oauth_app_exists(self):
|
||||
get_application_model().objects.filter(name="Dovecot").delete()
|
||||
msgs = checks.check_dovecot_oauth_app()
|
||||
self.assertEqual(len(msgs), 1)
|
||||
client_secret = str(uuid.uuid4())
|
||||
call_command(
|
||||
"createapplication",
|
||||
"--name=Dovecot",
|
||||
"--skip-authorization",
|
||||
"--client-id=dovecot",
|
||||
f"--client-secret={client_secret}",
|
||||
"confidential",
|
||||
"client-credentials",
|
||||
)
|
||||
msgs = checks.check_dovecot_oauth_app()
|
||||
self.assertEqual(len(msgs), 0)
|
||||
|
||||
def test_radicale_oauth_app_exists(self):
|
||||
get_application_model().objects.filter(name="Radicale").delete()
|
||||
msgs = checks.check_radicale_oauth_app()
|
||||
self.assertEqual(len(msgs), 1)
|
||||
client_secret = str(uuid.uuid4())
|
||||
call_command(
|
||||
"createapplication",
|
||||
"--name=Radicale",
|
||||
"--skip-authorization",
|
||||
"--client-id=radicale",
|
||||
f"--client-secret={client_secret}",
|
||||
"confidential",
|
||||
"client-credentials",
|
||||
)
|
||||
msgs = checks.check_radicale_oauth_app()
|
||||
self.assertEqual(len(msgs), 0)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 550 B |
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>{% block pagetitle %}{% endblock %}</title>
|
||||
<link rel="icon" type="image/png" href="{% static 'css/logo-icon.png' %}" />
|
||||
<link rel="icon" type="image/x-icon" href="{% static 'css/favicon.ico' %}" />
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/offline.css' %}" />
|
||||
</head>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>{% trans "Welcome to Modoboa" %}</title>
|
||||
<link rel="icon" type="image/png" href="{% static 'css/logo-icon.png' %}" />
|
||||
<link rel="icon" type="image/x-icon" href="{% static 'css/favicon.ico' %}" />
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/offline.css' %}" />
|
||||
{% block extra_css %}{% endblock %}
|
||||
</head>
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ dependencies = [
|
||||
"django-rename-app==0.1.7",
|
||||
"django-environ",
|
||||
"dj-database-url",
|
||||
"djangorestframework>=3.14,<3.17",
|
||||
"djangorestframework>=3.16,<3.17",
|
||||
"drf-spectacular",
|
||||
"uritemplate",
|
||||
"django-oauth-toolkit",
|
||||
|
||||
Reference in New Issue
Block a user