core/tests/components/auth/test_indieauth.py

191 lines
6.0 KiB
Python
Raw Normal View History

"""Tests for the client validator."""
import asyncio
from unittest.mock import patch
import pytest
from homeassistant.components.auth import indieauth
from tests.common import mock_coro
from tests.test_util.aiohttp import AiohttpClientMocker
@pytest.fixture
def mock_session():
"""Mock aiohttp.ClientSession."""
mocker = AiohttpClientMocker()
2019-07-31 19:25:30 +00:00
with patch(
"aiohttp.ClientSession",
side_effect=lambda *args, **kwargs: mocker.create_session(
asyncio.get_event_loop()
),
):
yield mocker
def test_client_id_scheme():
"""Test we enforce valid scheme."""
2019-07-31 19:25:30 +00:00
assert indieauth._parse_client_id("http://ex.com/")
assert indieauth._parse_client_id("https://ex.com/")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
indieauth._parse_client_id("ftp://ex.com")
def test_client_id_path():
"""Test we enforce valid path."""
2019-07-31 19:25:30 +00:00
assert indieauth._parse_client_id("http://ex.com").path == "/"
assert indieauth._parse_client_id("http://ex.com/hello").path == "/hello"
assert (
indieauth._parse_client_id("http://ex.com/hello/.world").path == "/hello/.world"
)
assert (
indieauth._parse_client_id("http://ex.com/hello./.world").path
== "/hello./.world"
)
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
indieauth._parse_client_id("http://ex.com/.")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
indieauth._parse_client_id("http://ex.com/hello/./yo")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
indieauth._parse_client_id("http://ex.com/hello/../yo")
def test_client_id_fragment():
"""Test we enforce valid fragment."""
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
indieauth._parse_client_id("http://ex.com/#yoo")
def test_client_id_user_pass():
"""Test we enforce valid username/password."""
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
indieauth._parse_client_id("http://user@ex.com/")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
indieauth._parse_client_id("http://user:pass@ex.com/")
def test_client_id_hostname():
"""Test we enforce valid hostname."""
2019-07-31 19:25:30 +00:00
assert indieauth._parse_client_id("http://www.home-assistant.io/")
assert indieauth._parse_client_id("http://[::1]")
assert indieauth._parse_client_id("http://127.0.0.1")
assert indieauth._parse_client_id("http://10.0.0.0")
assert indieauth._parse_client_id("http://10.255.255.255")
assert indieauth._parse_client_id("http://172.16.0.0")
assert indieauth._parse_client_id("http://172.31.255.255")
assert indieauth._parse_client_id("http://192.168.0.0")
assert indieauth._parse_client_id("http://192.168.255.255")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
assert indieauth._parse_client_id("http://255.255.255.255/")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
assert indieauth._parse_client_id("http://11.0.0.0/")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
assert indieauth._parse_client_id("http://172.32.0.0/")
with pytest.raises(ValueError):
2019-07-31 19:25:30 +00:00
assert indieauth._parse_client_id("http://192.167.0.0/")
def test_parse_url_lowercase_host():
"""Test we update empty paths."""
2019-07-31 19:25:30 +00:00
assert indieauth._parse_url("http://ex.com/hello").path == "/hello"
assert indieauth._parse_url("http://EX.COM/hello").hostname == "ex.com"
2019-07-31 19:25:30 +00:00
parts = indieauth._parse_url("http://EX.COM:123/HELLO")
assert parts.netloc == "ex.com:123"
assert parts.path == "/HELLO"
def test_parse_url_path():
"""Test we update empty paths."""
2019-07-31 19:25:30 +00:00
assert indieauth._parse_url("http://ex.com").path == "/"
async def test_verify_redirect_uri():
"""Test that we verify redirect uri correctly."""
assert await indieauth.verify_redirect_uri(
2019-07-31 19:25:30 +00:00
None, "http://ex.com", "http://ex.com/callback"
)
2019-07-31 19:25:30 +00:00
with patch.object(
indieauth, "fetch_redirect_uris", side_effect=lambda *_: mock_coro([])
):
# Different domain
assert not await indieauth.verify_redirect_uri(
2019-07-31 19:25:30 +00:00
None, "http://ex.com", "http://different.com/callback"
)
# Different scheme
assert not await indieauth.verify_redirect_uri(
2019-07-31 19:25:30 +00:00
None, "http://ex.com", "https://ex.com/callback"
)
# Different subdomain
assert not await indieauth.verify_redirect_uri(
2019-07-31 19:25:30 +00:00
None, "https://sub1.ex.com", "https://sub2.ex.com/callback"
)
async def test_find_link_tag(hass, mock_session):
"""Test finding link tag."""
2019-07-31 19:25:30 +00:00
mock_session.get(
"http://127.0.0.1:8000",
text="""
<!doctype html>
<html>
<head>
<link rel="redirect_uri" href="hass://oauth2_redirect">
<link rel="other_value" href="hass://oauth2_redirect">
<link rel="redirect_uri" href="/beer">
</head>
...
</html>
2019-07-31 19:25:30 +00:00
""",
)
redirect_uris = await indieauth.fetch_redirect_uris(hass, "http://127.0.0.1:8000")
2019-07-31 19:25:30 +00:00
assert redirect_uris == ["hass://oauth2_redirect", "http://127.0.0.1:8000/beer"]
async def test_find_link_tag_max_size(hass, mock_session):
"""Test finding link tag."""
2019-07-31 19:25:30 +00:00
text = "".join(
[
'<link rel="redirect_uri" href="/wine">',
("0" * 1024 * 10),
'<link rel="redirect_uri" href="/beer">',
]
)
mock_session.get("http://127.0.0.1:8000", text=text)
2019-07-31 19:25:30 +00:00
redirect_uris = await indieauth.fetch_redirect_uris(hass, "http://127.0.0.1:8000")
assert redirect_uris == ["http://127.0.0.1:8000/wine"]
@pytest.mark.parametrize(
"client_id",
["https://www.home-assistant.io/android", "https://www.home-assistant.io/iOS"],
)
async def test_verify_redirect_uri_android_ios(client_id):
"""Test that we verify redirect uri correctly for Android/iOS."""
with patch.object(
indieauth, "fetch_redirect_uris", side_effect=lambda *_: mock_coro([])
):
assert await indieauth.verify_redirect_uri(
None, client_id, "homeassistant://auth-callback"
)
assert not await indieauth.verify_redirect_uri(
None, client_id, "homeassistant://something-else"
)
assert not await indieauth.verify_redirect_uri(
None, "https://incorrect.com", "homeassistant://auth-callback"
)