mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-09-28 10:56:52 +03:00
Enhance user roles to limit camera access (#20024)
* update config for roles and add validator * ensure admin and viewer are never overridden * add class method to user to retrieve all allowed cameras * enforce config roles in auth api endpoints * add camera access api dependency functions * protect review endpoints * protect preview endpoints * rename param name for better fastapi injection matching * remove unneeded * protect export endpoints * protect event endpoints * protect media endpoints * update auth hook for allowed cameras * update default app view * ensure anonymous user always returns all cameras * limit cameras in explore * cameras is already a list * limit cameras in review/history * limit cameras in live view * limit cameras in camera groups * only show face library and classification in sidebar for admin * remove check in delete reviews since admin role is required, no need to check camera access. fixes failing test * pass request with camera access for tests * more async * camera access tests * fix proxy auth tests * allowed cameras for review tests * combine event tests and refactor for camera access * fix post validation for roles * don't limit roles in create user dialog * fix triggers endpoints no need to run require camera access dep since the required role is admin * fix type * create and edit role dialogs * delete role dialog * fix role change dialog * update settings view for roles * i18n changes * minor spacing tweaks * docs * use badges and camera name label component * clarify docs * display all cameras badge for admin and viewer * i18n fix * use validator to prevent reserved and empty roles from being assigned * split users and roles into separate tabs in settings * tweak docs * clarify docs * change icon * don't memoize roles always recalculate on component render
This commit is contained in:
@@ -19,61 +19,60 @@ class TestProxyRoleResolution(unittest.TestCase):
|
||||
},
|
||||
),
|
||||
)
|
||||
self.config_roles = list(["admin", "viewer"])
|
||||
|
||||
def test_role_map_single_group_match(self):
|
||||
headers = {"x-remote-role": "group_admin"}
|
||||
role = resolve_role(headers, self.proxy_config)
|
||||
role = resolve_role(headers, self.proxy_config, self.config_roles)
|
||||
self.assertEqual(role, "admin")
|
||||
|
||||
def test_role_map_multiple_groups(self):
|
||||
headers = {"x-remote-role": "group_viewer|group_admin"}
|
||||
role = resolve_role(headers, self.proxy_config)
|
||||
# admin should win since VALID_ROLES priority puts it before viewer
|
||||
headers = {"x-remote-role": "group_admin|group_viewer"}
|
||||
role = resolve_role(headers, self.proxy_config, self.config_roles)
|
||||
self.assertEqual(role, "admin")
|
||||
|
||||
def test_direct_role_header_with_separator(self):
|
||||
config = self.proxy_config
|
||||
config.header_map.role_map = None # disable role_map
|
||||
headers = {"x-remote-role": "viewer|admin"}
|
||||
role = resolve_role(headers, config)
|
||||
# admin should be chosen since it appears in VALID_ROLES
|
||||
headers = {"x-remote-role": "admin|viewer"}
|
||||
role = resolve_role(headers, config, self.config_roles)
|
||||
self.assertEqual(role, "admin")
|
||||
|
||||
def test_invalid_role_header(self):
|
||||
config = self.proxy_config
|
||||
config.header_map.role_map = None
|
||||
headers = {"x-remote-role": "notarole"}
|
||||
role = resolve_role(headers, config)
|
||||
role = resolve_role(headers, config, self.config_roles)
|
||||
self.assertEqual(role, config.default_role)
|
||||
|
||||
def test_missing_role_header(self):
|
||||
headers = {}
|
||||
role = resolve_role(headers, self.proxy_config)
|
||||
role = resolve_role(headers, self.proxy_config, self.config_roles)
|
||||
self.assertEqual(role, self.proxy_config.default_role)
|
||||
|
||||
def test_empty_role_header(self):
|
||||
headers = {"x-remote-role": ""}
|
||||
role = resolve_role(headers, self.proxy_config)
|
||||
role = resolve_role(headers, self.proxy_config, self.config_roles)
|
||||
self.assertEqual(role, self.proxy_config.default_role)
|
||||
|
||||
def test_whitespace_groups(self):
|
||||
headers = {"x-remote-role": " | group_admin | "}
|
||||
role = resolve_role(headers, self.proxy_config)
|
||||
role = resolve_role(headers, self.proxy_config, self.config_roles)
|
||||
self.assertEqual(role, "admin")
|
||||
|
||||
def test_mixed_valid_and_invalid_groups(self):
|
||||
headers = {"x-remote-role": "bogus|group_viewer"}
|
||||
role = resolve_role(headers, self.proxy_config)
|
||||
role = resolve_role(headers, self.proxy_config, self.config_roles)
|
||||
self.assertEqual(role, "viewer")
|
||||
|
||||
def test_case_insensitive_role_direct(self):
|
||||
config = self.proxy_config
|
||||
config.header_map.role_map = None
|
||||
headers = {"x-remote-role": "AdMiN"}
|
||||
role = resolve_role(headers, config)
|
||||
role = resolve_role(headers, config, self.config_roles)
|
||||
self.assertEqual(role, "admin")
|
||||
|
||||
def test_role_map_no_match_falls_back(self):
|
||||
headers = {"x-remote-role": "group_unknown"}
|
||||
role = resolve_role(headers, self.proxy_config)
|
||||
role = resolve_role(headers, self.proxy_config, self.config_roles)
|
||||
self.assertEqual(role, self.proxy_config.default_role)
|
||||
|
||||
Reference in New Issue
Block a user