diff --git a/homeassistant/components/cloud/__init__.py b/homeassistant/components/cloud/__init__.py index 3bfc5909b0b3a..ba2d41a9feb22 100644 --- a/homeassistant/components/cloud/__init__.py +++ b/homeassistant/components/cloud/__init__.py @@ -4,20 +4,16 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/cloud/ """ -import asyncio from datetime import datetime, timedelta import json import logging import os -import aiohttp -import async_timeout import voluptuous as vol from homeassistant.const import ( EVENT_HOMEASSISTANT_START, CONF_REGION, CONF_MODE, CONF_NAME) from homeassistant.helpers import entityfilter, config_validation as cv -from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.util import dt as dt_util from homeassistant.components.alexa import smart_home as alexa_sh from homeassistant.components.google_assistant import helpers as ga_h @@ -129,7 +125,6 @@ def __init__(self, hass, mode, alexa, google_actions, self._google_actions = google_actions self._gactions_config = None self._prefs = None - self.jwt_keyset = None self.id_token = None self.access_token = None self.refresh_token = None @@ -262,13 +257,6 @@ async def async_start(self, _): } self._prefs = prefs - success = await self._fetch_jwt_keyset() - - # Fetching keyset can fail if internet is not up yet. - if not success: - self.hass.helpers.event.async_call_later(5, self.async_start) - return - def load_config(): """Load config.""" # Ensure config dir exists @@ -288,14 +276,6 @@ def load_config(): if info is None: return - # Validate tokens - try: - for token in 'id_token', 'access_token': - self._decode_claims(info[token]) - except ValueError as err: # Raised when token is invalid - _LOGGER.warning("Found invalid token %s: %s", token, err) - return - self.id_token = info['id_token'] self.access_token = info['access_token'] self.refresh_token = info['refresh_token'] @@ -311,49 +291,7 @@ async def update_preferences(self, *, google_enabled=_UNDEF, self._prefs[STORAGE_ENABLE_ALEXA] = alexa_enabled await self._store.async_save(self._prefs) - async def _fetch_jwt_keyset(self): - """Fetch the JWT keyset for the Cognito instance.""" - session = async_get_clientsession(self.hass) - url = ("https://cognito-idp.us-east-1.amazonaws.com/" - "{}/.well-known/jwks.json".format(self.user_pool_id)) - - try: - with async_timeout.timeout(10, loop=self.hass.loop): - req = await session.get(url) - self.jwt_keyset = await req.json() - - return True - - except (asyncio.TimeoutError, aiohttp.ClientError) as err: - _LOGGER.error("Error fetching Cognito keyset: %s", err) - return False - - def _decode_claims(self, token): + def _decode_claims(self, token): # pylint: disable=no-self-use """Decode the claims in a token.""" - from jose import jwt, exceptions as jose_exceptions - try: - header = jwt.get_unverified_header(token) - except jose_exceptions.JWTError as err: - raise ValueError(str(err)) from None - kid = header.get('kid') - - if kid is None: - raise ValueError("No kid in header") - - # Locate the key for this kid - key = None - for key_dict in self.jwt_keyset['keys']: - if key_dict['kid'] == kid: - key = key_dict - break - if not key: - raise ValueError( - "Unable to locate kid ({}) in keyset".format(kid)) - - try: - return jwt.decode( - token, key, audience=self.cognito_client_id, options={ - 'verify_exp': False, - }) - except jose_exceptions.JWTError as err: - raise ValueError(str(err)) from None + from jose import jwt + return jwt.get_unverified_claims(token) diff --git a/tests/components/cloud/test_init.py b/tests/components/cloud/test_init.py index 61518f0f0e84e..44d56566f7566 100644 --- a/tests/components/cloud/test_init.py +++ b/tests/components/cloud/test_init.py @@ -32,8 +32,7 @@ def test_constructor_loads_info_from_constant(): 'google_actions_sync_url': 'test-google_actions_sync_url', 'subscription_info_url': 'test-subscription-info-url' } - }), patch('homeassistant.components.cloud.Cloud._fetch_jwt_keyset', - return_value=mock_coro(True)): + }): result = yield from cloud.async_setup(hass, { 'cloud': {cloud.CONF_MODE: 'beer'} }) @@ -54,17 +53,15 @@ def test_constructor_loads_info_from_config(): """Test non-dev mode loads info from SERVERS constant.""" hass = MagicMock(data={}) - with patch('homeassistant.components.cloud.Cloud._fetch_jwt_keyset', - return_value=mock_coro(True)): - result = yield from cloud.async_setup(hass, { - 'cloud': { - cloud.CONF_MODE: cloud.MODE_DEV, - 'cognito_client_id': 'test-cognito_client_id', - 'user_pool_id': 'test-user_pool_id', - 'region': 'test-region', - 'relayer': 'test-relayer', - } - }) + result = yield from cloud.async_setup(hass, { + 'cloud': { + cloud.CONF_MODE: cloud.MODE_DEV, + 'cognito_client_id': 'test-cognito_client_id', + 'user_pool_id': 'test-user_pool_id', + 'region': 'test-region', + 'relayer': 'test-relayer', + } + }) assert result cl = hass.data['cloud'] @@ -89,8 +86,6 @@ async def test_initialize_loads_info(mock_os, hass): cl.iot.connect.return_value = mock_coro() with patch('homeassistant.components.cloud.open', mopen, create=True), \ - patch('homeassistant.components.cloud.Cloud._fetch_jwt_keyset', - return_value=mock_coro(True)), \ patch('homeassistant.components.cloud.Cloud._decode_claims'): await cl.async_start(None)