Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions homeassistant/components/config/auth_provider_homeassistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
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."""
Expand All @@ -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


Expand Down Expand Up @@ -118,3 +129,46 @@ async def delete_creds():
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']
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a break

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())
74 changes: 74 additions & 0 deletions tests/components/config/test_auth_provider_homeassistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'