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

Return m.change_password.enabled=false if local database is disabled #9588

Merged
merged 7 commits into from
Mar 16, 2021
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/9588.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix the `/capabilities` endpoint to return `m.change_password` as disabled if the local password database is not used for authentication. Contributed by @dklimpel.
13 changes: 13 additions & 0 deletions synapse/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,19 @@ async def _find_user_id_and_pwd_hash(
)
return result

def can_change_password(self) -> bool:
"""Get whether users on this server are allowed to change or set a password.

Both `config.password_enabled` and `config.password_localdb_enabled` must be true.

Note that any account (even SSO accounts) are allowed to add passwords if the above
is true.

Returns:
Whether users on this server are allowed to change or set a password
"""
return self._password_enabled and self._password_localdb_enabled

def get_supported_login_types(self) -> Iterable[str]:
"""Get a the login types supported for the /login API

Expand Down
23 changes: 12 additions & 11 deletions synapse/rest/client/v2_alpha/capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from typing import TYPE_CHECKING, Tuple

from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.http.servlet import RestServlet
from synapse.http.site import SynapseRequest
from synapse.types import JsonDict

from ._base import client_patterns

if TYPE_CHECKING:
from synapse.server import HomeServer

logger = logging.getLogger(__name__)


Expand All @@ -27,21 +33,16 @@ class CapabilitiesRestServlet(RestServlet):

PATTERNS = client_patterns("/capabilities$")

def __init__(self, hs):
"""
Args:
hs (synapse.server.HomeServer): server
"""
def __init__(self, hs: "HomeServer"):
super().__init__()
self.hs = hs
self.config = hs.config
self.auth = hs.get_auth()
self.store = hs.get_datastore()
self.auth_handler = hs.get_auth_handler()

async def on_GET(self, request):
requester = await self.auth.get_user_by_req(request, allow_guest=True)
user = await self.store.get_user_by_id(requester.user.to_string())
change_password = bool(user["password_hash"])
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
await self.auth.get_user_by_req(request, allow_guest=True)
change_password = self.auth_handler.can_change_password()

response = {
"capabilities": {
Expand All @@ -58,5 +59,5 @@ async def on_GET(self, request):
return 200, response


def register_servlets(hs, http_server):
def register_servlets(hs: "HomeServer", http_server):
CapabilitiesRestServlet(hs).register(http_server)
36 changes: 32 additions & 4 deletions tests/rest/client/v2_alpha/test_capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from synapse.rest.client.v2_alpha import capabilities

from tests import unittest
from tests.unittest import override_config


class CapabilitiesTestCase(unittest.HomeserverTestCase):
Expand All @@ -33,6 +34,7 @@ def make_homeserver(self, reactor, clock):
hs = self.setup_test_homeserver()
self.store = hs.get_datastore()
self.config = hs.config
self.auth_handler = hs.get_auth_handler()
return hs

def test_check_auth_required(self):
Expand All @@ -56,7 +58,7 @@ def test_get_room_version_capabilities(self):
capabilities["m.room_versions"]["default"],
)

def test_get_change_password_capabilities(self):
def test_get_change_password_capabilities_password_login(self):
localpart = "user"
password = "pass"
user = self.register_user(localpart, password)
Expand All @@ -66,10 +68,36 @@ def test_get_change_password_capabilities(self):
capabilities = channel.json_body["capabilities"]

self.assertEqual(channel.code, 200)

# Test case where password is handled outside of Synapse
clokep marked this conversation as resolved.
Show resolved Hide resolved
self.assertTrue(capabilities["m.change_password"]["enabled"])
self.get_success(self.store.user_set_password_hash(user, None))

@override_config({"password_config": {"localdb_enabled": False}})
def test_get_change_password_capabilities_localdb_disabled(self):
localpart = "user"
password = "pass"
user = self.register_user(localpart, password)
access_token = self.get_success(
self.auth_handler.get_access_token_for_user_id(
user, device_id=None, valid_until_ms=None
)
)

channel = self.make_request("GET", self.url, access_token=access_token)
capabilities = channel.json_body["capabilities"]

self.assertEqual(channel.code, 200)
self.assertFalse(capabilities["m.change_password"]["enabled"])

@override_config({"password_config": {"enabled": False}})
def test_get_change_password_capabilities_password_disabled(self):
localpart = "user"
password = "pass"
user = self.register_user(localpart, password)
access_token = self.get_success(
self.auth_handler.get_access_token_for_user_id(
user, device_id=None, valid_until_ms=None
)
)

channel = self.make_request("GET", self.url, access_token=access_token)
capabilities = channel.json_body["capabilities"]

Expand Down