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

Commit 5d08fe2

Browse files
committed
Block login if a user requires approval and the server is configured to do so
1 parent 685f76f commit 5d08fe2

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

synapse/handlers/auth.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,17 @@ async def check_user_exists(self, user_id: str) -> Optional[str]:
10101010
return res[0]
10111011
return None
10121012

1013+
async def is_user_approved(self, user_id: str) -> bool:
1014+
"""Checks if a user is approved and therefore can be allowed to log in.
1015+
1016+
Args:
1017+
user_id: the user to check the approval status of.
1018+
1019+
Returns:
1020+
A boolean that is True if the user is approved, False otherwise.
1021+
"""
1022+
return await self.store.is_user_approved(user_id)
1023+
10131024
async def _find_user_id_and_pwd_hash(
10141025
self, user_id: str
10151026
) -> Optional[Tuple[str, str]]:

synapse/rest/client/login.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ def __init__(self, hs: "HomeServer"):
9292
hs.config.registration.refreshable_access_token_lifetime is not None
9393
)
9494

95+
# Whether we need to check if the user has been approved or not.
96+
self._require_approval = (
97+
hs.config.experimental.msc3866.enabled
98+
and hs.config.experimental.msc3866.require_approval_for_new_accounts
99+
)
100+
95101
self.auth = hs.get_auth()
96102

97103
self.clock = hs.get_clock()
@@ -220,6 +226,15 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, LoginResponse]:
220226
except KeyError:
221227
raise SynapseError(400, "Missing JSON keys.")
222228

229+
if self._require_approval:
230+
approved = await self.auth_handler.is_user_approved(result["user_id"])
231+
if not approved:
232+
raise SynapseError(
233+
code=403,
234+
errcode=Codes.USER_AWAITING_APPROVAL,
235+
msg="This account is pending approval by a server administrator.",
236+
)
237+
223238
well_known_data = self._well_known_builder.get_well_known()
224239
if well_known_data:
225240
result["well_known"] = well_known_data

tests/rest/client/test_login.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
from twisted.web.resource import Resource
2424

2525
import synapse.rest.admin
26+
from synapse.api.constants import LoginType
27+
from synapse.api.errors import Codes
2628
from synapse.appservice import ApplicationService
2729
from synapse.rest.client import devices, login, logout, register
2830
from synapse.rest.client.account import WhoamiRestServlet
@@ -94,6 +96,7 @@ class LoginRestServletTestCase(unittest.HomeserverTestCase):
9496
logout.register_servlets,
9597
devices.register_servlets,
9698
lambda hs, http_server: WhoamiRestServlet(hs).register(http_server),
99+
register.register_servlets,
97100
]
98101

99102
def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:
@@ -406,6 +409,38 @@ def test_login_with_overly_long_device_id_fails(self) -> None:
406409
self.assertEqual(channel.code, 400)
407410
self.assertEqual(channel.json_body["errcode"], "M_INVALID_PARAM")
408411

412+
@override_config(
413+
{
414+
"experimental_features": {
415+
"msc3866": {
416+
"enabled": True,
417+
"require_approval_for_new_accounts": True,
418+
}
419+
}
420+
}
421+
)
422+
def test_require_approval(self) -> None:
423+
channel = self.make_request(
424+
"POST",
425+
"register",
426+
{
427+
"username": "kermit",
428+
"password": "monkey",
429+
"auth": {"type": LoginType.DUMMY},
430+
},
431+
)
432+
self.assertEqual(403, channel.code, channel.result)
433+
self.assertEqual(Codes.USER_AWAITING_APPROVAL, channel.json_body["errcode"])
434+
435+
params = {
436+
"type": LoginType.PASSWORD,
437+
"identifier": {"type": "m.id.user", "user": "kermit"},
438+
"password": "monkey",
439+
}
440+
channel = self.make_request("POST", LOGIN_URL, params)
441+
self.assertEqual(403, channel.code, channel.result)
442+
self.assertEqual(Codes.USER_AWAITING_APPROVAL, channel.json_body["errcode"])
443+
409444

410445
@skip_unless(has_saml2 and HAS_OIDC, "Requires SAML2 and OIDC")
411446
class MultiSSOTestCase(unittest.HomeserverTestCase):

0 commit comments

Comments
 (0)