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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user