96 lines
2.3 KiB
Python
96 lines
2.3 KiB
Python
|
|
# retoor <retoor@molodetz.nl>
|
||
|
|
|
||
|
|
import time
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from devplacepy.services.tunnel.ssh_auth import authenticate_user, _cache, _load_cache, _save_cache
|
||
|
|
|
||
|
|
|
||
|
|
def _clear_cache():
|
||
|
|
_cache.clear()
|
||
|
|
|
||
|
|
|
||
|
|
def test_auth_cache_hits_valid(local_db):
|
||
|
|
_clear_cache()
|
||
|
|
key = "test-user:valid-pass"
|
||
|
|
future = time.time() + 300
|
||
|
|
_cache[key] = (future, True)
|
||
|
|
_save_cache()
|
||
|
|
|
||
|
|
_load_cache()
|
||
|
|
assert key in _cache
|
||
|
|
expires_at, valid = _cache[key]
|
||
|
|
assert valid is True
|
||
|
|
assert expires_at > time.time()
|
||
|
|
|
||
|
|
|
||
|
|
def test_auth_cache_expired_entry_removed(local_db):
|
||
|
|
_clear_cache()
|
||
|
|
key = "test-user:expired-pass"
|
||
|
|
past = time.time() - 10
|
||
|
|
_cache[key] = (past, True)
|
||
|
|
_save_cache()
|
||
|
|
|
||
|
|
_load_cache()
|
||
|
|
assert key not in _cache
|
||
|
|
|
||
|
|
|
||
|
|
def test_auth_cache_invalid_rejected(local_db):
|
||
|
|
_clear_cache()
|
||
|
|
key = "test-user:wrong-pass"
|
||
|
|
future = time.time() + 300
|
||
|
|
_cache[key] = (future, False)
|
||
|
|
_save_cache()
|
||
|
|
|
||
|
|
_load_cache()
|
||
|
|
assert key in _cache
|
||
|
|
_, valid = _cache[key]
|
||
|
|
assert valid is False
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_authenticate_user_invalid_credentials(local_db):
|
||
|
|
_clear_cache()
|
||
|
|
|
||
|
|
with patch("devplacepy.services.tunnel.ssh_auth.TUNNEL_AUTH_API_URL", "http://localhost:99999/api/tunnel/auth-check"):
|
||
|
|
result = await authenticate_user("nobody", "wrong-password")
|
||
|
|
assert result is False
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_authenticate_user_wrong_password_delays(local_db):
|
||
|
|
_clear_cache()
|
||
|
|
|
||
|
|
with patch("devplacepy.services.tunnel.ssh_auth.TUNNEL_AUTH_API_URL", "http://localhost:99999/api/tunnel/auth-check"):
|
||
|
|
start = time.time()
|
||
|
|
result = await authenticate_user("alice", "wrong-password")
|
||
|
|
elapsed = time.time() - start
|
||
|
|
assert result is False
|
||
|
|
assert elapsed >= 3.0, "Wrong password response must delay at least 3 seconds"
|
||
|
|
|
||
|
|
|
||
|
|
def test_cache_persistence(local_db):
|
||
|
|
_clear_cache()
|
||
|
|
key = "persist-user:pass123"
|
||
|
|
future = time.time() + 300
|
||
|
|
_cache[key] = (future, True)
|
||
|
|
_save_cache()
|
||
|
|
|
||
|
|
_cache.clear()
|
||
|
|
_load_cache()
|
||
|
|
if key in _cache:
|
||
|
|
_, valid = _cache[key]
|
||
|
|
assert valid is True
|
||
|
|
else:
|
||
|
|
assert key not in _cache
|
||
|
|
|
||
|
|
|
||
|
|
def test_cache_ttl_enforced(local_db):
|
||
|
|
_clear_cache()
|
||
|
|
key = "ttl-user:pass456"
|
||
|
|
past = time.time() - 1
|
||
|
|
_cache[key] = (past, True)
|
||
|
|
assert _cache[key][0] < time.time()
|