mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-27 06:18:43 +01:00
wip: Resellers and limits (see #105)
* Added support for migrations * Big refactoring of the admin code done: Support for SHA256 algorithm to store passwords (fix #195) done: admin models refactoring (fix #196)
This commit is contained in:
+32
-8
@@ -1,6 +1,4 @@
|
||||
from django.contrib.auth.models import User
|
||||
from modoboa.admin.models import Mailbox
|
||||
from modoboa.auth.lib import _check_password
|
||||
from modoboa.admin.models import User
|
||||
|
||||
class SimpleBackend:
|
||||
|
||||
@@ -13,11 +11,7 @@ class SimpleBackend:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
try:
|
||||
mb = user.mailbox_set.all()[0]
|
||||
except Exception:
|
||||
return None
|
||||
if not _check_password(password, mb.password):
|
||||
if not user.check_password(password):
|
||||
return None
|
||||
return user
|
||||
|
||||
@@ -27,3 +21,33 @@ class SimpleBackend:
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
try:
|
||||
from django_auth_ldap.backend import LDAPBackend as orig_LDAPBackend, _LDAPUser
|
||||
from modoboa.admin.models import User
|
||||
|
||||
class LDAPBackend(orig_LDAPBackend):
|
||||
|
||||
def get_or_create_user(self, username, ldap_user):
|
||||
"""
|
||||
This must return a (User, created) 2-tuple for the given LDAP user.
|
||||
username is the Django-friendly username of the user. ldap_user.dn is
|
||||
the user's DN and ldap_user.attrs contains all of their LDAP attributes.
|
||||
"""
|
||||
return User.objects.get_or_create(
|
||||
username__iexact=username,
|
||||
defaults={'username': username.lower()}
|
||||
)
|
||||
|
||||
def get_user(self, user_id):
|
||||
user = None
|
||||
|
||||
try:
|
||||
user = User.objects.get(pk=user_id)
|
||||
_LDAPUser(self, user=user) # This sets user.ldap_user
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
|
||||
return user
|
||||
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
:mod:`decorators` --- common decorators
|
||||
---------------------------------------
|
||||
"""
|
||||
from functools import wraps
|
||||
from exceptions import NeedsMailboxException
|
||||
|
||||
def needs_mailbox():
|
||||
"""Check if the current user owns at least one mailbox
|
||||
|
||||
Some applications (the webmail for example) need a mailbox to
|
||||
work.
|
||||
"""
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def wrapped_f(request, *args, **kwargs):
|
||||
if request.user.has_mailbox:
|
||||
return f(request, *args, **kwargs)
|
||||
raise NeedsMailboxException()
|
||||
return wrapped_f
|
||||
return decorator
|
||||
+5
-3
@@ -13,6 +13,8 @@ import inspect
|
||||
import re
|
||||
|
||||
events = [
|
||||
"SuperAdminPromotion",
|
||||
|
||||
"CanCreateDomain",
|
||||
"CreateDomain",
|
||||
"DeleteDomain",
|
||||
@@ -87,8 +89,8 @@ class observe(object):
|
||||
|
||||
:param evtname: the event's name
|
||||
"""
|
||||
def __init__(self, evtname):
|
||||
self.evtname = evtname
|
||||
def __init__(self, *evtnames):
|
||||
self.evtnames = evtnames
|
||||
|
||||
def __guess_extension_name(self, modname):
|
||||
if modname.startswith('modoboa.extensions'):
|
||||
@@ -112,7 +114,7 @@ class observe(object):
|
||||
return []
|
||||
return f(*args)
|
||||
|
||||
register(self.evtname, wrapped_f)
|
||||
map(lambda evt: register(evt, wrapped_f), self.evtnames)
|
||||
return wrapped_f
|
||||
|
||||
def unregister(event, callback):
|
||||
|
||||
@@ -16,3 +16,6 @@ class PermDeniedException(ModoboaException):
|
||||
def __str__(self):
|
||||
return _("Permission denied: %s" % self.msg)
|
||||
|
||||
class NeedsMailboxException(ModoboaException):
|
||||
pass
|
||||
|
||||
|
||||
+15
-7
@@ -36,9 +36,9 @@ Extracted from `this blog
|
||||
import sys
|
||||
import ldap
|
||||
import re
|
||||
import base64
|
||||
import base64, hashlib, string, crypt
|
||||
from random import Random
|
||||
from django.conf import settings
|
||||
from modoboa.auth.lib import crypt_password
|
||||
from modoboa.lib import parameters
|
||||
|
||||
class LDAPException(Exception): pass
|
||||
@@ -81,7 +81,7 @@ class LDAPAuthBackend(object):
|
||||
return None
|
||||
return dn
|
||||
|
||||
def _crypt_password(self, clearpassword):
|
||||
def _crypt_password(self, user, clearpassword):
|
||||
"""Overidding of the crypt_password function (LDAP compliant)
|
||||
|
||||
The crypted password in base64 encoded and we prepend the used
|
||||
@@ -91,10 +91,18 @@ class LDAPAuthBackend(object):
|
||||
:return: the encrypted password
|
||||
"""
|
||||
scheme = parameters.get_admin("PASSWORD_SCHEME", app="admin")
|
||||
if scheme == "clear":
|
||||
if scheme == "crypt":
|
||||
salt = ''.join(Random().sample(string.letters + string.digits, 2))
|
||||
result = crypt.crypt(clearpassword, salt)
|
||||
elif scheme == "md5":
|
||||
obj = hashlib.md5(clearpassword)
|
||||
result = obj.digest()
|
||||
elif scheme == "sha256":
|
||||
obj = hashlib.sha256(clearpassword)
|
||||
result = obj.digest()
|
||||
else:
|
||||
return str(clearpassword)
|
||||
crypted = crypt_password(clearpassword, False)
|
||||
return str("{%s}%s" % (scheme.upper(), base64.encodestring(crypted)))
|
||||
return str("{%s}%s" % (scheme.upper(), base64.b64encode(result)))
|
||||
|
||||
def update_user_password(self, user, password, newpassword):
|
||||
try:
|
||||
@@ -104,7 +112,7 @@ class LDAPAuthBackend(object):
|
||||
newpassword = ('"%s"' % newpassword).encode('utf-16').lstrip('\377\376')
|
||||
ldif = [(ldap.MOD_REPLACE,
|
||||
self.pwd_attr,
|
||||
self._crypt_password(newpassword))]
|
||||
self._crypt_password(user, newpassword))]
|
||||
conn.modify_s(dn, ldif)
|
||||
except ldap.LDAPError, e:
|
||||
raise LDAPException(str(e))
|
||||
|
||||
+1
-2
@@ -155,7 +155,6 @@ def topredirection(request):
|
||||
"""
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.extensions import get_extension_infos
|
||||
from modoboa.admin.lib import is_domain_admin
|
||||
|
||||
topredir = parameters.get_admin("DEFAULT_TOP_REDIRECTION", app="general")
|
||||
if not topredir in ["admin", "userprefs"]:
|
||||
@@ -165,7 +164,7 @@ def topredirection(request):
|
||||
path = topredir
|
||||
|
||||
if topredir in ["admin", "stats"] and \
|
||||
(not request.user.is_superuser and not is_domain_admin(request.user)):
|
||||
request.user.belongs_to_group('SimpleUsers'):
|
||||
path = "userprefs"
|
||||
|
||||
return HttpResponseRedirect(path)
|
||||
|
||||
Reference in New Issue
Block a user