1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 12:59:34 +00:00

Create decorator to check service permissions (#22667)

* Create decorator to check service permissions

* Typing

* Linting

* Member comments

* Linting

* Member comments

* Updated import

* Owner comments

* Linting

* Linting

* More work

* Fixed tests

* Removed service helper tests in RainMachine

* Linting

* Owner comments

* Linting

* Owner comments

Co-Authored-By: bachya <bachya1208@gmail.com>
This commit is contained in:
Aaron Bach
2019-04-13 13:54:29 -06:00
committed by GitHub
parent 7a6950fd72
commit fc481133e7
5 changed files with 177 additions and 118 deletions

View File

@@ -6,7 +6,7 @@ from typing import Callable
import voluptuous as vol
from homeassistant.auth.permissions.const import POLICY_CONTROL
from homeassistant.auth.permissions.const import CAT_ENTITIES, POLICY_CONTROL
from homeassistant.const import (
ATTR_ENTITY_ID, ENTITY_MATCH_ALL, ATTR_AREA_ID)
import homeassistant.core as ha
@@ -19,6 +19,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.util.async_ import run_coroutine_threadsafe
from homeassistant.helpers.typing import HomeAssistantType
from .typing import HomeAssistantType
CONF_SERVICE = 'service'
CONF_SERVICE_TEMPLATE = 'service_template'
CONF_SERVICE_ENTITY_ID = 'entity_id'
@@ -369,3 +371,47 @@ def async_register_admin_service(
hass.services.async_register(
domain, service, admin_handler, schema
)
@bind_hass
@ha.callback
def verify_domain_control(hass: HomeAssistantType, domain: str) -> Callable:
"""Ensure permission to access any entity under domain in service call."""
def decorator(service_handler: Callable) -> Callable:
"""Decorate."""
if not asyncio.iscoroutinefunction(service_handler):
raise HomeAssistantError(
'Can only decorate async functions.')
async def check_permissions(call):
"""Check user permission and raise before call if unauthorized."""
if not call.context.user_id:
return await service_handler(call)
user = await hass.auth.async_get_user(call.context.user_id)
if user is None:
raise UnknownUser(
context=call.context,
permission=POLICY_CONTROL,
user_id=call.context.user_id)
reg = await hass.helpers.entity_registry.async_get_registry()
entities = [
entity.entity_id for entity in reg.entities.values()
if entity.platform == domain
]
for entity_id in entities:
if user.permissions.check_entity(entity_id, POLICY_CONTROL):
return await service_handler(call)
raise Unauthorized(
context=call.context,
permission=POLICY_CONTROL,
user_id=call.context.user_id,
perm_category=CAT_ENTITIES
)
return check_permissions
return decorator