mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-26 06:08:38 +01:00
LDAP improvements:
* Support for domain adminstrator groups mapping (fixes #449) * Support for better hash algorithm (see #450)
This commit is contained in:
@@ -118,9 +118,9 @@ class GeneralParametersForm(parameters.AdminParametersForm):
|
||||
)
|
||||
|
||||
ldap_search_base = forms.CharField(
|
||||
label=ugettext_lazy("Search base"),
|
||||
label=ugettext_lazy("Users search base"),
|
||||
initial="",
|
||||
help_text=ugettext_lazy("The distinguished name of the search base"),
|
||||
help_text=ugettext_lazy("The distinguished name of the search base used to find users"),
|
||||
required=False
|
||||
)
|
||||
|
||||
@@ -150,6 +150,25 @@ class GeneralParametersForm(parameters.AdminParametersForm):
|
||||
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 groups will be created as domain "
|
||||
"administrators. Use a ';' 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"))
|
||||
|
||||
log_maximum_age = forms.IntegerField(
|
||||
@@ -185,6 +204,8 @@ class GeneralParametersForm(parameters.AdminParametersForm):
|
||||
"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):
|
||||
@@ -243,7 +264,7 @@ class GeneralParametersForm(parameters.AdminParametersForm):
|
||||
"""
|
||||
try:
|
||||
import ldap
|
||||
from django_auth_ldap.config import LDAPSearch
|
||||
from django_auth_ldap.config import LDAPSearch, PosixGroupType
|
||||
ldap_available = True
|
||||
except ImportError:
|
||||
ldap_available = False
|
||||
@@ -260,6 +281,11 @@ class GeneralParametersForm(parameters.AdminParametersForm):
|
||||
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"])
|
||||
@@ -270,7 +296,6 @@ class GeneralParametersForm(parameters.AdminParametersForm):
|
||||
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", {
|
||||
|
||||
@@ -108,7 +108,7 @@ class User(PermissionsMixin):
|
||||
:param raw_value: the new password's value
|
||||
:param curvalue: the current password (for LDAP authentication)
|
||||
"""
|
||||
if parameters.get_admin("AUTHENTICATION_TYPE") == "local":
|
||||
if self.is_local:
|
||||
self.password = self._crypt_password(raw_value)
|
||||
else:
|
||||
if not ldap_available:
|
||||
@@ -363,7 +363,7 @@ class User(PermissionsMixin):
|
||||
reversion.register(User)
|
||||
|
||||
|
||||
def populate_callback(user):
|
||||
def populate_callback(user, group='SimpleUsers'):
|
||||
"""Populate callback
|
||||
|
||||
If the LDAP authentication backend is in use, this callback will
|
||||
@@ -376,7 +376,7 @@ def populate_callback(user):
|
||||
from modoboa.lib.permissions import grant_access_to_object
|
||||
|
||||
sadmins = User.objects.filter(is_superuser=True)
|
||||
user.set_role("SimpleUsers")
|
||||
user.set_role(group)
|
||||
user.post_create(sadmins[0])
|
||||
for su in sadmins[1:]:
|
||||
grant_access_to_object(su, user)
|
||||
|
||||
@@ -16,7 +16,10 @@ class MD5CRYPTHasher(PasswordHasher):
|
||||
"""
|
||||
@property
|
||||
def scheme(self):
|
||||
return '{MD5-CRYPT}'
|
||||
return '{MD5-CRYPT}' if self._target == 'local' else '{CRYPT}'
|
||||
|
||||
def _b64encode(self, pwhash):
|
||||
return pwhash
|
||||
|
||||
def _encrypt(self, clearvalue, salt=None):
|
||||
return md5_crypt.encrypt(clearvalue)
|
||||
@@ -34,7 +37,10 @@ class SHA256CRYPTHasher(PasswordHasher):
|
||||
"""
|
||||
@property
|
||||
def scheme(self):
|
||||
return '{SHA256-CRYPT}'
|
||||
return '{SHA256-CRYPT}' if self._target == 'local' else '{CRYPT}'
|
||||
|
||||
def _b64encode(self, pwhash):
|
||||
return pwhash
|
||||
|
||||
def _encrypt(self, clearvalue, salt=None):
|
||||
rounds = int(parameters.get_admin('ROUNDS_NUMBER'))
|
||||
@@ -53,7 +59,10 @@ class SHA512CRYPTHasher(PasswordHasher):
|
||||
"""
|
||||
@property
|
||||
def scheme(self):
|
||||
return '{SHA512-CRYPT}'
|
||||
return '{SHA512-CRYPT}' if self._target == 'local' else '{CRYPT}'
|
||||
|
||||
def _b64encode(self, pwhash):
|
||||
return pwhash
|
||||
|
||||
def _encrypt(self, clearvalue, salt=None):
|
||||
rounds = int(parameters.get_admin('ROUNDS_NUMBER'))
|
||||
|
||||
@@ -15,6 +15,22 @@ class PasswordHasher(object):
|
||||
"""
|
||||
Base class of all hashers.
|
||||
"""
|
||||
def __init__(self, target='local'):
|
||||
self._target = target
|
||||
|
||||
def _encrypt(self, clearvalue, salt=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def _b64encode(self, pwhash):
|
||||
"""Encode :keyword:`pwhash` using base64 if needed.
|
||||
|
||||
:param str pwhash: password hash
|
||||
:return: base64 encoded hash or original hash
|
||||
"""
|
||||
if self._target == 'ldap':
|
||||
return base64.b64encode(pwhash)
|
||||
return pwhash
|
||||
|
||||
def encrypt(self, clearvalue):
|
||||
"""Encrypt a password.
|
||||
|
||||
@@ -28,7 +44,8 @@ class PasswordHasher(object):
|
||||
:rtype: str
|
||||
:return: encrypted password
|
||||
"""
|
||||
return '%s%s' % (self.scheme, self._encrypt(clearvalue))
|
||||
pwhash = self._b64encode(self._encrypt(clearvalue))
|
||||
return '%s%s' % (self.scheme, pwhash)
|
||||
|
||||
def verify(self, clearvalue, hashed_value):
|
||||
"""Verify a password against a hashed value.
|
||||
@@ -97,4 +114,12 @@ class SHA256Hasher(PasswordHasher):
|
||||
return '{SHA256}'
|
||||
|
||||
def _encrypt(self, clearvalue, salt=None):
|
||||
return base64.b64encode(hashlib.sha256(clearvalue).digest())
|
||||
return hashlib.sha256(clearvalue).digest()
|
||||
|
||||
def _b64encode(self, pwhash):
|
||||
"""Encode :keyword:`pwhash` using base64.
|
||||
|
||||
:param str pwhash: password hash
|
||||
:return: base64 encoded hash
|
||||
"""
|
||||
return base64.b64encode(pwhash)
|
||||
|
||||
Reference in New Issue
Block a user