Added WS endpoint for changing homeassistant password. (#15527)
* Added WS endpoint for changing homeassistant password. * Remove change password helper. Don't require current password. * Restore current password verification. * Added tests. * Use correct send method
This commit is contained in:
parent
5a1360678b
commit
9c337bc621
2 changed files with 128 additions and 0 deletions
|
@ -20,6 +20,13 @@ SCHEMA_WS_DELETE = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
|
|||
vol.Required('username'): str,
|
||||
})
|
||||
|
||||
WS_TYPE_CHANGE_PASSWORD = 'config/auth_provider/homeassistant/change_password'
|
||||
SCHEMA_WS_CHANGE_PASSWORD = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
|
||||
vol.Required('type'): WS_TYPE_CHANGE_PASSWORD,
|
||||
vol.Required('current_password'): str,
|
||||
vol.Required('new_password'): str
|
||||
})
|
||||
|
||||
|
||||
async def async_setup(hass):
|
||||
"""Enable the Home Assistant views."""
|
||||
|
@ -31,6 +38,10 @@ async def async_setup(hass):
|
|||
WS_TYPE_DELETE, websocket_delete,
|
||||
SCHEMA_WS_DELETE
|
||||
)
|
||||
hass.components.websocket_api.async_register_command(
|
||||
WS_TYPE_CHANGE_PASSWORD, websocket_change_password,
|
||||
SCHEMA_WS_CHANGE_PASSWORD
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
@ -118,3 +129,46 @@ def websocket_delete(hass, connection, msg):
|
|||
websocket_api.result_message(msg['id']))
|
||||
|
||||
hass.async_add_job(delete_creds())
|
||||
|
||||
|
||||
@callback
|
||||
def websocket_change_password(hass, connection, msg):
|
||||
"""Change user password."""
|
||||
async def change_password():
|
||||
"""Change user password."""
|
||||
user = connection.request.get('hass_user')
|
||||
if user is None:
|
||||
connection.send_message_outside(websocket_api.error_message(
|
||||
msg['id'], 'user_not_found', 'User not found'))
|
||||
return
|
||||
|
||||
provider = _get_provider(hass)
|
||||
await provider.async_initialize()
|
||||
|
||||
username = None
|
||||
for credential in user.credentials:
|
||||
if credential.auth_provider_type == provider.type:
|
||||
username = credential.data['username']
|
||||
break
|
||||
|
||||
if username is None:
|
||||
connection.send_message_outside(websocket_api.error_message(
|
||||
msg['id'], 'credentials_not_found', 'Credentials not found'))
|
||||
return
|
||||
|
||||
try:
|
||||
await provider.async_validate_login(
|
||||
username, msg['current_password'])
|
||||
except auth_ha.InvalidAuth:
|
||||
connection.send_message_outside(websocket_api.error_message(
|
||||
msg['id'], 'invalid_password', 'Invalid password'))
|
||||
return
|
||||
|
||||
await hass.async_add_executor_job(
|
||||
provider.data.change_password, username, msg['new_password'])
|
||||
await provider.data.async_save()
|
||||
|
||||
connection.send_message_outside(
|
||||
websocket_api.result_message(msg['id']))
|
||||
|
||||
hass.async_add_job(change_password())
|
||||
|
|
|
@ -227,3 +227,77 @@ async def test_delete_unknown_auth(hass, hass_ws_client, hass_access_token):
|
|||
result = await client.receive_json()
|
||||
assert not result['success'], result
|
||||
assert result['error']['code'] == 'auth_not_found'
|
||||
|
||||
|
||||
async def test_change_password(hass, hass_ws_client, hass_access_token):
|
||||
"""Test that change password succeeds with valid password."""
|
||||
provider = hass.auth.auth_providers[0]
|
||||
await provider.async_initialize()
|
||||
await hass.async_add_executor_job(
|
||||
provider.data.add_auth, 'test-user', 'test-pass')
|
||||
|
||||
credentials = await provider.async_get_or_create_credentials({
|
||||
'username': 'test-user'
|
||||
})
|
||||
|
||||
user = hass_access_token.refresh_token.user
|
||||
await hass.auth.async_link_user(user, credentials)
|
||||
|
||||
client = await hass_ws_client(hass, hass_access_token)
|
||||
await client.send_json({
|
||||
'id': 6,
|
||||
'type': auth_ha.WS_TYPE_CHANGE_PASSWORD,
|
||||
'current_password': 'test-pass',
|
||||
'new_password': 'new-pass'
|
||||
})
|
||||
|
||||
result = await client.receive_json()
|
||||
assert result['success'], result
|
||||
await provider.async_validate_login('test-user', 'new-pass')
|
||||
|
||||
|
||||
async def test_change_password_wrong_pw(hass, hass_ws_client,
|
||||
hass_access_token):
|
||||
"""Test that change password fails with invalid password."""
|
||||
provider = hass.auth.auth_providers[0]
|
||||
await provider.async_initialize()
|
||||
await hass.async_add_executor_job(
|
||||
provider.data.add_auth, 'test-user', 'test-pass')
|
||||
|
||||
credentials = await provider.async_get_or_create_credentials({
|
||||
'username': 'test-user'
|
||||
})
|
||||
|
||||
user = hass_access_token.refresh_token.user
|
||||
await hass.auth.async_link_user(user, credentials)
|
||||
|
||||
client = await hass_ws_client(hass, hass_access_token)
|
||||
await client.send_json({
|
||||
'id': 6,
|
||||
'type': auth_ha.WS_TYPE_CHANGE_PASSWORD,
|
||||
'current_password': 'wrong-pass',
|
||||
'new_password': 'new-pass'
|
||||
})
|
||||
|
||||
result = await client.receive_json()
|
||||
assert not result['success'], result
|
||||
assert result['error']['code'] == 'invalid_password'
|
||||
with pytest.raises(prov_ha.InvalidAuth):
|
||||
await provider.async_validate_login('test-user', 'new-pass')
|
||||
|
||||
|
||||
async def test_change_password_no_creds(hass, hass_ws_client,
|
||||
hass_access_token):
|
||||
"""Test that change password fails with no credentials."""
|
||||
client = await hass_ws_client(hass, hass_access_token)
|
||||
|
||||
await client.send_json({
|
||||
'id': 6,
|
||||
'type': auth_ha.WS_TYPE_CHANGE_PASSWORD,
|
||||
'current_password': 'test-pass',
|
||||
'new_password': 'new-pass'
|
||||
})
|
||||
|
||||
result = await client.receive_json()
|
||||
assert not result['success'], result
|
||||
assert result['error']['code'] == 'credentials_not_found'
|
||||
|
|
Loading…
Add table
Reference in a new issue