diff --git a/homeassistant/components/config/__init__.py b/homeassistant/components/config/__init__.py index 514154137e4..84a1c2eaa17 100644 --- a/homeassistant/components/config/__init__.py +++ b/homeassistant/components/config/__init__.py @@ -7,7 +7,7 @@ import os import voluptuous as vol from homeassistant.components import frontend -from homeassistant.components.http import HomeAssistantView +from homeassistant.components.http import HomeAssistantView, require_admin from homeassistant.const import CONF_ID, EVENT_COMPONENT_LOADED from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError @@ -103,6 +103,7 @@ class BaseEditConfigView(HomeAssistantView): """Delete value.""" raise NotImplementedError + @require_admin async def get(self, request, config_key): """Fetch device specific config.""" hass = request.app["hass"] @@ -115,6 +116,7 @@ class BaseEditConfigView(HomeAssistantView): return self.json(value) + @require_admin async def post(self, request, config_key): """Validate config and return results.""" try: @@ -156,6 +158,7 @@ class BaseEditConfigView(HomeAssistantView): return self.json({"result": "ok"}) + @require_admin async def delete(self, request, config_key): """Remove an entry.""" hass = request.app["hass"] diff --git a/tests/components/config/test_automation.py b/tests/components/config/test_automation.py index 11f17199e5a..abe0ed90e86 100644 --- a/tests/components/config/test_automation.py +++ b/tests/components/config/test_automation.py @@ -372,3 +372,35 @@ async def test_delete_automation( assert hass_config_store["automations.yaml"] == [{"id": "moon"}] assert len(ent_reg.entities) == 1 + + +@pytest.mark.parametrize("automation_config", ({},)) +async def test_api_calls_require_admin( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + hass_read_only_access_token: str, + hass_config_store, + setup_automation, +) -> None: + """Test cloud APIs endpoints do not work as a normal user.""" + with patch.object(config, "SECTIONS", ["automation"]): + await async_setup_component(hass, "config", {}) + + hass_config_store["automations.yaml"] = [{"id": "sun"}, {"id": "moon"}] + + client = await hass_client(hass_read_only_access_token) + + # Get + resp = await client.get("/api/config/automation/config/moon") + assert resp.status == HTTPStatus.UNAUTHORIZED + + # Update + resp = await client.post( + "/api/config/automation/config/moon", + data=json.dumps({"trigger": [], "action": [], "condition": []}), + ) + assert resp.status == HTTPStatus.UNAUTHORIZED + + # Delete + resp = await client.delete("/api/config/automation/config/sun") + assert resp.status == HTTPStatus.UNAUTHORIZED diff --git a/tests/components/config/test_scene.py b/tests/components/config/test_scene.py index d07db81b715..1f09d5e9989 100644 --- a/tests/components/config/test_scene.py +++ b/tests/components/config/test_scene.py @@ -221,3 +221,47 @@ async def test_delete_scene( ] assert len(ent_reg.entities) == 1 + + +@pytest.mark.parametrize("scene_config", ({},)) +async def test_api_calls_require_admin( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + hass_read_only_access_token: str, + hass_config_store, + setup_scene, +) -> None: + """Test scene APIs endpoints do not work as a normal user.""" + with patch.object(config, "SECTIONS", ["scene"]): + await async_setup_component(hass, "config", {}) + + hass_config_store["scenes.yaml"] = [ + { + "id": "light_off", + "name": "Lights off", + "entities": {"light.bedroom": {"state": "off"}}, + } + ] + + client = await hass_client(hass_read_only_access_token) + + # Get + resp = await client.get("/api/config/scene/config/light_off") + assert resp.status == HTTPStatus.UNAUTHORIZED + + # Update + resp = await client.post( + "/api/config/scene/config/light_off", + data=json.dumps( + { + "id": "light_off", + "name": "Lights off", + "entities": {"light.bedroom": {"state": "off"}}, + } + ), + ) + assert resp.status == HTTPStatus.UNAUTHORIZED + + # Delete + resp = await client.delete("/api/config/scene/config/light_on") + assert resp.status == HTTPStatus.UNAUTHORIZED diff --git a/tests/components/config/test_script.py b/tests/components/config/test_script.py index 86ea2cf9e7f..cc0352301b4 100644 --- a/tests/components/config/test_script.py +++ b/tests/components/config/test_script.py @@ -314,3 +314,36 @@ async def test_delete_script( assert hass_config_store["scripts.yaml"] == {"one": {}} assert len(ent_reg.entities) == 1 + + +@pytest.mark.parametrize("script_config", ({},)) +async def test_api_calls_require_admin( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + hass_read_only_access_token: str, + hass_config_store, +) -> None: + """Test script APIs endpoints do not work as a normal user.""" + with patch.object(config, "SECTIONS", ["script"]): + await async_setup_component(hass, "config", {}) + + hass_config_store["scripts.yaml"] = { + "moon": {"alias": "Moon"}, + } + + client = await hass_client(hass_read_only_access_token) + + # Get + resp = await client.get("/api/config/script/config/moon") + assert resp.status == HTTPStatus.UNAUTHORIZED + + # Update + resp = await client.post( + "/api/config/script/config/moon", + data=json.dumps({"sequence": []}), + ) + assert resp.status == HTTPStatus.UNAUTHORIZED + + # Delete + resp = await client.delete("/api/config/script/config/moon") + assert resp.status == HTTPStatus.UNAUTHORIZED