Added NTLM auth to email client settings

This commit is contained in:
Daniel Schick 2026-01-13 07:01:15 +01:00
parent 62c13eb17a
commit 77959b4a50
2 changed files with 34 additions and 1 deletions

View File

@ -35,3 +35,4 @@ typing_extensions==4.12.2
tzdata==2024.1 tzdata==2024.1
webargs==8.6.0 webargs==8.6.0
Werkzeug==3.0.4 Werkzeug==3.0.4
ntlm-auth==1.5.0

View File

@ -3,6 +3,7 @@ import pydapper
import smtplib import smtplib
import json import json
import os import os
import base64
from email.message import EmailMessage from email.message import EmailMessage
from BreCal.schemas import model, defs from BreCal.schemas import model, defs
@ -110,8 +111,33 @@ def SendEmails(email_dict):
pooledConnection = getPoolConnection() pooledConnection = getPoolConnection()
commands = pydapper.using(pooledConnection) commands = pydapper.using(pooledConnection)
def _parse_bool(value) -> bool:
if isinstance(value, bool):
return value
if value is None:
return False
return str(value).strip().lower() in ("1", "true", "yes", "y", "on")
def _smtp_auth_ntlm(connection, username: str, password: str, domain: str | None = None, workstation: str | None = None):
try:
from ntlm_auth.ntlm import NtlmContext
except Exception as exc:
raise RuntimeError("NTLM auth requested but ntlm-auth is not installed") from exc
context = NtlmContext(username, password, domain=domain, workstation=workstation)
negotiate = context.step()
code, challenge = connection.docmd("AUTH", "NTLM " + base64.b64encode(negotiate).decode("ascii"))
if code != 334:
raise smtplib.SMTPException(f"NTLM negotiate failed: {code} {challenge}")
challenge_bytes = base64.b64decode(challenge.strip())
authenticate = context.step(challenge_bytes)
code, msg = connection.docmd(base64.b64encode(authenticate).decode("ascii"))
if code != 235:
raise smtplib.SMTPAuthenticationError(code, msg)
encryption = defs.email_credentials.get("encryption") or defs.email_credentials.get("encryption_method") or "STARTTLS" encryption = defs.email_credentials.get("encryption") or defs.email_credentials.get("encryption_method") or "STARTTLS"
encryption_norm = str(encryption).strip().upper().replace(" ", "").replace("_", "").replace("-", "") encryption_norm = str(encryption).strip().upper().replace(" ", "").replace("_", "").replace("-", "")
use_ntlm_auth = _parse_bool(defs.email_credentials.get("USE_NTLM_AUTH"))
if encryption_norm in ("SSLTLS", "SSL", "TLS"): if encryption_norm in ("SSLTLS", "SSL", "TLS"):
conn = smtplib.SMTP_SSL(defs.email_credentials["server"], defs.email_credentials["port"]) conn = smtplib.SMTP_SSL(defs.email_credentials["server"], defs.email_credentials["port"])
else: else:
@ -127,6 +153,12 @@ def SendEmails(email_dict):
logging.warning("Unknown email encryption '%s'; defaulting to STARTTLS.", encryption) logging.warning("Unknown email encryption '%s'; defaulting to STARTTLS.", encryption)
conn.starttls() conn.starttls()
conn.ehlo() conn.ehlo()
if use_ntlm_auth:
ntlm_user = defs.email_credentials.get("ntlm_user") or defs.email_credentials["sender"]
ntlm_domain = defs.email_credentials.get("ntlm_domain")
ntlm_workstation = defs.email_credentials.get("ntlm_workstation")
_smtp_auth_ntlm(conn, ntlm_user, defs.email_credentials["password_send"], domain=ntlm_domain, workstation=ntlm_workstation)
else:
conn.login(defs.email_credentials["sender"], defs.email_credentials["password_send"]) conn.login(defs.email_credentials["sender"], defs.email_credentials["password_send"])
current_path = os.path.dirname(os.path.abspath(__file__)) current_path = os.path.dirname(os.path.abspath(__file__))