mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-08-03 18:54:13 -04:00
Allow admins to require a manual approval process before new accounts can be used (using MSC3866) (#13556)
This commit is contained in:
parent
8625ad8099
commit
be76cd8200
21 changed files with 731 additions and 34 deletions
|
@ -20,7 +20,8 @@ from twisted.test.proto_helpers import MemoryReactor
|
|||
from twisted.web.resource import Resource
|
||||
|
||||
import synapse.rest.admin
|
||||
from synapse.api.constants import LoginType
|
||||
from synapse.api.constants import ApprovalNoticeMedium, LoginType
|
||||
from synapse.api.errors import Codes
|
||||
from synapse.handlers.ui_auth.checkers import UserInteractiveAuthChecker
|
||||
from synapse.rest.client import account, auth, devices, login, logout, register
|
||||
from synapse.rest.synapse.client import build_synapse_client_resource_tree
|
||||
|
@ -567,6 +568,36 @@ class UIAuthTests(unittest.HomeserverTestCase):
|
|||
body={"auth": {"session": session_id}},
|
||||
)
|
||||
|
||||
@skip_unless(HAS_OIDC, "requires OIDC")
|
||||
@override_config(
|
||||
{
|
||||
"oidc_config": TEST_OIDC_CONFIG,
|
||||
"experimental_features": {
|
||||
"msc3866": {
|
||||
"enabled": True,
|
||||
"require_approval_for_new_accounts": True,
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
def test_sso_not_approved(self) -> None:
|
||||
"""Tests that if we register a user via SSO while requiring approval for new
|
||||
accounts, we still raise the correct error before logging the user in.
|
||||
"""
|
||||
login_resp = self.helper.login_via_oidc("username", expected_status=403)
|
||||
|
||||
self.assertEqual(login_resp["errcode"], Codes.USER_AWAITING_APPROVAL)
|
||||
self.assertEqual(
|
||||
ApprovalNoticeMedium.NONE, login_resp["approval_notice_medium"]
|
||||
)
|
||||
|
||||
# Check that we didn't register a device for the user during the login attempt.
|
||||
devices = self.get_success(
|
||||
self.hs.get_datastores().main.get_devices_by_user("@username:test")
|
||||
)
|
||||
|
||||
self.assertEqual(len(devices), 0)
|
||||
|
||||
|
||||
class RefreshAuthTests(unittest.HomeserverTestCase):
|
||||
servlets = [
|
||||
|
|
|
@ -23,6 +23,8 @@ from twisted.test.proto_helpers import MemoryReactor
|
|||
from twisted.web.resource import Resource
|
||||
|
||||
import synapse.rest.admin
|
||||
from synapse.api.constants import ApprovalNoticeMedium, LoginType
|
||||
from synapse.api.errors import Codes
|
||||
from synapse.appservice import ApplicationService
|
||||
from synapse.rest.client import devices, login, logout, register
|
||||
from synapse.rest.client.account import WhoamiRestServlet
|
||||
|
@ -94,6 +96,7 @@ class LoginRestServletTestCase(unittest.HomeserverTestCase):
|
|||
logout.register_servlets,
|
||||
devices.register_servlets,
|
||||
lambda hs, http_server: WhoamiRestServlet(hs).register(http_server),
|
||||
register.register_servlets,
|
||||
]
|
||||
|
||||
def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:
|
||||
|
@ -406,6 +409,44 @@ class LoginRestServletTestCase(unittest.HomeserverTestCase):
|
|||
self.assertEqual(channel.code, 400)
|
||||
self.assertEqual(channel.json_body["errcode"], "M_INVALID_PARAM")
|
||||
|
||||
@override_config(
|
||||
{
|
||||
"experimental_features": {
|
||||
"msc3866": {
|
||||
"enabled": True,
|
||||
"require_approval_for_new_accounts": True,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_require_approval(self) -> None:
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"register",
|
||||
{
|
||||
"username": "kermit",
|
||||
"password": "monkey",
|
||||
"auth": {"type": LoginType.DUMMY},
|
||||
},
|
||||
)
|
||||
self.assertEqual(403, channel.code, channel.result)
|
||||
self.assertEqual(Codes.USER_AWAITING_APPROVAL, channel.json_body["errcode"])
|
||||
self.assertEqual(
|
||||
ApprovalNoticeMedium.NONE, channel.json_body["approval_notice_medium"]
|
||||
)
|
||||
|
||||
params = {
|
||||
"type": LoginType.PASSWORD,
|
||||
"identifier": {"type": "m.id.user", "user": "kermit"},
|
||||
"password": "monkey",
|
||||
}
|
||||
channel = self.make_request("POST", LOGIN_URL, params)
|
||||
self.assertEqual(403, channel.code, channel.result)
|
||||
self.assertEqual(Codes.USER_AWAITING_APPROVAL, channel.json_body["errcode"])
|
||||
self.assertEqual(
|
||||
ApprovalNoticeMedium.NONE, channel.json_body["approval_notice_medium"]
|
||||
)
|
||||
|
||||
|
||||
@skip_unless(has_saml2 and HAS_OIDC, "Requires SAML2 and OIDC")
|
||||
class MultiSSOTestCase(unittest.HomeserverTestCase):
|
||||
|
|
|
@ -22,7 +22,11 @@ import pkg_resources
|
|||
from twisted.test.proto_helpers import MemoryReactor
|
||||
|
||||
import synapse.rest.admin
|
||||
from synapse.api.constants import APP_SERVICE_REGISTRATION_TYPE, LoginType
|
||||
from synapse.api.constants import (
|
||||
APP_SERVICE_REGISTRATION_TYPE,
|
||||
ApprovalNoticeMedium,
|
||||
LoginType,
|
||||
)
|
||||
from synapse.api.errors import Codes
|
||||
from synapse.appservice import ApplicationService
|
||||
from synapse.rest.client import account, account_validity, login, logout, register, sync
|
||||
|
@ -765,6 +769,32 @@ class RegisterRestServletTestCase(unittest.HomeserverTestCase):
|
|||
self.assertEqual(channel.code, 400, channel.json_body)
|
||||
self.assertEqual(channel.json_body["errcode"], Codes.USER_IN_USE)
|
||||
|
||||
@override_config(
|
||||
{
|
||||
"experimental_features": {
|
||||
"msc3866": {
|
||||
"enabled": True,
|
||||
"require_approval_for_new_accounts": True,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_require_approval(self) -> None:
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"register",
|
||||
{
|
||||
"username": "kermit",
|
||||
"password": "monkey",
|
||||
"auth": {"type": LoginType.DUMMY},
|
||||
},
|
||||
)
|
||||
self.assertEqual(403, channel.code, channel.result)
|
||||
self.assertEqual(Codes.USER_AWAITING_APPROVAL, channel.json_body["errcode"])
|
||||
self.assertEqual(
|
||||
ApprovalNoticeMedium.NONE, channel.json_body["approval_notice_medium"]
|
||||
)
|
||||
|
||||
|
||||
class AccountValidityTestCase(unittest.HomeserverTestCase):
|
||||
|
||||
|
|
|
@ -543,8 +543,12 @@ class RestHelper:
|
|||
|
||||
return channel.json_body
|
||||
|
||||
def login_via_oidc(self, remote_user_id: str) -> JsonDict:
|
||||
"""Log in (as a new user) via OIDC
|
||||
def login_via_oidc(
|
||||
self,
|
||||
remote_user_id: str,
|
||||
expected_status: int = 200,
|
||||
) -> JsonDict:
|
||||
"""Log in via OIDC
|
||||
|
||||
Returns the result of the final token login.
|
||||
|
||||
|
@ -578,7 +582,9 @@ class RestHelper:
|
|||
"/login",
|
||||
content={"type": "m.login.token", "token": login_token},
|
||||
)
|
||||
assert channel.code == HTTPStatus.OK
|
||||
assert (
|
||||
channel.code == expected_status
|
||||
), f"unexpected status in response: {channel.code}"
|
||||
return channel.json_body
|
||||
|
||||
def auth_via_oidc(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue