| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| from unittest.mock import MagicMock, patch |
| |
| from flask_appbuilder.security.sqla.models import Group, Role, User |
| |
| from superset.security.manager import ( |
| _log_audit_event, |
| SupersetGroupApi, |
| SupersetRoleApi, |
| SupersetSecurityManager, |
| SupersetUserApi, |
| ) |
| |
| |
| @patch("superset.extensions.event_logger") |
| @patch("superset.security.manager.get_user_id", return_value=1) |
| def test_log_audit_event_calls_event_logger( |
| mock_get_user_id: MagicMock, |
| mock_event_logger: MagicMock, |
| ) -> None: |
| """_log_audit_event delegates to the configured event_logger.""" |
| _log_audit_event("TestAction", {"key": "value"}) |
| |
| mock_event_logger.log.assert_called_once_with( |
| user_id=1, |
| action="TestAction", |
| dashboard_id=None, |
| duration_ms=None, |
| slice_id=None, |
| referrer=None, |
| curated_payload=None, |
| curated_form_data=None, |
| records=[{"key": "value"}], |
| ) |
| |
| |
| @patch("superset.extensions.event_logger") |
| @patch("superset.security.manager.get_user_id", return_value=1) |
| def test_log_audit_event_handles_logger_error( |
| mock_get_user_id: MagicMock, |
| mock_event_logger: MagicMock, |
| ) -> None: |
| """_log_audit_event does not raise on event_logger errors.""" |
| mock_event_logger.log.side_effect = Exception("Logger error") |
| # Should not raise |
| _log_audit_event("TestAction", {"key": "value"}) |
| |
| |
| # --- Role CRUD --- |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_role_api_post_add_logs_event(mock_log: MagicMock) -> None: |
| """SupersetRoleApi.post_add logs a RoleCreated event.""" |
| api = SupersetRoleApi.__new__(SupersetRoleApi) |
| role = MagicMock(spec=Role) |
| role.name = "TestRole" |
| role.id = 42 |
| api.post_add(role) |
| mock_log.assert_called_once_with( |
| "RoleCreated", {"role_name": "TestRole", "role_id": 42} |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_role_api_post_update_logs_event(mock_log: MagicMock) -> None: |
| """SupersetRoleApi.post_update logs a RoleUpdated event.""" |
| api = SupersetRoleApi.__new__(SupersetRoleApi) |
| role = MagicMock(spec=Role) |
| role.name = "TestRole" |
| role.id = 42 |
| api.post_update(role) |
| mock_log.assert_called_once_with( |
| "RoleUpdated", {"role_name": "TestRole", "role_id": 42} |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_role_api_post_delete_logs_event(mock_log: MagicMock) -> None: |
| """SupersetRoleApi.post_delete logs a RoleDeleted event.""" |
| api = SupersetRoleApi.__new__(SupersetRoleApi) |
| role = MagicMock(spec=Role) |
| role.name = "TestRole" |
| role.id = 42 |
| api.post_delete(role) |
| mock_log.assert_called_once_with( |
| "RoleDeleted", {"role_name": "TestRole", "role_id": 42} |
| ) |
| |
| |
| # --- User CRUD --- |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_user_api_post_add_logs_event(mock_log: MagicMock) -> None: |
| """SupersetUserApi.post_add logs a UserCreated event.""" |
| api = SupersetUserApi.__new__(SupersetUserApi) |
| user = MagicMock(spec=User) |
| user.username = "testuser" |
| user.id = 7 |
| user.email = "test@example.com" |
| api.post_add(user) |
| mock_log.assert_called_once_with( |
| "UserCreated", |
| { |
| "target_username": "testuser", |
| "target_user_id": 7, |
| "email": "test@example.com", |
| }, |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_user_api_post_update_logs_event(mock_log: MagicMock) -> None: |
| """SupersetUserApi.post_update logs a UserUpdated event.""" |
| api = SupersetUserApi.__new__(SupersetUserApi) |
| user = MagicMock(spec=User) |
| user.username = "testuser" |
| user.id = 7 |
| user.email = "test@example.com" |
| user.active = True |
| api.post_update(user) |
| mock_log.assert_called_once_with( |
| "UserUpdated", |
| { |
| "target_username": "testuser", |
| "target_user_id": 7, |
| "email": "test@example.com", |
| "active": True, |
| }, |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_user_api_post_delete_logs_event(mock_log: MagicMock) -> None: |
| """SupersetUserApi.post_delete logs a UserDeleted event.""" |
| api = SupersetUserApi.__new__(SupersetUserApi) |
| user = MagicMock(spec=User) |
| user.username = "testuser" |
| user.id = 7 |
| api.post_delete(user) |
| mock_log.assert_called_once_with( |
| "UserDeleted", |
| {"target_username": "testuser", "target_user_id": 7}, |
| ) |
| |
| |
| # --- Group CRUD --- |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_group_api_post_add_logs_event(mock_log: MagicMock) -> None: |
| """SupersetGroupApi.post_add logs a GroupCreated event.""" |
| api = SupersetGroupApi.__new__(SupersetGroupApi) |
| group = MagicMock(spec=Group) |
| group.name = "TestGroup" |
| group.id = 10 |
| api.post_add(group) |
| mock_log.assert_called_once_with( |
| "GroupCreated", {"group_name": "TestGroup", "group_id": 10} |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_group_api_post_update_logs_event(mock_log: MagicMock) -> None: |
| """SupersetGroupApi.post_update logs a GroupUpdated event.""" |
| api = SupersetGroupApi.__new__(SupersetGroupApi) |
| group = MagicMock(spec=Group) |
| group.name = "TestGroup" |
| group.id = 10 |
| api.post_update(group) |
| mock_log.assert_called_once_with( |
| "GroupUpdated", {"group_name": "TestGroup", "group_id": 10} |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_group_api_post_delete_logs_event(mock_log: MagicMock) -> None: |
| """SupersetGroupApi.post_delete logs a GroupDeleted event.""" |
| api = SupersetGroupApi.__new__(SupersetGroupApi) |
| group = MagicMock(spec=Group) |
| group.name = "TestGroup" |
| group.id = 10 |
| api.post_delete(group) |
| mock_log.assert_called_once_with( |
| "GroupDeleted", {"group_name": "TestGroup", "group_id": 10} |
| ) |
| |
| |
| # --- Login / Logout --- |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_on_user_login_logs_event(mock_log: MagicMock) -> None: |
| """on_user_login logs a UserLoggedIn event.""" |
| sm = SupersetSecurityManager.__new__(SupersetSecurityManager) |
| user = MagicMock(spec=User) |
| user.username = "testuser" |
| user.id = 7 |
| |
| sm.on_user_login(user) |
| |
| mock_log.assert_called_once_with( |
| "UserLoggedIn", {"username": "testuser", "user_id": 7} |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_on_user_login_failed_logs_event(mock_log: MagicMock) -> None: |
| """on_user_login_failed logs a UserLoginFailed event.""" |
| sm = SupersetSecurityManager.__new__(SupersetSecurityManager) |
| user = MagicMock(spec=User) |
| user.username = "testuser" |
| user.id = 7 |
| |
| sm.on_user_login_failed(user) |
| |
| mock_log.assert_called_once_with( |
| "UserLoginFailed", {"username": "testuser", "user_id": 7} |
| ) |
| |
| |
| @patch("superset.security.manager._log_audit_event") |
| def test_on_user_logout_logs_event(mock_log: MagicMock) -> None: |
| """on_user_logout logs a UserLoggedOut event.""" |
| sm = SupersetSecurityManager.__new__(SupersetSecurityManager) |
| user = MagicMock(spec=User) |
| user.username = "testuser" |
| user.id = 7 |
| |
| sm.on_user_logout(user) |
| |
| mock_log.assert_called_once_with( |
| "UserLoggedOut", {"username": "testuser", "user_id": 7} |
| ) |