diff --git a/homeassistant/components/auth/login_flow.py b/homeassistant/components/auth/login_flow.py index cc6cb5fc47a..9b96e57dbd3 100644 --- a/homeassistant/components/auth/login_flow.py +++ b/homeassistant/components/auth/login_flow.py @@ -91,7 +91,6 @@ from homeassistant.components.http.data_validator import RequestDataValidator from homeassistant.components.http.view import HomeAssistantView from homeassistant.core import HomeAssistant from homeassistant.helpers.network import is_cloud_connection -from homeassistant.util.network import is_local from . import indieauth @@ -186,14 +185,7 @@ class AuthProvidersView(HomeAssistantView): } ) - preselect_remember_me = not cloud_connection and is_local(remote_address) - - return self.json( - { - "providers": providers, - "preselect_remember_me": preselect_remember_me, - } - ) + return self.json(providers) def _prepare_result_json( diff --git a/homeassistant/components/person/__init__.py b/homeassistant/components/person/__init__.py index 49b719a5490..c796cb8d843 100644 --- a/homeassistant/components/person/__init__.py +++ b/homeassistant/components/person/__init__.py @@ -1,9 +1,11 @@ """Support for tracking people.""" from __future__ import annotations +from http import HTTPStatus import logging from typing import Any +from aiohttp import web import voluptuous as vol from homeassistant.auth import EVENT_USER_REMOVED @@ -13,6 +15,7 @@ from homeassistant.components.device_tracker import ( DOMAIN as DEVICE_TRACKER_DOMAIN, SourceType, ) +from homeassistant.components.http.view import HomeAssistantView from homeassistant.const import ( ATTR_EDITABLE, ATTR_ENTITY_ID, @@ -385,6 +388,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: hass, DOMAIN, SERVICE_RELOAD, async_reload_yaml ) + hass.http.register_view(ListPersonsView) + return True @@ -569,3 +574,19 @@ def _get_latest(prev: State | None, curr: State): if prev is None or curr.last_updated > prev.last_updated: return curr return prev + + +class ListPersonsView(HomeAssistantView): + """List all persons if request is made from a local network.""" + + requires_auth = False + url = "/api/person/list" + name = "api:person:list" + + async def get(self, request: web.Request) -> web.Response: + """Return a list of persons if request comes from a local IP.""" + return self.json_message( + message="Not local", + status_code=HTTPStatus.BAD_REQUEST, + message_code="not_local", + ) diff --git a/tests/components/auth/test_login_flow.py b/tests/components/auth/test_login_flow.py index c8b0261b79c..27652ca2be4 100644 --- a/tests/components/auth/test_login_flow.py +++ b/tests/components/auth/test_login_flow.py @@ -6,6 +6,7 @@ from unittest.mock import patch import pytest from homeassistant.core import HomeAssistant +from homeassistant.setup import async_setup_component from . import BASE_CONFIG, async_setup_auth @@ -25,30 +26,22 @@ _TRUSTED_NETWORKS_CONFIG = { @pytest.mark.parametrize( - ("ip", "preselect_remember_me"), - [ - ("192.168.1.10", True), - ("::ffff:192.168.0.10", True), - ("1.2.3.4", False), - ("2001:db8::1", False), - ], -) -@pytest.mark.parametrize( - ("provider_configs", "expected"), + ("provider_configs", "ip", "expected"), [ ( BASE_CONFIG, + None, [{"name": "Example", "type": "insecure_example", "id": None}], ), ( - [{"type": "homeassistant"}], - [ - { - "name": "Home Assistant Local", - "type": "homeassistant", - "id": None, - } - ], + [_TRUSTED_NETWORKS_CONFIG], + None, + [], + ), + ( + [_TRUSTED_NETWORKS_CONFIG], + "192.168.0.1", + [{"name": "Trusted Networks", "type": "trusted_networks", "id": None}], ), ], ) @@ -56,9 +49,8 @@ async def test_fetch_auth_providers( hass: HomeAssistant, aiohttp_client: ClientSessionGenerator, provider_configs: list[dict[str, Any]], + ip: str | None, expected: list[dict[str, Any]], - ip: str, - preselect_remember_me: bool, ) -> None: """Test fetching auth providers.""" client = await async_setup_auth( @@ -66,37 +58,73 @@ async def test_fetch_auth_providers( ) resp = await client.get("/auth/providers") assert resp.status == HTTPStatus.OK - assert await resp.json() == { - "providers": expected, - "preselect_remember_me": preselect_remember_me, + assert await resp.json() == expected + + +async def _test_fetch_auth_providers_home_assistant( + hass: HomeAssistant, + aiohttp_client: ClientSessionGenerator, + ip: str, +) -> None: + """Test fetching auth providers for homeassistant auth provider.""" + client = await async_setup_auth( + hass, aiohttp_client, [{"type": "homeassistant"}], custom_ip=ip + ) + + expected = { + "name": "Home Assistant Local", + "type": "homeassistant", + "id": None, } + resp = await client.get("/auth/providers") + assert resp.status == HTTPStatus.OK + assert await resp.json() == [expected] + @pytest.mark.parametrize( - ("ip", "expected"), + "ip", [ - ( - "192.168.0.1", - [{"name": "Trusted Networks", "type": "trusted_networks", "id": None}], - ), - ("::ffff:192.168.0.10", []), - ("1.2.3.4", []), - ("2001:db8::1", []), + "192.168.0.10", + "::ffff:192.168.0.10", + "1.2.3.4", + "2001:db8::1", ], ) -async def test_fetch_auth_providers_trusted_network( +async def test_fetch_auth_providers_home_assistant_person_not_loaded( hass: HomeAssistant, aiohttp_client: ClientSessionGenerator, - expected: list[dict[str, Any]], ip: str, ) -> None: - """Test fetching auth providers.""" - client = await async_setup_auth( - hass, aiohttp_client, [_TRUSTED_NETWORKS_CONFIG], custom_ip=ip + """Test fetching auth providers for homeassistant auth provider, where person integration is not loaded.""" + await _test_fetch_auth_providers_home_assistant(hass, aiohttp_client, ip) + + +@pytest.mark.parametrize( + ("ip", "is_local"), + [ + ("192.168.0.10", True), + ("::ffff:192.168.0.10", True), + ("1.2.3.4", False), + ("2001:db8::1", False), + ], +) +async def test_fetch_auth_providers_home_assistant_person_loaded( + hass: HomeAssistant, + aiohttp_client: ClientSessionGenerator, + ip: str, + is_local: bool, +) -> None: + """Test fetching auth providers for homeassistant auth provider, where person integration is loaded.""" + domain = "person" + config = {domain: {"id": "1234", "name": "test person"}} + assert await async_setup_component(hass, domain, config) + + await _test_fetch_auth_providers_home_assistant( + hass, + aiohttp_client, + ip, ) - resp = await client.get("/auth/providers") - assert resp.status == HTTPStatus.OK - assert (await resp.json())["providers"] == expected async def test_fetch_auth_providers_onboarding( diff --git a/tests/components/person/test_init.py b/tests/components/person/test_init.py index 71491ee3caf..1866f682b55 100644 --- a/tests/components/person/test_init.py +++ b/tests/components/person/test_init.py @@ -1,4 +1,5 @@ """The tests for the person component.""" +from http import HTTPStatus from typing import Any from unittest.mock import patch @@ -29,7 +30,7 @@ from homeassistant.setup import async_setup_component from .conftest import DEVICE_TRACKER, DEVICE_TRACKER_2 from tests.common import MockUser, mock_component, mock_restore_cache -from tests.typing import WebSocketGenerator +from tests.typing import ClientSessionGenerator, WebSocketGenerator async def test_minimal_setup(hass: HomeAssistant) -> None: @@ -847,3 +848,30 @@ async def test_entities_in_person(hass: HomeAssistant) -> None: "device_tracker.paulus_iphone", "device_tracker.paulus_ipad", ] + + +async def test_list_persons( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + hass_admin_user: MockUser, +) -> None: + """Test listing persons from a not local ip address.""" + + user_id = hass_admin_user.id + admin = {"id": "1234", "name": "Admin", "user_id": user_id, "picture": "/bla"} + config = { + DOMAIN: [ + admin, + {"id": "5678", "name": "Only a person"}, + ] + } + assert await async_setup_component(hass, DOMAIN, config) + + await async_setup_component(hass, "api", {}) + client = await hass_client_no_auth() + + resp = await client.get("/api/person/list") + + assert resp.status == HTTPStatus.BAD_REQUEST + result = await resp.json() + assert result == {"code": "not_local", "message": "Not local"}