mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-20 06:08:35 +02:00
386 lines
14 KiB
Python
386 lines
14 KiB
Python
# coding: utf-8
|
|
from django import forms
|
|
from django.conf import settings
|
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
|
|
|
from modoboa.lib import parameters
|
|
from modoboa.lib.cryptutils import random_key
|
|
from modoboa.lib.form_utils import YesNoField, SeparatorField, InlineRadioSelect
|
|
|
|
|
|
def enabled_applications():
|
|
"""Return the list of installed extensions.
|
|
|
|
We check if the table exists before trying to fetch activated
|
|
extensions because the admin module is always imported by Django,
|
|
even before the database exists (example: the first ``syncdb``).
|
|
|
|
:return: a list
|
|
"""
|
|
from modoboa.core.extensions import exts_pool
|
|
|
|
result = [("user", "user")]
|
|
for extension in exts_pool.list_all():
|
|
result.append((extension["name"], extension["name"]))
|
|
return sorted(result, key=lambda e: e[0])
|
|
|
|
|
|
class GeneralParametersForm(parameters.AdminParametersForm):
|
|
|
|
"""General parameters."""
|
|
|
|
app = "core"
|
|
|
|
sep1 = SeparatorField(label=ugettext_lazy("Authentication"))
|
|
|
|
authentication_type = forms.ChoiceField(
|
|
label=ugettext_lazy("Authentication type"),
|
|
choices=[('local', ugettext_lazy("Local")),
|
|
('ldap', "LDAP")],
|
|
initial="local",
|
|
help_text=ugettext_lazy("The backend used for authentication"),
|
|
widget=InlineRadioSelect
|
|
)
|
|
|
|
password_scheme = forms.ChoiceField(
|
|
label=ugettext_lazy("Default password scheme"),
|
|
choices=[("sha512crypt", "sha512crypt"),
|
|
("sha256crypt", "sha256crypt"),
|
|
("md5crypt", ugettext_lazy("md5crypt (weak)")),
|
|
("sha256", ugettext_lazy("sha256 (weak)")),
|
|
("md5", ugettext_lazy("md5 (weak)")),
|
|
("crypt", ugettext_lazy("crypt (weak)")),
|
|
("plain", ugettext_lazy("plain (weak)"))],
|
|
initial="sha512crypt",
|
|
help_text=ugettext_lazy("Scheme used to crypt mailbox passwords"),
|
|
widget=forms.Select(attrs={"class": "form-control"})
|
|
)
|
|
|
|
rounds_number = forms.IntegerField(
|
|
label=ugettext_lazy("Rounds"),
|
|
initial=70000,
|
|
help_text=ugettext_lazy(
|
|
"Number of rounds to use (only used by sha256crypt and "
|
|
"sha512crypt). Must be between 1000 and 999999999, inclusive."
|
|
),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
secret_key = forms.CharField(
|
|
label=ugettext_lazy("Secret key"),
|
|
initial=random_key(),
|
|
help_text=ugettext_lazy("Key used to encrypt/decrypt passwords"),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
# LDAP specific settings
|
|
ldap_sep = SeparatorField(label=ugettext_lazy("LDAP settings"))
|
|
|
|
ldap_server_address = forms.CharField(
|
|
label=ugettext_lazy("Server address"),
|
|
initial="localhost",
|
|
help_text=ugettext_lazy(
|
|
"The IP address of the DNS name of the LDAP server"),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_server_port = forms.IntegerField(
|
|
label=ugettext_lazy("Server port"),
|
|
initial=389,
|
|
help_text=ugettext_lazy("The TCP port number used by the LDAP server"),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_secured = YesNoField(
|
|
label=ugettext_lazy("Use a secured connection"),
|
|
initial="no",
|
|
help_text=ugettext_lazy(
|
|
"Use an SSL/TLS connection to access the LDAP server")
|
|
)
|
|
|
|
ldap_auth_method = forms.ChoiceField(
|
|
label=ugettext_lazy("Authentication method"),
|
|
choices=[('searchbind', ugettext_lazy("Search and bind")),
|
|
('directbind', ugettext_lazy("Direct bind"))],
|
|
initial='searchbind',
|
|
help_text=ugettext_lazy("Choose the authentication method to use"),
|
|
widget=forms.Select(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_bind_dn = forms.CharField(
|
|
label=ugettext_lazy("Bind DN"),
|
|
initial='',
|
|
help_text=ugettext_lazy(
|
|
"The distinguished name to use when binding to the LDAP server. "
|
|
"Leave empty for an anonymous bind"
|
|
),
|
|
required=False,
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_bind_password = forms.CharField(
|
|
label=ugettext_lazy("Bind password"),
|
|
initial='',
|
|
help_text=ugettext_lazy(
|
|
"The password to use when binding to the LDAP server "
|
|
"(with 'Bind DN')"
|
|
),
|
|
widget=forms.PasswordInput(
|
|
attrs={"class": "form-control"}, render_value=True),
|
|
required=False
|
|
)
|
|
|
|
ldap_search_base = forms.CharField(
|
|
label=ugettext_lazy("Users search base"),
|
|
initial="",
|
|
help_text=ugettext_lazy(
|
|
"The distinguished name of the search base used to find users"
|
|
),
|
|
required=False,
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_search_filter = forms.CharField(
|
|
label=ugettext_lazy("Search filter"),
|
|
initial="(mail=%(user)s)",
|
|
help_text=ugettext_lazy(
|
|
"An optional filter string (e.g. '(objectClass=person)'). "
|
|
"In order to be valid, it must be enclosed in parentheses."
|
|
),
|
|
required=False,
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_user_dn_template = forms.CharField(
|
|
label=ugettext_lazy("User DN template"),
|
|
initial="",
|
|
help_text=ugettext_lazy(
|
|
"The template used to construct a user's DN. It should contain "
|
|
"one placeholder (ie. %(user)s)"
|
|
),
|
|
required=False,
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_password_attribute = forms.CharField(
|
|
label=ugettext_lazy("Password attribute"),
|
|
initial="userPassword",
|
|
help_text=ugettext_lazy("The attribute used to store user passwords"),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
ldap_is_active_directory = YesNoField(
|
|
label=ugettext_lazy("Active Directory"),
|
|
initial="no",
|
|
help_text=ugettext_lazy(
|
|
"Tell if the LDAP server is an Active Directory one")
|
|
)
|
|
|
|
ldap_admin_groups = forms.CharField(
|
|
label=ugettext_lazy("Administrator groups"),
|
|
initial="",
|
|
help_text=ugettext_lazy(
|
|
"Members of those LDAP Posix groups will be created as domain "
|
|
"administrators. Use ';' characters to separate groups."
|
|
),
|
|
required=False
|
|
)
|
|
|
|
ldap_groups_search_base = forms.CharField(
|
|
label=ugettext_lazy("Groups search base"),
|
|
initial="",
|
|
help_text=ugettext_lazy(
|
|
"The distinguished name of the search base used to find groups"
|
|
),
|
|
required=False
|
|
)
|
|
|
|
sep3 = SeparatorField(label=ugettext_lazy("Miscellaneous"))
|
|
|
|
top_notifications_check_interval = forms.IntegerField(
|
|
label=_("Top notifications check interval"),
|
|
initial=30,
|
|
help_text=_("Interval between two top notification checks"),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
check_new_versions = YesNoField(
|
|
label=ugettext_lazy("Check new versions"),
|
|
initial="yes",
|
|
help_text=ugettext_lazy(
|
|
"Automatically checks if a newer version is available")
|
|
)
|
|
|
|
log_maximum_age = forms.IntegerField(
|
|
label=ugettext_lazy("Maximum log record age"),
|
|
initial=365,
|
|
help_text=ugettext_lazy("The maximum age in days of a log record"),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
items_per_page = forms.IntegerField(
|
|
label=ugettext_lazy("Items per page"),
|
|
initial=30,
|
|
help_text=ugettext_lazy("Number of displayed items per page"),
|
|
widget=forms.TextInput(attrs={"class": "form-control"})
|
|
)
|
|
|
|
default_top_redirection = forms.ChoiceField(
|
|
label=ugettext_lazy("Default top redirection"),
|
|
choices=[],
|
|
initial="user",
|
|
help_text=ugettext_lazy(
|
|
"The default redirection used when no application is specified"
|
|
),
|
|
widget=forms.Select(attrs={"class": "form-control"})
|
|
)
|
|
|
|
# Visibility rules
|
|
visibility_rules = {
|
|
"ldap_sep": "authentication_type=ldap",
|
|
"ldap_server_address": "authentication_type=ldap",
|
|
"ldap_server_port": "authentication_type=ldap",
|
|
"ldap_secured": "authentication_type=ldap",
|
|
"ldap_auth_method": "authentication_type=ldap",
|
|
"ldap_bind_dn": "ldap_auth_method=searchbind",
|
|
"ldap_bind_password": "ldap_auth_method=searchbind",
|
|
"ldap_search_base": "ldap_auth_method=searchbind",
|
|
"ldap_search_filter": "ldap_auth_method=searchbind",
|
|
"ldap_user_dn_template": "ldap_auth_method=directbind",
|
|
"ldap_password_attribute": "authentication_type=ldap",
|
|
"ldap_is_active_directory": "authentication_type=ldap",
|
|
"ldap_admin_groups": "authentication_type=ldap",
|
|
"ldap_groups_search_base": "authentication_type=ldap",
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(GeneralParametersForm, self).__init__(*args, **kwargs)
|
|
self.fields["default_top_redirection"].choices = enabled_applications()
|
|
|
|
def clean_secret_key(self):
|
|
if len(self.cleaned_data["secret_key"]) not in [16, 24, 32]:
|
|
raise forms.ValidationError(
|
|
_("Key must be either 16, 24, or 32 bytes long")
|
|
)
|
|
return self.cleaned_data["secret_key"]
|
|
|
|
def clean_ldap_user_dn_template(self):
|
|
tpl = self.cleaned_data["ldap_user_dn_template"]
|
|
try:
|
|
test = tpl % {"user": "toto"}
|
|
except (KeyError, ValueError):
|
|
raise forms.ValidationError(_("Invalid syntax"))
|
|
return tpl
|
|
|
|
def clean_rounds_number(self):
|
|
value = self.cleaned_data["rounds_number"]
|
|
if value < 1000 or value > 999999999:
|
|
raise forms.ValidationError(_("Invalid rounds number"))
|
|
return value
|
|
|
|
def clean(self):
|
|
"""Custom validation method
|
|
|
|
Depending on 'ldap_auth_method' value, we check for different
|
|
required parameters.
|
|
"""
|
|
super(GeneralParametersForm, self).clean()
|
|
cleaned_data = self.cleaned_data
|
|
if cleaned_data["authentication_type"] != "ldap":
|
|
return cleaned_data
|
|
|
|
if cleaned_data["ldap_auth_method"] == "searchbind":
|
|
required_fields = ["ldap_search_base", "ldap_search_filter"]
|
|
else:
|
|
required_fields = ["ldap_user_dn_template"]
|
|
|
|
for f in required_fields:
|
|
if f not in cleaned_data or cleaned_data[f] == u'':
|
|
self.add_error(f, _("This field is required"))
|
|
|
|
return cleaned_data
|
|
|
|
def to_django_settings(self):
|
|
"""Apply LDAP related parameters to Django settings
|
|
|
|
Doing so, we can use the django_auth_ldap module.
|
|
"""
|
|
try:
|
|
import ldap
|
|
from django_auth_ldap.config import LDAPSearch, PosixGroupType
|
|
ldap_available = True
|
|
except ImportError:
|
|
ldap_available = False
|
|
|
|
values = self.get_current_values()
|
|
if not ldap_available or values["authentication_type"] != "ldap":
|
|
return
|
|
if not hasattr(settings, "AUTH_LDAP_USER_ATTR_MAP"):
|
|
setattr(settings, "AUTH_LDAP_USER_ATTR_MAP", {
|
|
"first_name": "givenName",
|
|
"email": "mail",
|
|
"last_name": "sn"
|
|
})
|
|
ldap_uri = 'ldaps://' if values["ldap_secured"] == "yes" else "ldap://"
|
|
ldap_uri += "%s:%s" % (
|
|
values["ldap_server_address"], values["ldap_server_port"])
|
|
setattr(settings, "AUTH_LDAP_SERVER_URI", ldap_uri)
|
|
setattr(settings, "AUTH_LDAP_GROUP_TYPE", PosixGroupType())
|
|
setattr(settings, "AUTH_LDAP_GROUP_SEARCH", LDAPSearch(
|
|
values["ldap_groups_search_base"], ldap.SCOPE_SUBTREE,
|
|
"(objectClass=posixGroup)"
|
|
))
|
|
if values["ldap_auth_method"] == "searchbind":
|
|
setattr(settings, "AUTH_LDAP_BIND_DN", values["ldap_bind_dn"])
|
|
setattr(
|
|
settings, "AUTH_LDAP_BIND_PASSWORD",
|
|
values["ldap_bind_password"]
|
|
)
|
|
search = LDAPSearch(
|
|
values["ldap_search_base"], ldap.SCOPE_SUBTREE,
|
|
values["ldap_search_filter"]
|
|
)
|
|
setattr(settings, "AUTH_LDAP_USER_SEARCH", search)
|
|
else:
|
|
setattr(
|
|
settings, "AUTH_LDAP_USER_DN_TEMPLATE",
|
|
values["ldap_user_dn_template"]
|
|
)
|
|
if values["ldap_is_active_directory"] == "yes":
|
|
if not hasattr(settings, "AUTH_LDAP_GLOBAL_OPTIONS"):
|
|
setattr(settings, "AUTH_LDAP_GLOBAL_OPTIONS", {
|
|
ldap.OPT_REFERRALS: False
|
|
})
|
|
else:
|
|
settings.AUTH_LDAP_GLOBAL_OPTIONS[ldap.OPT_REFERRALS] = False
|
|
|
|
|
|
def translate_language_code(value):
|
|
if "-" in value:
|
|
return value.split("-")[0]
|
|
return value
|
|
|
|
|
|
class UserSettings(parameters.UserParametersForm):
|
|
app = "core"
|
|
|
|
sep = SeparatorField(label=ugettext_lazy("Display"))
|
|
|
|
lang = forms.ChoiceField(
|
|
initial=translate_language_code(settings.LANGUAGE_CODE),
|
|
label=ugettext_lazy("Prefered language"),
|
|
choices=[("cs", "čeština"),
|
|
("de", "deutsch"),
|
|
("en", "english"),
|
|
("es", "español"),
|
|
("fr", "français"),
|
|
("it", "italiano"),
|
|
("nl", "nederlands"),
|
|
("pt_PT", "português"),
|
|
("pt_BR", "português (BR)"),
|
|
("ru", "русский"),
|
|
("sv", "svenska")],
|
|
help_text=ugettext_lazy("Prefered language to display pages"),
|
|
widget=forms.Select(attrs={"class": "form-control"})
|
|
)
|