mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
Support for LDAP password modification (user level only for now). I need a working environment to check if postfix/dovecot accept the way I encrypt passwords.
see #192
This commit is contained in:
@@ -5,6 +5,10 @@ from django.utils.translation import ugettext as _
|
||||
from django.db.utils import DatabaseError
|
||||
from models import Extension
|
||||
|
||||
parameters.register_admin("AUTHENTICATION_TYPE", type="list", deflt="local",
|
||||
values=[('local', _("Local")),
|
||||
('ldap', "LDAP")],
|
||||
help=_("The backend used for authentication"))
|
||||
parameters.register_admin("CREATE_DIRECTORIES", type="list_yesno", deflt="yes",
|
||||
help=_("Modoboa will handle mailbox creation on filesystem"))
|
||||
parameters.register_admin("STORAGE_PATH", type="string", deflt="/var/vmail",
|
||||
|
||||
+59
-30
@@ -6,6 +6,7 @@ from django.conf import settings
|
||||
from modoboa.lib import parameters, events
|
||||
from modoboa.lib.sysutils import exec_cmd, exec_as_vuser
|
||||
from modoboa.lib.emailutils import split_mailbox
|
||||
from modoboa.lib.ldaputils import *
|
||||
from modoboa.auth.lib import crypt_password
|
||||
import os
|
||||
import pwd
|
||||
@@ -291,6 +292,26 @@ class Mailbox(DatesAware):
|
||||
pass
|
||||
super(Mailbox, self).save(*args, **kwargs)
|
||||
|
||||
def set_password(self, curvalue, newvalue):
|
||||
"""Password update
|
||||
|
||||
Update the current mailbox's password with the given clear
|
||||
value. This value is encrypted according to the defined method
|
||||
before it is saved.
|
||||
|
||||
:param value: the new password's value
|
||||
"""
|
||||
if parameters.get_admin("AUTHENTICATION_TYPE") == "local":
|
||||
self.password = crypt_password(value)
|
||||
self.save()
|
||||
return
|
||||
|
||||
ab = LDAPAuthBackend()
|
||||
try:
|
||||
ab.update_user_password(self.user.username, curvalue, newvalue)
|
||||
except LDAPException, e:
|
||||
raise AdminError(_("Failed to update password: %s" % str(e)))
|
||||
|
||||
def save_from_user(self, localpart, domain, user):
|
||||
"""Simple save method called for automatic creations
|
||||
|
||||
@@ -307,16 +328,16 @@ class Mailbox(DatesAware):
|
||||
# If we ever had numerical uid, don't resolve it
|
||||
v_uid = parameters.get_admin("VIRTUAL_UID");
|
||||
if v_uid.isdigit():
|
||||
self.uid = v_uid
|
||||
self.uid = v_uid
|
||||
else:
|
||||
self.uid = pwd.getpwnam(parameters.get_admin("VIRTUAL_UID")).pw_uid
|
||||
self.uid = pwd.getpwnam(parameters.get_admin("VIRTUAL_UID")).pw_uid
|
||||
# Just the same for gid
|
||||
v_gid = parameters.get_admin("VIRTUAL_GID")
|
||||
if v_gid.isdigit:
|
||||
self.gid = v_gid
|
||||
if v_gid.isdigit():
|
||||
self.gid = v_gid
|
||||
else:
|
||||
self.gid = pwd.getpwnam(parameters.get_admin("VIRTUAL_GID")).pw_gid
|
||||
self.quota = self.domain.quota
|
||||
self.gid = pwd.getpwnam(parameters.get_admin("VIRTUAL_GID")).pw_gid
|
||||
self.quota = self.domain.quota
|
||||
super(Mailbox, self).save()
|
||||
|
||||
def create_from_csv(self, line):
|
||||
@@ -489,31 +510,39 @@ class Extension(models.Model):
|
||||
|
||||
events.raiseEvent("ExtDisabled", ext=self)
|
||||
|
||||
#
|
||||
# Optional callback to execute if django-auth-ldap is enabled.
|
||||
#
|
||||
def populate_callback(sender, user=None, **kwargs):
|
||||
"""Populate signal callback
|
||||
|
||||
If the LDAP authentication backend is in use, this callback will
|
||||
be called each time a new user authenticates succesfuly to
|
||||
Modoboa. This function is in charge of creating the mailbox
|
||||
associated to the provided ``User`` object.
|
||||
|
||||
:param sender: ??
|
||||
:param user: a ``User`` instance
|
||||
"""
|
||||
if parameters.get_admin("AUTHENTICATION_TYPE") != "ldap":
|
||||
return
|
||||
if user is None:
|
||||
return
|
||||
localpart, domname = split_mailbox(user.username)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
domain = Domain()
|
||||
domain.name = domname
|
||||
domain.enabled = True
|
||||
domain.quota = 0
|
||||
domain.save()
|
||||
try:
|
||||
mb = Mailbox.objects.get(domain=domain, address=localpart)
|
||||
except Mailbox.DoesNotExist:
|
||||
mb = Mailbox()
|
||||
mb.save_from_user(localpart, domain, user)
|
||||
|
||||
try:
|
||||
from django_auth_ldap.backend import populate_user
|
||||
|
||||
def populate_callback(sender, user=None, **kwargs):
|
||||
if user is None:
|
||||
return
|
||||
localpart, domname = split_mailbox(user.username)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
domain = Domain()
|
||||
domain.name = domname
|
||||
domain.enabled = True
|
||||
domain.quota = 0
|
||||
domain.save()
|
||||
try:
|
||||
mb = Mailbox.objects.get(domain=domain, address=localpart)
|
||||
except Mailbox.DoesNotExist:
|
||||
mb = Mailbox()
|
||||
mb.save_from_user(localpart, domain, user)
|
||||
|
||||
populate_user.connect(populate_callback, dispatch_uid="myuid")
|
||||
|
||||
except ImportError, inst:
|
||||
pass
|
||||
else:
|
||||
populate_user.connect(populate_callback, dispatch_uid="myuid")
|
||||
|
||||
+3
-2
@@ -34,11 +34,12 @@ def _check_password(password, crypted):
|
||||
return hashlib.md5(password).hexdigest() == crypted
|
||||
return password
|
||||
|
||||
def crypt_password(password):
|
||||
def crypt_password(password, hexdigest=True):
|
||||
scheme = parameters.get_admin("PASSWORD_SCHEME", app="admin")
|
||||
if scheme == "crypt":
|
||||
salt = ''.join(Random().sample(string.letters + string.digits, 2))
|
||||
return crypt.crypt(password, salt)
|
||||
if scheme == "md5":
|
||||
return hashlib.md5(password).hexdigest()
|
||||
obj = hashlib.md5(password)
|
||||
return obj.hexdigest() if hexdigest else obj.digest()
|
||||
return password
|
||||
|
||||
@@ -4,6 +4,7 @@ from modoboa.auth.lib import _check_password
|
||||
from django.contrib.auth.models import check_password
|
||||
from django.utils.translation import ugettext as _, ugettext_noop
|
||||
from modoboa.lib.emailutils import split_mailbox
|
||||
from modoboa.lib import parameters
|
||||
|
||||
class BadDestination(Exception):
|
||||
pass
|
||||
@@ -21,6 +22,9 @@ class ChangePasswordForm(forms.Form):
|
||||
self.target = target
|
||||
|
||||
def clean_oldpassword(self):
|
||||
if parameters.get_admin("AUTHENTICATION_TYPE", app="admin") != "local":
|
||||
return self.cleaned_data["oldpassword"]
|
||||
|
||||
if not isinstance(self.target, Mailbox):
|
||||
func = check_password
|
||||
else:
|
||||
|
||||
+12
-7
@@ -8,9 +8,9 @@ from django.utils.translation import ugettext as _
|
||||
from modoboa.lib import parameters, events
|
||||
from modoboa.lib.webutils import _render, _render_error, ajax_response
|
||||
from forms import *
|
||||
from modoboa.admin.models import Mailbox, Alias
|
||||
from modoboa.admin.models import Mailbox, Alias, AdminError
|
||||
from modoboa.admin.lib import is_domain_admin
|
||||
from modoboa.auth.lib import encrypt, crypt_password
|
||||
from modoboa.auth.lib import encrypt
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
@@ -31,13 +31,18 @@ def changepassword(request, tplname="userprefs/chpassword.html"):
|
||||
if request.method == "POST":
|
||||
form = ChangePasswordForm(target, request.POST)
|
||||
if form.is_valid():
|
||||
if request.user.id != 1:
|
||||
target.password = crypt_password(request.POST["confirmation"])
|
||||
if request.user.id != 1:
|
||||
try:
|
||||
target.set_password(form.cleaned_data["oldpassword"],
|
||||
form.cleaned_data["confirmation"])
|
||||
except AdminError, e:
|
||||
error = str(e)
|
||||
request.session["password"] = encrypt(request.POST["confirmation"])
|
||||
else:
|
||||
target.set_password(request.POST["confirmation"])
|
||||
request.session["password"] = encrypt(request.POST["confirmation"])
|
||||
target.save()
|
||||
return ajax_response(request, respmsg=_("Password changed"))
|
||||
|
||||
if error is None:
|
||||
return ajax_response(request, respmsg=_("Password changed"))
|
||||
return ajax_response(request, status="ko", template=tplname,
|
||||
form=form, error=error)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user