""" Tests for authentication module """ import pytest import json from app import db from app.models import User @pytest.fixture def test_user(app): """Create a test user""" with app.app_context(): user = User( username='testuser', email='test@example.com', role='user' ) user.set_password('testpassword123') db.session.add(user) db.session.commit() # Return user data (not the object, as it will be detached) return { 'id': user.id, 'username': user.username, 'email': user.email, 'role': user.role } @pytest.fixture def admin_user(app): """Create an admin user""" with app.app_context(): user = User( username='adminuser', email='admin@example.com', role='admin' ) user.set_password('adminpassword123') db.session.add(user) db.session.commit() return { 'id': user.id, 'username': user.username, 'email': user.email, 'role': user.role } class TestLogin: """Tests for login endpoint""" def test_login_success(self, client, test_user): """Test successful login""" response = client.post('/api/auth/login', data=json.dumps({ 'username': 'testuser', 'password': 'testpassword123' }), content_type='application/json' ) assert response.status_code == 200 data = json.loads(response.data) assert 'token' in data assert 'refresh_token' in data assert 'user' in data assert data['user']['username'] == 'testuser' def test_login_invalid_password(self, client, test_user): """Test login with invalid password""" response = client.post('/api/auth/login', data=json.dumps({ 'username': 'testuser', 'password': 'wrongpassword' }), content_type='application/json' ) assert response.status_code == 401 data = json.loads(response.data) assert 'error' in data def test_login_missing_fields(self, client): """Test login with missing fields""" response = client.post('/api/auth/login', data=json.dumps({ 'username': 'testuser' }), content_type='application/json' ) assert response.status_code == 400 data = json.loads(response.data) assert 'error' in data class TestGetCurrentUser: """Tests for get current user endpoint""" def test_get_current_user_success(self, client, test_user): """Test getting current user with valid token""" # First login to get token login_response = client.post('/api/auth/login', data=json.dumps({ 'username': 'testuser', 'password': 'testpassword123' }), content_type='application/json' ) token = json.loads(login_response.data)['token'] # Get current user response = client.get('/api/auth/me', headers={'Authorization': f'Bearer {token}'} ) assert response.status_code == 200 data = json.loads(response.data) assert data['username'] == 'testuser' def test_get_current_user_no_token(self, client): """Test getting current user without token""" response = client.get('/api/auth/me') assert response.status_code == 401 class TestRefreshToken: """Tests for token refresh endpoint""" def test_refresh_token_success(self, client, test_user): """Test successful token refresh""" # First login to get tokens login_response = client.post('/api/auth/login', data=json.dumps({ 'username': 'testuser', 'password': 'testpassword123' }), content_type='application/json' ) refresh_token = json.loads(login_response.data)['refresh_token'] # Refresh token response = client.post('/api/auth/refresh', data=json.dumps({ 'refresh_token': refresh_token }), content_type='application/json' ) assert response.status_code == 200 data = json.loads(response.data) assert 'access_token' in data def test_refresh_token_invalid(self, client): """Test refresh with invalid token""" response = client.post('/api/auth/refresh', data=json.dumps({ 'refresh_token': 'invalid_token' }), content_type='application/json' ) assert response.status_code == 401 class TestLogout: """Tests for logout endpoint""" def test_logout_success(self, client, test_user): """Test successful logout""" # First login to get token login_response = client.post('/api/auth/login', data=json.dumps({ 'username': 'testuser', 'password': 'testpassword123' }), content_type='application/json' ) token = json.loads(login_response.data)['token'] # Logout response = client.post('/api/auth/logout', headers={'Authorization': f'Bearer {token}'} ) assert response.status_code == 200 @pytest.fixture def power_user(app): """Create a power user""" with app.app_context(): user = User( username='poweruser', email='power@example.com', role='power_user' ) user.set_password('powerpassword123') db.session.add(user) db.session.commit() return { 'id': user.id, 'username': user.username, 'email': user.email, 'role': user.role } class TestRBAC: """Tests for role-based access control""" def test_admin_access(self, client, admin_user): """Test admin can access admin-only endpoints""" # Login as admin login_response = client.post('/api/auth/login', data=json.dumps({ 'username': 'adminuser', 'password': 'adminpassword123' }), content_type='application/json' ) token = json.loads(login_response.data)['token'] # Admin should be able to access user list (admin endpoint) response = client.get('/api/users', headers={'Authorization': f'Bearer {token}'} ) # Should not return 403 (may return 200 or other status depending on implementation) assert response.status_code != 403 def test_regular_user_denied_admin_access(self, client, test_user): """Test regular user cannot access admin-only endpoints""" # Login as regular user login_response = client.post('/api/auth/login', data=json.dumps({ 'username': 'testuser', 'password': 'testpassword123' }), content_type='application/json' ) token = json.loads(login_response.data)['token'] # Regular user should be denied access to admin endpoints response = client.get('/api/users', headers={'Authorization': f'Bearer {token}'} ) assert response.status_code == 403 def test_power_user_access(self, client, power_user): """Test power user can access power_user endpoints""" # Login as power user login_response = client.post('/api/auth/login', data=json.dumps({ 'username': 'poweruser', 'password': 'powerpassword123' }), content_type='application/json' ) token = json.loads(login_response.data)['token'] # Power user should be able to access credentials list response = client.get('/api/credentials', headers={'Authorization': f'Bearer {token}'} ) # Should not return 403 assert response.status_code != 403