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:
Jerad Meisner 2018-07-19 00:39:51 -07:00 committed by Paulus Schoutsen
parent 5a1360678b
commit 9c337bc621
2 changed files with 128 additions and 0 deletions

View file

@ -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())

View file

@ -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'