Browse Source

Ещё больше асинхронности, "моя прелесть (ц)"

tags/1.0.0
Бородин Роман 2 months ago
parent
commit
ddb3bc487d
3 changed files with 40 additions and 31 deletions
  1. +25
    -16
      dovecot_checkpassword.py
  2. +13
    -13
      mbkmail/ldap.py
  3. +2
    -2
      mbkmail/smtp/auth.py

+ 25
- 16
dovecot_checkpassword.py View File

@@ -1,5 +1,12 @@
#!/usr/bin/env python3

import asyncio
uvloop_exist = False
try:
import uvloop
uvloop_exist = True
except ImportError:
pass
import os, sys
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
from mbkmail import ldap
@@ -10,40 +17,40 @@ ERR_LOOKUP_OK=2
ERR_NOUSER=3
ERR_TEMPFAIL=111

def credentials_lookup(username, none_password, scheme='PLAIN'):
async def credentials_lookup(username, none_password, scheme='PLAIN'):
return False # FIXME: Не реализовано

def user_lookup(username, password, scheme='PLAIN'):
async def user_lookup(username, password, scheme='PLAIN'):
u = ldap.UserDB()
if os.environ.get('AUTH_LOGIN_USER', None) and os.environ.get('AUTH_LOGIN_USER', None) != os.environ.get('AUTH_ORIG_USER', None): # Masteruser login
user = u.user_by_email(os.environ['AUTH_LOGIN_USER'])
user = await u.user_by_email(os.environ['AUTH_LOGIN_USER'])
if user:
uq = u.user_quota_mb(os.environ['AUTH_LOGIN_USER'])
ugroups = u.user_groups(os.environ['AUTH_LOGIN_USER'])
uq = await u.user_quota_mb(os.environ['AUTH_LOGIN_USER'])
ugroups = await u.user_groups(os.environ['AUTH_LOGIN_USER'])
return (os.environ['AUTH_LOGIN_USER'], password, scheme, uq, ugroups)
else:
return False
else:
user = u.user_by_email(username)
user = await u.user_by_email(username)
if user:
uq = u.user_quota_mb(username)
ugroups = u.user_groups(username)
uq = await u.user_quota_mb(username)
ugroups = await u.user_groups(username)
return (username, password, scheme, uq, ugroups)
else:
return False

def credentials_verify(username, password, scheme):
async def credentials_verify(username, password, scheme):
u = ldap.UserDB()
if os.environ.get('AUTH_LOGIN_USER', None) and os.environ.get('AUTH_LOGIN_USER', None) != os.environ.get('AUTH_ORIG_USER', None): # Masteruser login
if u.check_auth(os.environ['AUTH_ORIG_USER'], password, master=True):
uq = u.user_quota_mb(os.environ['AUTH_LOGIN_USER'])
ugroups = u.user_groups(os.environ['AUTH_LOGIN_USER'])
if await u.check_auth(os.environ['AUTH_ORIG_USER'], password, master=True):
uq = await u.user_quota_mb(os.environ['AUTH_LOGIN_USER'])
ugroups = await u.user_groups(os.environ['AUTH_LOGIN_USER'])
return (os.environ['AUTH_LOGIN_USER'], password, scheme, uq, ugroups)
else:
return False
if u.check_auth(username, password):
uq = u.user_quota_mb(username)
ugroups = u.user_groups(username)
if await u.check_auth(username, password):
uq = await u.user_quota_mb(username)
ugroups = await u.user_groups(username)
return (username, password, scheme, uq, ugroups)
else:
return False
@@ -79,7 +86,9 @@ if __name__ == '__main__':
else:
action = credentials_verify
try:
lookup_result = action(username, password, os.getenv('SCHEME', None))
if uvloop_exist:
uvloop.install()
lookup_result = asyncio.run(action(username, password, os.getenv('SCHEME', None)))
except:
print(sys.exc_info())
exit(ERR_TEMPFAIL)


+ 13
- 13
mbkmail/ldap.py View File

@@ -12,7 +12,7 @@ class UserDB:
c.conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
_ = c.conn.simple_bind_s(c.connect_binddn,c.connect_password)
self.l.append(c)
def check_rcpt_mail(self, email):
async def check_rcpt_mail(self, email):
res = []
email = email.decode('utf-8') if isinstance(email, bytes) else email
dom = email.split('@')[1].lower()
@@ -35,12 +35,12 @@ class UserDB:
return None

async def expand_alias(self, alias):
emails = self.find_group_members(alias)
emails.extend(self.find_alternate_address(alias))
emails.extend(self.find_redirects(alias))
emails = await self.find_group_members(alias)
emails.extend(await self.find_alternate_address(alias))
emails.extend(await self.find_redirects(alias))
return emails
def find_redirects(self, email):
async def find_redirects(self, email):
email = email.decode('utf-8') if isinstance(email, bytes) else email
if email.split('@')[1] not in cfg.local_domains + [cfg.system_domain]:
return []
@@ -71,7 +71,7 @@ class UserDB:
for m3 in m2:
d[m3.strip()] = True
return list(map(lambda x: x.decode('utf-8') if isinstance(x, bytes) else x, d.keys()))
def find_alternate_address(self, email):
async def find_alternate_address(self, email):
email = email.decode('utf-8') if isinstance(email, bytes) else email
if email.split('@')[1] not in cfg.local_domains + [cfg.system_domain]:
return []
@@ -96,7 +96,7 @@ class UserDB:
mail = att[util.ldap_attr(c.user_mail_attr, att)][0]
d[mail] = True
return list(map(lambda x: x.decode('utf-8') if isinstance(x, bytes) else x, d.keys()))
def find_group_members(self, email):
async def find_group_members(self, email):
email = email.decode('utf-8') if isinstance(email, bytes) else email
if email.split('@')[1] not in cfg.local_domains + [cfg.system_domain]:
return []
@@ -137,7 +137,7 @@ class UserDB:
continue
expand_group(c, email)
return list(map(lambda x: x.decode('utf-8') if isinstance(x, bytes) else x, gemails))
def user_by_email(self, email):
async def user_by_email(self, email):
u = []
email = email.decode('utf-8') if isinstance(email, bytes) else email
dom = email.split('@')[1].lower()
@@ -155,7 +155,7 @@ class UserDB:
return u[0]
else:
return None
def user_quota_mb(self, email):
async def user_quota_mb(self, email):
email = email.decode('utf-8') if isinstance(email, bytes) else email
dom = email.split('@')[1].lower()
quota = None
@@ -176,7 +176,7 @@ class UserDB:
continue
quota = uq
return quota
def user_groups(self, email):
async def user_groups(self, email):
email = email.decode('utf-8') if isinstance(email, bytes) else email
dom = email.split('@')[1].lower()
groups = set()
@@ -240,7 +240,7 @@ class UserDB:
g_name = g_name.decode('utf-8') if isinstance(g_name, bytes) else g_name
groups.add(g_name)
return list(groups)
def check_auth(self, email, password, master=False):
async def check_auth(self, email, password, master=False):
email = email.decode('utf-8') if isinstance(email, bytes) else email
password = password.decode('utf-8') if isinstance(password, bytes) else password
if email.split('@')[1] not in cfg.local_domains + [cfg.system_domain]:
@@ -283,14 +283,14 @@ class UserDB:
async def get_username_from_mail(lp, dom):
if dom != cfg.system_domain:
l = UserDB()
user = l.user_by_email('%s@%s' % (lp, dom)).lower()
user = await l.user_by_email('%s@%s' % (lp, dom)).lower()
else:
user = lp.lower()
return user
async def check_rcpt(lp, dom):
l = UserDB()
mail = '%s@%s' % (lp, dom)
real_mail = l.check_rcpt_mail(mail)
real_mail = await l.check_rcpt_mail(mail)
if real_mail is not None and real_mail.lower() == mail.lower():
return mail.lower()
else:


+ 2
- 2
mbkmail/smtp/auth.py View File

@@ -17,7 +17,7 @@ class SMTPAuth:
_, user, password = decoded.split(b'\x00')
user = user.decode('utf-8') if isinstance(user, bytes) else user
password = password.decode('utf-8') if isinstance(password, bytes) else password
if auth_func(user, password):
if await auth_func(user, password):
session.authenticated = True
session.auth_id = user
await send_msg(writer, '235 Authentication successful')
@@ -33,7 +33,7 @@ class SMTPAuth:
b64password = await readline(reader)
user = base64.b64decode(b64user.strip().decode('utf-8')).decode('utf-8')
password = base64.b64decode(b64password.strip().decode('utf-8'))
if auth_func(user, password):
if await auth_func(user, password):
session.authenticated = True
session.auth_id = user
await send_msg(writer, '235 Authentication successful')


Loading…
Cancel
Save