mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-19 07:06:30 +00:00
Improve security layer (#352)
* Improve security layer * Update logger * Fix access * Validate token * fix * fix some bugs * fix lint
This commit is contained in:
parent
0c67cc13a1
commit
3bf446cbdb
@ -34,9 +34,16 @@ class AddonManager(CoreSysAttributes):
|
||||
return list(self.repositories_obj.values())
|
||||
|
||||
def get(self, addon_slug):
|
||||
"""Return a adddon from slug."""
|
||||
"""Return a add-on from slug."""
|
||||
return self.addons_obj.get(addon_slug)
|
||||
|
||||
def from_uuid(self, uuid):
|
||||
"""Return a add-on from uuid."""
|
||||
for addon in self.list_addons:
|
||||
if addon.is_installed and uuid == addon.uuid:
|
||||
return addon
|
||||
return None
|
||||
|
||||
async def load(self):
|
||||
"""Startup addon management."""
|
||||
self.data.reload()
|
||||
|
@ -17,6 +17,16 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class APIProxy(CoreSysAttributes):
|
||||
"""API Proxy for Home-Assistant."""
|
||||
|
||||
def _check_access(self, request):
|
||||
"""Check the Hass.io token."""
|
||||
hassio_token = request.headers.get(HEADER_HA_ACCESS)
|
||||
addon = self._addons.from_uuid(hassio_token)
|
||||
|
||||
if not addon:
|
||||
_LOGGER.warning("Unknown Home-Assistant API access!")
|
||||
else:
|
||||
_LOGGER.info("%s access from %s", request.path, addon.slug)
|
||||
|
||||
async def _api_client(self, request, path, timeout=300):
|
||||
"""Return a client request with proxy origin for Home-Assistant."""
|
||||
url = f"{self._homeassistant.api_url}/api/{path}"
|
||||
@ -59,6 +69,8 @@ class APIProxy(CoreSysAttributes):
|
||||
|
||||
async def stream(self, request):
|
||||
"""Proxy HomeAssistant EventStream Requests."""
|
||||
self._check_access(request)
|
||||
|
||||
_LOGGER.info("Home-Assistant EventStream start")
|
||||
client = await self._api_client(request, 'stream', timeout=None)
|
||||
|
||||
@ -83,12 +95,14 @@ class APIProxy(CoreSysAttributes):
|
||||
client.close()
|
||||
_LOGGER.info("Home-Assistant EventStream close")
|
||||
|
||||
return response
|
||||
|
||||
async def api(self, request):
|
||||
"""Proxy HomeAssistant API Requests."""
|
||||
path = request.match_info.get('path', '')
|
||||
self._check_access(request)
|
||||
|
||||
# Normal request
|
||||
_LOGGER.info("Home-Assistant /api/%s request", path)
|
||||
path = request.match_info.get('path', '')
|
||||
client = await self._api_client(request, path)
|
||||
|
||||
data = await client.read()
|
||||
@ -138,7 +152,17 @@ class APIProxy(CoreSysAttributes):
|
||||
'type': 'auth_required',
|
||||
'ha_version': self._homeassistant.version,
|
||||
})
|
||||
await server.receive_json() # get internal token
|
||||
|
||||
# Check API access
|
||||
response = await server.receive_json()
|
||||
hassio_token = response.get('api_password')
|
||||
addon = self._addons.from_uuid(hassio_token)
|
||||
|
||||
if not addon:
|
||||
_LOGGER.warning("Unauthorized websocket access!")
|
||||
else:
|
||||
_LOGGER.info("Websocket access from %s", addon.slug)
|
||||
|
||||
await server.send_json({
|
||||
'type': 'auth_ok',
|
||||
'ha_version': self._homeassistant.version,
|
||||
|
@ -1,12 +1,19 @@
|
||||
"""Handle security part of this API."""
|
||||
import logging
|
||||
import re
|
||||
|
||||
from aiohttp.web import middleware
|
||||
from aiohttp.web_exceptions import HTTPUnauthorized
|
||||
|
||||
from ..const import HEADER_TOKEN, REQUEST_FROM
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
NO_SECURITY_CHECK = set((
|
||||
re.compile(r"^/homeassistant/api/.*$"),
|
||||
re.compile(r"^/homeassistant/websocket$")
|
||||
))
|
||||
|
||||
|
||||
@middleware
|
||||
async def security_layer(request, handler):
|
||||
@ -14,21 +21,29 @@ async def security_layer(request, handler):
|
||||
coresys = request.app['coresys']
|
||||
hassio_token = request.headers.get(HEADER_TOKEN)
|
||||
|
||||
# Ignore security check
|
||||
for rule in NO_SECURITY_CHECK:
|
||||
if rule.match(request.path):
|
||||
_LOGGER.debug("Passthrough %s", request.path)
|
||||
return await handler(request)
|
||||
|
||||
# Need to be removed later
|
||||
if not hassio_token:
|
||||
_LOGGER.warning("No valid hassio token for API access!")
|
||||
_LOGGER.warning("No valid Hass.io token for API access!")
|
||||
request[REQUEST_FROM] = 'UNKNOWN'
|
||||
return await handler(request)
|
||||
|
||||
# From Home-Assistant
|
||||
elif hassio_token == coresys.homeassistant.uuid:
|
||||
# Home-Assistant
|
||||
if hassio_token == coresys.homeassistant.uuid:
|
||||
_LOGGER.debug("%s access from Home-Assistant", request.path)
|
||||
request[REQUEST_FROM] = 'homeassistant'
|
||||
return await handler(request)
|
||||
|
||||
# From Add-on
|
||||
else:
|
||||
for addon in coresys.addons.list_addons:
|
||||
if hassio_token != addon.uuid:
|
||||
continue
|
||||
request[REQUEST_FROM] = addon.slug
|
||||
break
|
||||
# Add-on
|
||||
addon = coresys.addons.from_uuid(hassio_token)
|
||||
if addon:
|
||||
_LOGGER.info("%s access from %s", request.path, addon.slug)
|
||||
request[REQUEST_FROM] = addon.slug
|
||||
return await handler(request)
|
||||
|
||||
return await handler(request)
|
||||
raise HTTPUnauthorized()
|
||||
|
Loading…
x
Reference in New Issue
Block a user