109 lines
3.5 KiB
Python
109 lines
3.5 KiB
Python
import base64
|
|
|
|
import pytest
|
|
from django.test import override_settings
|
|
|
|
from apps.core.services.microsoft365 import (
|
|
Microsoft365OAuthError,
|
|
acquire_exchange_access_token,
|
|
xoauth2_b64,
|
|
)
|
|
from apps.notifications.backends import Microsoft365OAuthEmailBackend
|
|
|
|
|
|
@override_settings(
|
|
M365_TENANT_ID="tenant-id",
|
|
M365_CLIENT_ID="client-id",
|
|
M365_CLIENT_SECRET="client-secret",
|
|
M365_EXCHANGE_SCOPE="https://outlook.office365.com/.default",
|
|
)
|
|
def test_app_only_token_uses_tenant_authority_and_exchange_scope():
|
|
calls = {}
|
|
|
|
class Client:
|
|
def acquire_token_for_client(self, *, scopes):
|
|
calls["scopes"] = scopes
|
|
return {"access_token": "access-token"}
|
|
|
|
def factory(client_id, *, authority, client_credential):
|
|
calls.update(
|
|
client_id=client_id,
|
|
authority=authority,
|
|
client_credential=client_credential,
|
|
)
|
|
return Client()
|
|
|
|
assert acquire_exchange_access_token(client_factory=factory) == "access-token"
|
|
assert calls == {
|
|
"client_id": "client-id",
|
|
"authority": "https://login.microsoftonline.com/tenant-id",
|
|
"client_credential": "client-secret",
|
|
"scopes": ["https://outlook.office365.com/.default"],
|
|
}
|
|
|
|
|
|
@override_settings(M365_TENANT_ID="", M365_CLIENT_ID="", M365_CLIENT_SECRET="")
|
|
def test_missing_oauth_configuration_fails_without_secret_material():
|
|
with pytest.raises(Microsoft365OAuthError, match="niet volledig") as error:
|
|
acquire_exchange_access_token()
|
|
assert "secret" not in str(error.value).lower()
|
|
|
|
|
|
def test_xoauth2_payload_is_encoded_exactly():
|
|
encoded = xoauth2_b64("mailbox@example.invalid", "token-value")
|
|
assert base64.b64decode(encoded) == (
|
|
b"user=mailbox@example.invalid\x01auth=Bearer token-value\x01\x01"
|
|
)
|
|
|
|
|
|
@override_settings(
|
|
M365_MAILBOX_USER="vacatureradar@example.invalid",
|
|
EMAIL_HOST="smtp.office365.com",
|
|
EMAIL_PORT=587,
|
|
DEFAULT_FROM_EMAIL="VacatureRadar <vacatureradar@example.invalid>",
|
|
M365_SMTP_TIMEOUT_SECONDS=10,
|
|
)
|
|
def test_oauth_smtp_backend_authenticates_and_sends(monkeypatch):
|
|
calls = []
|
|
|
|
class SMTP:
|
|
def __init__(self, host, port, *, timeout):
|
|
calls.append(("connect", host, port, timeout))
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *args):
|
|
return None
|
|
|
|
def ehlo(self):
|
|
calls.append(("ehlo",))
|
|
|
|
def starttls(self, *, context):
|
|
calls.append(("starttls", bool(context)))
|
|
|
|
def docmd(self, command, argument):
|
|
calls.append((command, argument))
|
|
return 235, b"ok"
|
|
|
|
def sendmail(self, sender, recipients, message):
|
|
calls.append(("sendmail", sender, recipients, message))
|
|
|
|
monkeypatch.setattr("apps.notifications.backends.smtplib.SMTP", SMTP)
|
|
monkeypatch.setattr(
|
|
"apps.notifications.backends.acquire_exchange_access_token",
|
|
lambda: "token-value",
|
|
)
|
|
from django.core.mail import EmailMessage as DjangoEmailMessage
|
|
|
|
django_message = DjangoEmailMessage(
|
|
subject="Test",
|
|
body="test",
|
|
from_email="vacatureradar@example.invalid",
|
|
to=["recipient@example.invalid"],
|
|
)
|
|
assert Microsoft365OAuthEmailBackend().send_messages([django_message]) == 1
|
|
assert calls[0] == ("connect", "smtp.office365.com", 587, 10)
|
|
assert any(call[0] == "AUTH" and call[1].startswith("XOAUTH2 ") for call in calls)
|
|
assert any(call[0] == "sendmail" for call in calls)
|