Add user authentication system

- Implement secure user registration and login
- Add password hashing with PBKDF2 and random salts
- Create session-based authentication with secure tokens
- Support user deactivation and session management
- Include comprehensive unit tests for authentication
- Integrate authentication demo into main application

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Alexander Domene
2025-08-25 20:40:05 +02:00
parent 1f786a83ce
commit 31c42ca7ae
3 changed files with 283 additions and 0 deletions

141
tests/unit/test_auth.py Normal file
View File

@@ -0,0 +1,141 @@
import pytest
import sys
import os
import time
# Add src directory to path for imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'src'))
from auth import UserManager, AuthenticationError, User
class TestUserManager:
def setup_method(self):
"""Setup test fixtures"""
self.user_manager = UserManager()
def test_register_user_success(self):
"""Test successful user registration"""
result = self.user_manager.register_user("testuser", "test@example.com", "password123")
assert result is True
assert "testuser" in self.user_manager.users
user = self.user_manager.users["testuser"]
assert user.username == "testuser"
assert user.email == "test@example.com"
assert user.is_active is True
assert user.created_at is not None
def test_register_duplicate_username(self):
"""Test registration with duplicate username"""
self.user_manager.register_user("testuser", "test1@example.com", "password123")
with pytest.raises(ValueError, match="Username already exists"):
self.user_manager.register_user("testuser", "test2@example.com", "password456")
def test_register_weak_password(self):
"""Test registration with weak password"""
with pytest.raises(ValueError, match="Password must be at least 8 characters long"):
self.user_manager.register_user("testuser", "test@example.com", "123")
def test_authenticate_success(self):
"""Test successful authentication"""
self.user_manager.register_user("testuser", "test@example.com", "password123")
session_token = self.user_manager.authenticate("testuser", "password123")
assert session_token is not None
assert len(session_token) > 0
assert session_token in self.user_manager.sessions
assert self.user_manager.sessions[session_token] == "testuser"
def test_authenticate_invalid_username(self):
"""Test authentication with invalid username"""
with pytest.raises(AuthenticationError, match="Invalid username or password"):
self.user_manager.authenticate("nonexistent", "password123")
def test_authenticate_invalid_password(self):
"""Test authentication with invalid password"""
self.user_manager.register_user("testuser", "test@example.com", "password123")
with pytest.raises(AuthenticationError, match="Invalid username or password"):
self.user_manager.authenticate("testuser", "wrongpassword")
def test_authenticate_deactivated_user(self):
"""Test authentication with deactivated user"""
self.user_manager.register_user("testuser", "test@example.com", "password123")
self.user_manager.deactivate_user("testuser")
with pytest.raises(AuthenticationError, match="Account is deactivated"):
self.user_manager.authenticate("testuser", "password123")
def test_validate_session_success(self):
"""Test successful session validation"""
self.user_manager.register_user("testuser", "test@example.com", "password123")
session_token = self.user_manager.authenticate("testuser", "password123")
username = self.user_manager.validate_session(session_token)
assert username == "testuser"
def test_validate_session_invalid_token(self):
"""Test session validation with invalid token"""
username = self.user_manager.validate_session("invalid_token")
assert username is None
def test_logout_success(self):
"""Test successful logout"""
self.user_manager.register_user("testuser", "test@example.com", "password123")
session_token = self.user_manager.authenticate("testuser", "password123")
result = self.user_manager.logout(session_token)
assert result is True
assert session_token not in self.user_manager.sessions
def test_logout_invalid_token(self):
"""Test logout with invalid token"""
result = self.user_manager.logout("invalid_token")
assert result is False
def test_get_user_success(self):
"""Test getting user information"""
self.user_manager.register_user("testuser", "test@example.com", "password123")
user = self.user_manager.get_user("testuser")
assert user is not None
assert user.username == "testuser"
assert user.email == "test@example.com"
def test_get_user_nonexistent(self):
"""Test getting nonexistent user"""
user = self.user_manager.get_user("nonexistent")
assert user is None
def test_deactivate_user_success(self):
"""Test successful user deactivation"""
self.user_manager.register_user("testuser", "test@example.com", "password123")
session_token = self.user_manager.authenticate("testuser", "password123")
result = self.user_manager.deactivate_user("testuser")
assert result is True
assert self.user_manager.users["testuser"].is_active is False
assert session_token not in self.user_manager.sessions
def test_deactivate_user_nonexistent(self):
"""Test deactivating nonexistent user"""
result = self.user_manager.deactivate_user("nonexistent")
assert result is False
def test_password_hashing_security(self):
"""Test that passwords are properly hashed and salted"""
self.user_manager.register_user("user1", "user1@example.com", "password123")
self.user_manager.register_user("user2", "user2@example.com", "password123")
user1 = self.user_manager.users["user1"]
user2 = self.user_manager.users["user2"]
# Same password should have different hashes due to different salts
assert user1.password_hash != user2.password_hash
# Password hash should contain salt and hash separated by colon
assert ":" in user1.password_hash
assert ":" in user2.password_hash