async def test_oauth_session_refresh_failure(opp, flow_handler, local_impl,
                                             aioclient_mock):
    """Test the OAuth2 session helper when no refresh is needed."""
    flow_handler.async_register_implementation(opp, local_impl)

    aioclient_mock.post(TOKEN_URL, status=400)

    config_entry = MockConfigEntry(
        domain=TEST_DOMAIN,
        data={
            "auth_implementation": TEST_DOMAIN,
            "token": {
                "refresh_token": REFRESH_TOKEN,
                "access_token": ACCESS_TOKEN_1,
                # Already expired, requires a refresh
                "expires_in": -500,
                "expires_at": time.time() - 500,
                "token_type": "bearer",
                "random_other_data": "should_stay",
            },
        },
    )

    session = config_entry_oauth2_flow.OAuth2Session(opp, config_entry,
                                                     local_impl)
    with pytest.raises(aiohttp.client_exceptions.ClientResponseError):
        await session.async_request("post", "https://example.com")
예제 #2
0
async def async_setup_entry(opp: OpenPeerPower, entry: ConfigEntry):
    """Set up xbox from a config entry."""
    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            opp, entry))
    session = config_entry_oauth2_flow.OAuth2Session(opp, entry,
                                                     implementation)
    auth = api.AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(opp), session)

    client = XboxLiveClient(auth)
    consoles: SmartglassConsoleList = await client.smartglass.get_console_list(
    )
    _LOGGER.debug(
        "Found %d consoles: %s",
        len(consoles.result),
        consoles.dict(),
    )

    coordinator = XboxUpdateCoordinator(opp, client, consoles)
    await coordinator.async_config_entry_first_refresh()

    opp.data[DOMAIN][entry.entry_id] = {
        "client": XboxLiveClient(auth),
        "consoles": consoles,
        "coordinator": coordinator,
    }

    opp.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
예제 #3
0
async def async_setup_entry(opp: OpenPeerPower, entry: ConfigEntry) -> bool:
    """Set up config entry."""
    if CONF_TOKEN not in entry.data:
        raise ConfigEntryAuthFailed

    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            opp, entry))

    session = config_entry_oauth2_flow.OAuth2Session(opp, entry,
                                                     implementation)

    neato_session = api.ConfigEntryAuth(opp, entry, session)
    opp.data[NEATO_DOMAIN][entry.entry_id] = neato_session
    hub = NeatoHub(opp, Account(neato_session))

    try:
        await opp.async_add_executor_job(hub.update_robots)
    except NeatoException as ex:
        _LOGGER.debug("Failed to connect to Neato API")
        raise ConfigEntryNotReady from ex

    opp.data[NEATO_LOGIN] = hub

    opp.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
예제 #4
0
 def __init__(
     self,
     opp: core.OpenPeerPower,
     config_entry: config_entries.ConfigEntry,
     implementation: config_entry_oauth2_flow.AbstractOAuth2Implementation,
 ) -> None:
     """Initialize Neato Botvac Auth."""
     self.opp = opp
     self.session = config_entry_oauth2_flow.OAuth2Session(
         opp, config_entry, implementation)
     super().__init__(self.session.token, vendor=pybotvac.Neato())
예제 #5
0
파일: api.py 프로젝트: OpenPeerPower/core
 def __init__(
     self,
     opp: core.OpenPeerPower,
     config_entry: config_entries.ConfigEntry,
     implementation: config_entry_oauth2_flow.AbstractOAuth2Implementation,
 ) -> None:
     """Initialize the Config Entry Somfy API."""
     self.opp = opp
     self.config_entry = config_entry
     self.session = config_entry_oauth2_flow.OAuth2Session(
         opp, config_entry, implementation)
     super().__init__(None, None, token=self.session.token)
예제 #6
0
파일: api.py 프로젝트: OpenPeerPower/core
 def __init__(
     self,
     opp: core.OpenPeerPower,
     config_entry: config_entries.ConfigEntry,
     implementation: config_entry_oauth2_flow.AbstractOAuth2Implementation,
 ) -> None:
     """Initialize Home Connect Auth."""
     self.opp = opp
     self.config_entry = config_entry
     self.session = config_entry_oauth2_flow.OAuth2Session(
         opp, config_entry, implementation)
     super().__init__(self.session.token)
     self.devices = []
예제 #7
0
async def async_setup_entry(opp: OpenPeerPower,
                            entry: config_entries.ConfigEntry):
    """Set up Almond config entry."""
    websession = aiohttp_client.async_get_clientsession(opp)

    if entry.data["type"] == TYPE_LOCAL:
        auth = AlmondLocalAuth(entry.data["host"], websession)
    else:
        # OAuth2
        implementation = (
            await
            config_entry_oauth2_flow.async_get_config_entry_implementation(
                opp, entry))
        oauth_session = config_entry_oauth2_flow.OAuth2Session(
            opp, entry, implementation)
        auth = AlmondOAuth(entry.data["host"], websession, oauth_session)

    api = WebAlmondAPI(auth)
    agent = AlmondAgent(opp, api, entry)

    # Opp.io does its own configuration.
    if not entry.data.get("is_oppio"):
        # If we're not starting or local, set up Almond right away
        if opp.state != CoreState.not_running or entry.data[
                "type"] == TYPE_LOCAL:
            await _configure_almond_for_ha(opp, entry, api)

        else:
            # OAuth2 implementations can potentially rely on the HA Cloud url.
            # This url is not be available until 30 seconds after boot.

            async def configure_almond(_now):
                try:
                    await _configure_almond_for_ha(opp, entry, api)
                except ConfigEntryNotReady:
                    _LOGGER.warning(
                        "Unable to configure Almond to connect to Open Peer Power"
                    )

            async def almond_opp_start(_event):
                event.async_call_later(opp, ALMOND_SETUP_DELAY,
                                       configure_almond)

            opp.bus.async_listen_once(EVENT_OPENPEERPOWER_START,
                                      almond_opp_start)

    conversation.async_set_agent(opp, agent)
    return True
async def test_oauth_session_with_clock_slightly_out_of_sync(
        opp, flow_handler, local_impl, aioclient_mock):
    """Test the OAuth2 session helper when the remote clock is slightly out of sync."""
    flow_handler.async_register_implementation(opp, local_impl)

    aioclient_mock.post(TOKEN_URL,
                        json={
                            "access_token": ACCESS_TOKEN_2,
                            "expires_in": 19
                        })

    aioclient_mock.post("https://example.com", status=201)

    config_entry = MockConfigEntry(
        domain=TEST_DOMAIN,
        data={
            "auth_implementation": TEST_DOMAIN,
            "token": {
                "refresh_token": REFRESH_TOKEN,
                "access_token": ACCESS_TOKEN_1,
                "expires_in": 19,
                "expires_at": time.time() + 19,  # Forces a refresh,
                "token_type": "bearer",
                "random_other_data": "should_stay",
            },
        },
    )

    now = time.time()
    session = config_entry_oauth2_flow.OAuth2Session(opp, config_entry,
                                                     local_impl)
    resp = await session.async_request("post", "https://example.com")
    assert resp.status == 201

    # Refresh token, make request
    assert len(aioclient_mock.mock_calls) == 2

    assert (aioclient_mock.mock_calls[1][3]["authorization"] ==
            f"Bearer {ACCESS_TOKEN_2}")

    assert config_entry.data["token"]["refresh_token"] == REFRESH_TOKEN
    assert config_entry.data["token"]["access_token"] == ACCESS_TOKEN_2
    assert config_entry.data["token"]["expires_in"] == 19
    assert config_entry.data["token"]["random_other_data"] == "should_stay"
    assert round(config_entry.data["token"]["expires_at"] - now) == 19
예제 #9
0
async def async_setup_entry(opp: OpenPeerPower, entry: ConfigEntry) -> bool:
    """Set up Honeywell Lyric from a config entry."""
    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            opp, entry))

    session = aiohttp_client.async_get_clientsession(opp)
    oauth_session = config_entry_oauth2_flow.OAuth2Session(
        opp, entry, implementation)

    client = ConfigEntryLyricClient(session, oauth_session)

    client_id = opp.data[DOMAIN][CONF_CLIENT_ID]
    lyric = Lyric(client, client_id)

    async def async_update_data() -> Lyric:
        """Fetch data from Lyric."""
        try:
            async with async_timeout.timeout(60):
                await lyric.get_locations()
            return lyric
        except LyricAuthenticationException as exception:
            raise ConfigEntryAuthFailed from exception
        except (LyricException, ClientResponseError) as exception:
            raise UpdateFailed(exception) from exception

    coordinator = DataUpdateCoordinator(
        opp,
        _LOGGER,
        # Name of the data. For logging purposes.
        name="lyric_coordinator",
        update_method=async_update_data,
        # Polling interval. Will only be polled if there are subscribers.
        update_interval=timedelta(seconds=120),
    )

    opp.data[DOMAIN][entry.entry_id] = coordinator

    # Fetch initial data so we have data when entities subscribe
    await coordinator.async_config_entry_first_refresh()

    opp.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
예제 #10
0
async def async_setup_entry(opp: OpenPeerPower, entry: ConfigEntry) -> bool:
    """Set up NEW_NAME from a config entry."""
    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            opp, entry))

    session = config_entry_oauth2_flow.OAuth2Session(opp, entry,
                                                     implementation)

    # If using a requests-based API lib
    opp.data[DOMAIN][entry.entry_id] = api.ConfigEntryAuth(opp, session)

    # If using an aiohttp-based API lib
    opp.data[DOMAIN][entry.entry_id] = api.AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(opp), session)

    opp.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
예제 #11
0
async def async_setup_entry(opp: OpenPeerPower, entry: ConfigEntry):
    """Set up NEW_NAME from a config entry."""
    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            opp, entry))

    session = config_entry_oauth2_flow.OAuth2Session(opp, entry,
                                                     implementation)

    # If using a requests-based API lib
    opp.data[DOMAIN][entry.entry_id] = api.ConfigEntryAuth(opp, entry, session)

    # If using an aiohttp-based API lib
    opp.data[DOMAIN][entry.entry_id] = api.AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(opp), session)

    for component in PLATFORMS:
        opp.async_create_task(
            opp.config_entries.async_forward_entry_setup(entry, component))

    return True
async def test_oauth_session_no_token_refresh_needed(opp, flow_handler,
                                                     local_impl,
                                                     aioclient_mock):
    """Test the OAuth2 session helper when no refresh is needed."""
    flow_handler.async_register_implementation(opp, local_impl)

    aioclient_mock.post("https://example.com", status=201)

    config_entry = MockConfigEntry(
        domain=TEST_DOMAIN,
        data={
            "auth_implementation": TEST_DOMAIN,
            "token": {
                "refresh_token": REFRESH_TOKEN,
                "access_token": ACCESS_TOKEN_1,
                "expires_in": 500,
                "expires_at": time.time() + 500,  # Should NOT refresh
                "token_type": "bearer",
                "random_other_data": "should_stay",
            },
        },
    )

    now = time.time()
    session = config_entry_oauth2_flow.OAuth2Session(opp, config_entry,
                                                     local_impl)
    resp = await session.async_request("post", "https://example.com")
    assert resp.status == 201

    # make request (no refresh)
    assert len(aioclient_mock.mock_calls) == 1

    assert (aioclient_mock.mock_calls[0][3]["authorization"] ==
            f"Bearer {ACCESS_TOKEN_1}")

    assert config_entry.data["token"]["refresh_token"] == REFRESH_TOKEN
    assert config_entry.data["token"]["access_token"] == ACCESS_TOKEN_1
    assert config_entry.data["token"]["expires_in"] == 500
    assert config_entry.data["token"]["random_other_data"] == "should_stay"
    assert round(config_entry.data["token"]["expires_at"] - now) == 500
예제 #13
0
파일: api.py 프로젝트: OpenPeerPower/core
    def __init__(
        self,
        opp: core.OpenPeerPower,
        config_entry: config_entries.ConfigEntry,
        implementation: config_entry_oauth2_flow.AbstractOAuth2Implementation,
    ) -> None:
        """Initialize Smappee Auth."""
        self.opp = opp
        self.config_entry = config_entry
        self.session = config_entry_oauth2_flow.OAuth2Session(
            opp, config_entry, implementation)

        platform_to_farm = {
            "PRODUCTION": 1,
            "ACCEPTANCE": 2,
            "DEVELOPMENT": 3,
        }
        super().__init__(
            None,
            None,
            token=self.session.token,
            farm=platform_to_farm[opp.data[DOMAIN][CONF_PLATFORM]],
        )
예제 #14
0
async def async_setup_entry(opp: OpenPeerPower, entry: ConfigEntry):
    """Set up Netatmo from a config entry."""
    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            opp, entry))

    # Set unique id if non was set (migration)
    if not entry.unique_id:
        opp.config_entries.async_update_entry(entry, unique_id=DOMAIN)

    session = config_entry_oauth2_flow.OAuth2Session(opp, entry,
                                                     implementation)
    opp.data[DOMAIN][entry.entry_id] = {
        AUTH:
        api.AsyncConfigEntryNetatmoAuth(
            aiohttp_client.async_get_clientsession(opp), session)
    }

    data_handler = NetatmoDataHandler(opp, entry)
    await data_handler.async_setup()
    opp.data[DOMAIN][entry.entry_id][DATA_HANDLER] = data_handler

    opp.config_entries.async_setup_platforms(entry, PLATFORMS)

    async def unregister_webhook(_):
        if CONF_WEBHOOK_ID not in entry.data:
            return
        _LOGGER.debug("Unregister Netatmo webhook (%s)",
                      entry.data[CONF_WEBHOOK_ID])
        async_dispatcher_send(
            opp,
            f"signal-{DOMAIN}-webhook-None",
            {
                "type": "None",
                "data": {
                    WEBHOOK_PUSH_TYPE: WEBHOOK_DEACTIVATION
                }
            },
        )
        webhook_unregister(opp, entry.data[CONF_WEBHOOK_ID])
        await opp.data[DOMAIN][entry.entry_id][AUTH].async_dropwebhook()

    async def register_webhook(event):
        if CONF_WEBHOOK_ID not in entry.data:
            data = {**entry.data, CONF_WEBHOOK_ID: secrets.token_hex()}
            opp.config_entries.async_update_entry(entry, data=data)

        if opp.components.cloud.async_active_subscription():
            if CONF_CLOUDHOOK_URL not in entry.data:
                webhook_url = await opp.components.cloud.async_create_cloudhook(
                    entry.data[CONF_WEBHOOK_ID])
                data = {**entry.data, CONF_CLOUDHOOK_URL: webhook_url}
                opp.config_entries.async_update_entry(entry, data=data)
            else:
                webhook_url = entry.data[CONF_CLOUDHOOK_URL]
        else:
            webhook_url = opp.components.webhook.async_generate_url(
                entry.data[CONF_WEBHOOK_ID])

        if entry.data[
                "auth_implementation"] == cloud.DOMAIN and not webhook_url.startswith(
                    "https://"):
            _LOGGER.warning(
                "Webhook not registered - "
                "https and port 443 is required to register the webhook")
            return

        try:
            webhook_register(
                opp,
                DOMAIN,
                "Netatmo",
                entry.data[CONF_WEBHOOK_ID],
                async_handle_webhook,
            )

            async def handle_event(event):
                """Handle webhook events."""
                if event["data"][WEBHOOK_PUSH_TYPE] == WEBHOOK_ACTIVATION:
                    if activation_listener is not None:
                        activation_listener()

                    if activation_timeout is not None:
                        activation_timeout()

            activation_listener = async_dispatcher_connect(
                opp,
                f"signal-{DOMAIN}-webhook-None",
                handle_event,
            )

            activation_timeout = async_call_later(opp, 30, unregister_webhook)

            await opp.data[DOMAIN][entry.entry_id
                                   ][AUTH].async_addwebhook(webhook_url)
            _LOGGER.info("Register Netatmo webhook: %s", webhook_url)
        except pyatmo.ApiError as err:
            _LOGGER.error("Error during webhook registration - %s", err)

        entry.async_on_unload(
            opp.bus.async_listen_once(EVENT_OPENPEERPOWER_STOP,
                                      unregister_webhook))

    if opp.state == CoreState.running:
        await register_webhook(None)
    else:
        opp.bus.async_listen_once(EVENT_OPENPEERPOWER_START, register_webhook)

    opp.services.async_register(DOMAIN, "register_webhook", register_webhook)
    opp.services.async_register(DOMAIN, "unregister_webhook",
                                unregister_webhook)

    entry.add_update_listener(async_config_entry_updated)

    return True