* Possibility to configure LDAP authentication through the online panel (see #289)

* Simpler way to define visibility rules (see #392)
This commit is contained in:
Antoine Nguyen
2013-04-12 22:42:21 +02:00
parent 919f4522be
commit d1353678ff
7 changed files with 182 additions and 23 deletions
+146 -3
View File
@@ -56,6 +56,83 @@ class GeneralParametersForm(parameters.AdminParametersForm):
help_text=ugettext_lazy("Key used to encrypt/decrypt passwords")
)
# 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")
)
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")
)
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")
)
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
)
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,
required=False
)
ldap_search_base = forms.CharField(
label=ugettext_lazy("Search base"),
initial="",
help_text=ugettext_lazy("The distinguished name of the search base"),
required=False
)
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
)
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
)
ldap_password_attribute = forms.CharField(
label=ugettext_lazy("Password attribute"),
initial="userPassword",
help_text=ugettext_lazy("The attribute used to store user passwords")
)
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")
)
sep2 = SeparatorField(label=ugettext_lazy("Mailboxes"))
handle_mailboxes = YesNoField(
@@ -91,6 +168,23 @@ class GeneralParametersForm(parameters.AdminParametersForm):
help_text=ugettext_lazy("The default redirection used when no application is specified")
)
# Visibility rules
visibility_rules = {
"mailboxes_owner": "handle_mailboxes=yes",
"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"
}
def __init__(self, *args, **kwargs):
super(GeneralParametersForm, self).__init__(*args, **kwargs)
self.fields["default_top_redirection"].choices = enabled_applications()
@@ -106,10 +200,59 @@ class GeneralParametersForm(parameters.AdminParametersForm):
del self.fields["handle_mailboxes"]
del self.fields["mailboxes_owner"]
# Visibility rules
def visibility_mailboxes_owner(self):
return "handle_mailboxes=yes"
def clean(self):
"""Custom validation method
Depending on 'ldap_auth_method' value, we check for different
required parameters.
"""
super(GeneralParametersForm, self).clean()
if len(self._errors):
raise forms.ValidationError(self._errors)
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 not f in cleaned_data or cleaned_data[f] == u'':
self._errors[f] = self.error_class([_("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.
"""
from django.conf import settings
try:
import ldap
from django_auth_ldap.config import LDAPSearch
ldap_available = True
except ImportError:
ldap_available = False
values = self.get_current_values()
if not ldap_available or values["authentication_type"] != "ldap":
return
ldap_uri = 'ldap://' if values["ldap_secured"] == "yes" else "ldaps://"
ldap_uri += "%s:%s" % (values["ldap_server_address"], values["ldap_server_port"])
setattr(settings, "AUTH_LDAP_SERVER_URI", ldap_uri)
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"])
parameters.register(GeneralParametersForm, ugettext_lazy("General"))
+5 -9
View File
@@ -71,15 +71,11 @@ class ParametersForm(AdminParametersForm):
help_text=_("The e-mail address used to send notitications")
)
# Visibility rules
def visibility_am_pdp_host(self):
return "am_pdp_mode=inet"
def visibility_am_pdp_port(self):
return "am_pdp_mode=inet"
def visibility_am_pdp_socket(self):
return "am_pdp_mode=unix"
visibility_rules = {
"am_pdp_host": "am_pdp_mode=inet",
"am_pdp_port": "am_pdp_mode=inet",
"am_pdp_socket": "am_pdp_mode=unix"
}
class UserSettings(UserParametersForm):
+3 -2
View File
@@ -133,8 +133,9 @@ class UserSettings(UserParametersForm):
required=False
)
def visibility_enable_links(self):
return "displaymode=html"
visibility_rules = {
"enable_links": "displaymode=html"
}
@staticmethod
def has_access(user):
+21 -7
View File
@@ -40,13 +40,11 @@ class GenericParametersForm(forms.Form):
super(GenericParametersForm, self).__init__(*args, **kwargs)
self.visirules = {}
for param in self.fields.keys():
fname = "visibility_%s" % param
if not hasattr(self, fname):
continue
field, value = getattr(self, fname)().split("=")
visibility = {"field": "id_%s-%s" % (self.app, field), "value": value}
self.visirules["%s-%s" % (self.app, param)] = visibility
if hasattr(self, "visibility_rules"):
for key, rule in self.visibility_rules.items():
field, value = rule.split("=")
visibility = {"field": "id_%s-%s" % (self.app, field), "value": value}
self.visirules["%s-%s" % (self.app, key)] = visibility
if not args:
self._load_initial_values()
@@ -97,6 +95,17 @@ class AdminParametersForm(GenericParametersForm):
p.name = fullname
self._save_parameter(p, name, value)
def to_django_settings(self):
pass
def get_current_values(self):
values = {}
for key in self.fields.keys():
try:
values[key] = get_admin(key.upper(), app=self.app)
except NotDefined:
pass
return values
class UserParametersForm(GenericParametersForm):
def __init__(self, *args, **kwargs):
@@ -312,3 +321,8 @@ def get_parameter_form(level, name, app=None):
app = __guess_extension()
__is_defined(app, level, name)
return _params[level][app]["form"]
def apply_to_django_settings():
for form in get_admin_forms():
form["form"].to_django_settings()
+1 -1
View File
@@ -92,7 +92,7 @@ def render_form(form, tpl=None):
@register.simple_tag
def render_field(field, help_display_mode="tooltip"):
if type(field.form.fields[field.name]) is SeparatorField:
return "<h5>%s</h5>" % unicode(field.label)
return "<h5%s>%s</h5>" % (visirule(field), unicode(field.label))
return render_to_string("common/generic_field.html", dict(
field=field, help_display_mode=help_display_mode
+4 -1
View File
@@ -87,7 +87,7 @@ TwocolsNav.prototype = {
},
toggle_field_visibility: function($field, $parent, value) {
if ($parent.attr("idsabled") === undefined &&
if ($parent.attr("disabled") === undefined &&
$field.attr("data-visibility-value") == value) {
$field.attr("disabled", null);
$field.show();
@@ -107,6 +107,9 @@ TwocolsNav.prototype = {
$('div[data-visibility-field="' + $target.attr("id") + '"]').each(function(idx) {
instance.toggle_field_visibility($(this), $parent, $target.attr("value"));
});
$('h5[data-visibility-field="' + $target.attr("id") + '"]').each(function(idx) {
instance.toggle_field_visibility($(this), $parent, $target.attr("value"));
});
},
radio_clicked: function(e) {
+2
View File
@@ -3,6 +3,8 @@ from django.conf import settings
from modoboa.extensions import *
from modoboa.lib import parameters
parameters.apply_to_django_settings()
urlpatterns = patterns('',
(r'^$', 'modoboa.lib.webutils.topredirection'),
(r'^admin/', include('modoboa.admin.urls')),