Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Update the set password API to optionally logout other devices. #7085

Merged
merged 4 commits into from
Mar 18, 2020
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
1 change: 1 addition & 0 deletions changelog.d/7085.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add an optional parameter to control whether other sessions are logged out when a user's password is modified.
6 changes: 5 additions & 1 deletion docs/admin_api/user_admin_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The parameter ``threepids`` is optional.
The parameter ``avatar_url`` is optional.
The parameter ``admin`` is optional and defaults to 'false'.
The parameter ``deactivated`` is optional and defaults to 'false'.
The parameter ``password`` is optional. If provided the user's password is updated and all devices are logged out.
If the user already exists then optional parameters default to the current value.

List Accounts
Expand Down Expand Up @@ -168,11 +169,14 @@ with a body of:
.. code:: json

{
"new_password": "<secret>"
"new_password": "<secret>",
"logout_devices": true,
}

including an ``access_token`` of a server admin.

The parameter ``new_password`` is required.
The parameter ``logout_devices`` is optional and defaults to ``true``.

Get whether a user is a server administrator or not
===================================================
Expand Down
41 changes: 25 additions & 16 deletions synapse/handlers/set_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from typing import Optional

from twisted.internet import defer

from synapse.api.errors import Codes, StoreError, SynapseError
from synapse.types import Requester

from ._base import BaseHandler

Expand All @@ -32,14 +34,17 @@ def __init__(self, hs):
self._device_handler = hs.get_device_handler()

@defer.inlineCallbacks
def set_password(self, user_id, newpassword, requester=None):
def set_password(
self,
user_id: str,
new_password: str,
logout_devices: bool,
clokep marked this conversation as resolved.
Show resolved Hide resolved
requester: Optional[Requester] = None,
):
if not self.hs.config.password_localdb_enabled:
raise SynapseError(403, "Password change disabled", errcode=Codes.FORBIDDEN)

password_hash = yield self._auth_handler.hash(newpassword)

except_device_id = requester.device_id if requester else None
except_access_token_id = requester.access_token_id if requester else None
password_hash = yield self._auth_handler.hash(new_password)

try:
yield self.store.user_set_password_hash(user_id, password_hash)
Expand All @@ -48,14 +53,18 @@ def set_password(self, user_id, newpassword, requester=None):
raise SynapseError(404, "Unknown user", Codes.NOT_FOUND)
raise e

# we want to log out all of the user's other sessions. First delete
# all his other devices.
yield self._device_handler.delete_all_devices_for_user(
user_id, except_device_id=except_device_id
)

# and now delete any access tokens which weren't associated with
# devices (or were associated with this device).
yield self._auth_handler.delete_access_tokens_for_user(
user_id, except_token_id=except_access_token_id
)
# Optionally, log out all of the user's other sessions.
if logout_devices:
except_device_id = requester.device_id if requester else None
except_access_token_id = requester.access_token_id if requester else None

# First delete all of their other devices.
yield self._device_handler.delete_all_devices_for_user(
user_id, except_device_id=except_device_id
)

# and now delete any access tokens which weren't associated with
# devices (or were associated with this device).
yield self._auth_handler.delete_access_tokens_for_user(
user_id, except_token_id=except_access_token_id
)
6 changes: 4 additions & 2 deletions synapse/rest/admin/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,9 @@ async def on_PUT(self, request, user_id):
raise SynapseError(400, "Invalid password")
else:
new_password = body["password"]
logout_devices = True
await self.set_password_handler.set_password(
target_user.to_string(), new_password, requester
target_user.to_string(), new_password, logout_devices, requester
)

if "deactivated" in body:
Expand Down Expand Up @@ -536,9 +537,10 @@ async def on_POST(self, request, target_user_id):
params = parse_json_object_from_request(request)
assert_params_in_dict(params, ["new_password"])
new_password = params["new_password"]
logout_devices = params.get("logout_devices", True)

await self._set_password_handler.set_password(
target_user_id, new_password, requester
target_user_id, new_password, logout_devices, requester
)
return 200, {}

Expand Down
5 changes: 4 additions & 1 deletion synapse/rest/client/v2_alpha/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,11 @@ async def on_POST(self, request):

assert_params_in_dict(params, ["new_password"])
new_password = params["new_password"]
logout_devices = params.get("logout_devices", True)

await self._set_password_handler.set_password(user_id, new_password, requester)
await self._set_password_handler.set_password(
user_id, new_password, logout_devices, requester
)

return 200, {}

Expand Down