Abort config flow when invalid token is received (#101642)

This commit is contained in:
Joost Lekkerkerker 2023-10-08 13:32:35 +02:00 committed by GitHub
parent 3155e62510
commit faea3b1634
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 3 deletions

View File

@ -16,7 +16,8 @@
"authorize_url_timeout": "[%key:common::config_flow::abort::oauth2_authorize_url_timeout%]",
"missing_configuration": "[%key:common::config_flow::abort::oauth2_missing_configuration%]",
"already_configured": "Configuration updated for profile.",
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]"
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]",
"oauth_error": "[%key:common::config_flow::abort::oauth2_error%]"
},
"create_entry": {
"default": "Successfully authenticated with Withings."

View File

@ -319,6 +319,10 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
_LOGGER.error("Timeout resolving OAuth token: %s", err)
return self.async_abort(reason="oauth2_timeout")
if "expires_in" not in token:
_LOGGER.warning("Invalid token: %s", token)
return self.async_abort(reason="oauth_error")
# Force int for non-compliant oauth2 providers
try:
token["expires_in"] = int(token["expires_in"])

View File

@ -253,3 +253,54 @@ async def test_config_reauth_wrong_account(
assert result
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "wrong_account"
async def test_config_flow_with_invalid_credentials(
hass: HomeAssistant,
hass_client_no_auth: ClientSessionGenerator,
aioclient_mock: AiohttpClientMocker,
polling_config_entry: MockConfigEntry,
withings: AsyncMock,
current_request_with_host,
) -> None:
"""Test flow with invalid credentials."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
state = config_entry_oauth2_flow._encode_jwt(
hass,
{
"flow_id": result["flow_id"],
"redirect_uri": "https://example.com/auth/external/callback",
},
)
assert result["type"] == FlowResultType.EXTERNAL_STEP
assert result["url"] == (
"https://account.withings.com/oauth2_user/authorize2?"
f"response_type=code&client_id={CLIENT_ID}&"
"redirect_uri=https://example.com/auth/external/callback&"
f"state={state}"
"&scope=user.info,user.metrics,user.activity,user.sleepevents"
)
client = await hass_client_no_auth()
resp = await client.get(f"/auth/external/callback?code=abcd&state={state}")
assert resp.status == 200
assert resp.headers["content-type"] == "text/html; charset=utf-8"
aioclient_mock.clear_requests()
aioclient_mock.post(
"https://wbsapi.withings.net/v2/oauth2",
json={
"body": {
"status": 503,
"error": "Invalid Params: invalid client id/secret",
},
},
)
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "oauth_error"

View File

@ -167,6 +167,7 @@ async def test_abort_if_no_url_available(
assert result["reason"] == "no_url_available"
@pytest.mark.parametrize("expires_in_dict", [{}, {"expires_in": "badnumber"}])
async def test_abort_if_oauth_error(
hass: HomeAssistant,
flow_handler,
@ -174,6 +175,7 @@ async def test_abort_if_oauth_error(
hass_client_no_auth: ClientSessionGenerator,
aioclient_mock: AiohttpClientMocker,
current_request_with_host: None,
expires_in_dict: dict[str, str],
) -> None:
"""Check bad oauth token."""
flow_handler.async_register_implementation(hass, local_impl)
@ -219,8 +221,8 @@ async def test_abort_if_oauth_error(
"refresh_token": REFRESH_TOKEN,
"access_token": ACCESS_TOKEN_1,
"type": "bearer",
"expires_in": "badnumber",
},
}
| expires_in_dict,
)
result = await hass.config_entries.flow.async_configure(result["flow_id"])