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 ", 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)