agnes-the-ai-analyst/tests/test_email_auth.py
Petr e2ab219171 Add email magic link authentication provider
New pluggable auth provider that sends passwordless sign-in links.
Works with domain restriction (same as Google OAuth). Falls back to
showing the link in browser when SMTP is not configured (dev mode).
2026-03-10 10:39:19 +01:00

95 lines
3.4 KiB
Python

"""Tests for the email magic link authentication provider."""
import pytest
from auth.email.provider import (
EmailAuthProvider,
_generate_magic_token,
_verify_magic_token,
)
# ---------------------------------------------------------------------------
# Token tests
# ---------------------------------------------------------------------------
class TestMagicTokens:
"""Test magic link token generation and verification."""
@pytest.fixture(autouse=True)
def setup_env(self, monkeypatch):
"""Set required env vars for Config."""
monkeypatch.setenv("WEBAPP_SECRET_KEY", "test-secret-key-for-tokens")
def test_generate_and_verify_token(self):
"""Valid token should return the email."""
token = _generate_magic_token("user@acme.com")
email = _verify_magic_token(token, max_age_seconds=60)
assert email == "user@acme.com"
def test_token_normalizes_email(self):
"""Email should be lowercased in the token."""
token = _generate_magic_token("User@ACME.com")
email = _verify_magic_token(token, max_age_seconds=60)
assert email == "user@acme.com"
def test_expired_token_returns_none(self):
"""Expired token should return None."""
import time
token = _generate_magic_token("user@acme.com")
time.sleep(2)
email = _verify_magic_token(token, max_age_seconds=1)
assert email is None
def test_invalid_token_returns_none(self):
"""Tampered token should return None."""
email = _verify_magic_token("not-a-valid-token", max_age_seconds=60)
assert email is None
def test_empty_token_returns_none(self):
"""Empty token should return None."""
email = _verify_magic_token("", max_age_seconds=60)
assert email is None
# ---------------------------------------------------------------------------
# Provider tests
# ---------------------------------------------------------------------------
class TestEmailAuthProvider:
"""Test the EmailAuthProvider class."""
@pytest.fixture(autouse=True)
def setup_env(self, monkeypatch):
"""Set required env vars."""
monkeypatch.setenv("WEBAPP_SECRET_KEY", "test-secret")
def test_provider_name(self):
provider = EmailAuthProvider()
assert provider.get_name() == "email"
def test_provider_display_name(self):
provider = EmailAuthProvider()
assert provider.get_display_name() == "Email"
def test_login_button_properties(self, monkeypatch):
# Reload config with allowed domain set
monkeypatch.setattr("webapp.config.Config.ALLOWED_DOMAIN", "acme.com")
provider = EmailAuthProvider()
button = provider.get_login_button()
assert button["text"] == "Sign in with Email"
assert button["url"] == "/login/email"
assert button["visible"] is True
assert button["order"] == 20
assert "btn-email" in button["css_class"]
assert "acme.com" in button["subtitle"]
def test_provider_available_with_domain(self, monkeypatch):
monkeypatch.setattr("webapp.config.Config.ALLOWED_DOMAIN", "acme.com")
provider = EmailAuthProvider()
assert provider.is_available() is True
def test_provider_unavailable_without_domain(self, monkeypatch):
monkeypatch.setattr("webapp.config.Config.ALLOWED_DOMAIN", "")
provider = EmailAuthProvider()
assert provider.is_available() is False