56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
"""Admin panel — CSRF protection on mutation endpoints.
|
|
|
|
ADMIN-005. Every admin POST route must reject requests that lack a valid
|
|
CSRF token. These tests use the app_with_csrf fixture where CSRF is
|
|
enabled, unlike the default app fixture which disables it.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
ADMIN_POST_ROUTES = [
|
|
'/admin/backup/create',
|
|
'/admin/toggle-tryouts',
|
|
'/admin/season/start',
|
|
'/admin/season/end',
|
|
'/admin/teams/wipe',
|
|
]
|
|
|
|
|
|
class TestAdminCsrfProtection:
|
|
@pytest.mark.parametrize('route', ADMIN_POST_ROUTES)
|
|
def test_post_without_csrf_is_rejected(self, app_with_csrf, route):
|
|
"""Every admin POST route must reject a missing CSRF token."""
|
|
# as_role uses the default app fixture, so we log in manually
|
|
# with the csrf-enabled app.
|
|
from app.extensions import db as _db
|
|
from app.models import User
|
|
|
|
client = app_with_csrf.test_client()
|
|
|
|
# Create and log in an admin on the CSRF-enabled app
|
|
with app_with_csrf.app_context():
|
|
from app.extensions import hash_password
|
|
from app.models import Admin
|
|
|
|
admin = Admin(
|
|
username='csrfadmin',
|
|
password_hash=hash_password('Password123'),
|
|
role='admin',
|
|
full_name='CSRF Admin',
|
|
email='[email protected]',
|
|
)
|
|
_db.session.add(admin)
|
|
_db.session.commit()
|
|
|
|
client.post(
|
|
'/auth/login',
|
|
data={'username': 'csrfadmin', 'password': 'Password123'},
|
|
follow_redirects=False,
|
|
)
|
|
|
|
response = client.post(route, data={}, follow_redirects=False)
|
|
# Flask-WTF returns 400 on missing CSRF token
|
|
assert response.status_code in (400, 302), (
|
|
f'{route} returned {response.status_code} without CSRF token'
|
|
) |