This repository was archived by the owner on Apr 26, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Allow new users to be registered via the admin API even if the monthly active user limit has been reached #7263
Merged
richvdh
merged 13 commits into
matrix-org:develop
from
dklimpel:admin_api_create_user_mau
Jun 5, 2020
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
d813e69
Sync develop
dklimpel 8f75ac6
Create user with admin API if MAU is reached
dklimpel 26bddb3
Sync develop for renew tests
dklimpel b1ad0f0
Add parameter 'by_admin' to register_user
dklimpel 4c2d3a7
Update tests
dklimpel ae0eff0
Update tests after review
dklimpel 75975e0
Merge synapse/develop
dklimpel b3b347b
Update MAU limit tests
dklimpel 9c17aa2
Merge branch 'develop' into admin_api_create_user_mau
dklimpel cf1c9ea
Apply suggestions from code review
dklimpel b9d9bec
code style
dklimpel d3b0a82
Update tests/rest/admin/test_user.py
richvdh d47b564
Update 7263.bugfix
richvdh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Allow new users to be registered via the admin API even if the monthly active user limit has been reached. Contributed by @dkimpel. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,9 +22,12 @@ | |
|
||
import synapse.rest.admin | ||
from synapse.api.constants import UserTypes | ||
from synapse.api.errors import HttpResponseException, ResourceLimitError | ||
from synapse.rest.client.v1 import login | ||
from synapse.rest.client.v2_alpha import sync | ||
|
||
from tests import unittest | ||
from tests.unittest import override_config | ||
|
||
|
||
class UserRegisterTestCase(unittest.HomeserverTestCase): | ||
|
@@ -320,6 +323,52 @@ def nonce(): | |
self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"]) | ||
self.assertEqual("Invalid user type", channel.json_body["error"]) | ||
|
||
@override_config( | ||
{"limit_usage_by_mau": True, "max_mau_value": 2, "mau_trial_days": 0} | ||
) | ||
def test_register_mau_limit_reached(self): | ||
""" | ||
Check we can register a user via the shared secret registration API | ||
even if the MAU limit is reached. | ||
""" | ||
handler = self.hs.get_registration_handler() | ||
store = self.hs.get_datastore() | ||
|
||
# Set monthly active users to the limit | ||
store.get_monthly_active_count = Mock(return_value=self.hs.config.max_mau_value) | ||
# Check that the blocking of monthly active users is working as expected | ||
# The registration of a new user fails due to the limit | ||
self.get_failure( | ||
handler.register_user(localpart="local_part"), ResourceLimitError | ||
) | ||
|
||
# Register new user with admin API | ||
request, channel = self.make_request("GET", self.url) | ||
self.render(request) | ||
nonce = channel.json_body["nonce"] | ||
|
||
want_mac = hmac.new(key=b"shared", digestmod=hashlib.sha1) | ||
want_mac.update( | ||
nonce.encode("ascii") + b"\x00bob\x00abc123\x00admin\x00support" | ||
) | ||
want_mac = want_mac.hexdigest() | ||
|
||
body = json.dumps( | ||
{ | ||
"nonce": nonce, | ||
"username": "bob", | ||
"password": "abc123", | ||
"admin": True, | ||
"user_type": UserTypes.SUPPORT, | ||
"mac": want_mac, | ||
} | ||
) | ||
request, channel = self.make_request("POST", self.url, body.encode("utf8")) | ||
self.render(request) | ||
|
||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) | ||
self.assertEqual("@bob:test", channel.json_body["user_id"]) | ||
|
||
|
||
class UsersListTestCase(unittest.HomeserverTestCase): | ||
|
||
|
@@ -368,6 +417,7 @@ class UserRestTestCase(unittest.HomeserverTestCase): | |
servlets = [ | ||
synapse.rest.admin.register_servlets, | ||
login.register_servlets, | ||
sync.register_servlets, | ||
] | ||
|
||
def prepare(self, reactor, clock, hs): | ||
|
@@ -386,7 +436,6 @@ def test_requester_is_no_admin(self): | |
""" | ||
If the user is not a server admin, an error is returned. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
request, channel = self.make_request( | ||
|
@@ -409,7 +458,6 @@ def test_user_does_not_exist(self): | |
""" | ||
Tests that a lookup for a user that does not exist returns a 404 | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
|
||
request, channel = self.make_request( | ||
"GET", | ||
|
@@ -425,7 +473,6 @@ def test_create_server_admin(self): | |
""" | ||
Check that a new admin user is created successfully. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
# Create user (server admin) | ||
|
@@ -473,7 +520,6 @@ def test_create_user(self): | |
""" | ||
Check that a new regular user is created successfully. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
# Create user | ||
|
@@ -516,14 +562,114 @@ def test_create_user(self): | |
self.assertEqual(False, channel.json_body["is_guest"]) | ||
self.assertEqual(False, channel.json_body["deactivated"]) | ||
|
||
@override_config( | ||
{"limit_usage_by_mau": True, "max_mau_value": 2, "mau_trial_days": 0} | ||
) | ||
def test_create_user_mau_limit_reached_active_admin(self): | ||
""" | ||
Check that an admin can register a new user via the admin API | ||
even if the MAU limit is reached. | ||
Admin user was active before creating user. | ||
""" | ||
|
||
handler = self.hs.get_registration_handler() | ||
|
||
# Sync to set admin user to active | ||
# before limit of monthly active users is reached | ||
request, channel = self.make_request( | ||
"GET", "/sync", access_token=self.admin_user_tok | ||
) | ||
self.render(request) | ||
|
||
if channel.code != 200: | ||
raise HttpResponseException( | ||
channel.code, channel.result["reason"], channel.result["body"] | ||
) | ||
|
||
# Set monthly active users to the limit | ||
self.store.get_monthly_active_count = Mock( | ||
return_value=self.hs.config.max_mau_value | ||
) | ||
# Check that the blocking of monthly active users is working as expected | ||
# The registration of a new user fails due to the limit | ||
self.get_failure( | ||
handler.register_user(localpart="local_part"), ResourceLimitError | ||
) | ||
|
||
# Register new user with admin API | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
# Create user | ||
body = json.dumps({"password": "abc123", "admin": False}) | ||
|
||
request, channel = self.make_request( | ||
"PUT", | ||
url, | ||
access_token=self.admin_user_tok, | ||
content=body.encode(encoding="utf_8"), | ||
) | ||
self.render(request) | ||
|
||
self.assertEqual(201, int(channel.result["code"]), msg=channel.result["body"]) | ||
self.assertEqual("@bob:test", channel.json_body["name"]) | ||
self.assertEqual(False, channel.json_body["admin"]) | ||
|
||
@override_config( | ||
{"limit_usage_by_mau": True, "max_mau_value": 2, "mau_trial_days": 0} | ||
) | ||
def test_create_user_mau_limit_reached_passive_admin(self): | ||
""" | ||
Check that an admin can register a new user via the admin API | ||
even if the MAU limit is reached. | ||
Admin user was not active before creating user. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still a bit baffled by why we need this as well as the previous test. Is it really likely that an inactive admin could be blocked from creating a new user? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test is presented for completeness. It can be left out. We deal with mau. And it would be possible that an active and passive admin/user get different results. |
||
""" | ||
|
||
handler = self.hs.get_registration_handler() | ||
|
||
# Set monthly active users to the limit | ||
self.store.get_monthly_active_count = Mock( | ||
return_value=self.hs.config.max_mau_value | ||
) | ||
# Check that the blocking of monthly active users is working as expected | ||
# The registration of a new user fails due to the limit | ||
self.get_failure( | ||
handler.register_user(localpart="local_part"), ResourceLimitError | ||
) | ||
|
||
# Register new user with admin API | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
# Create user | ||
body = json.dumps({"password": "abc123", "admin": False}) | ||
|
||
request, channel = self.make_request( | ||
"PUT", | ||
url, | ||
access_token=self.admin_user_tok, | ||
content=body.encode(encoding="utf_8"), | ||
) | ||
self.render(request) | ||
|
||
# Admin user is not blocked by mau anymore | ||
self.assertEqual(201, int(channel.result["code"]), msg=channel.result["body"]) | ||
self.assertEqual("@bob:test", channel.json_body["name"]) | ||
self.assertEqual(False, channel.json_body["admin"]) | ||
|
||
@override_config( | ||
{ | ||
"email": { | ||
"enable_notifs": True, | ||
"notif_for_new_users": True, | ||
"notif_from": "[email protected]", | ||
}, | ||
"public_baseurl": "https://example.com", | ||
} | ||
) | ||
def test_create_user_email_notif_for_new_users(self): | ||
""" | ||
Check that a new regular user is created successfully and | ||
got an email pusher. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
self.hs.config.email_enable_notifs = True | ||
self.hs.config.email_notif_for_new_users = True | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
# Create user | ||
|
@@ -554,14 +700,21 @@ def test_create_user_email_notif_for_new_users(self): | |
self.assertEqual(len(pushers), 1) | ||
self.assertEqual("@bob:test", pushers[0]["user_name"]) | ||
|
||
@override_config( | ||
{ | ||
"email": { | ||
"enable_notifs": False, | ||
"notif_for_new_users": False, | ||
"notif_from": "[email protected]", | ||
}, | ||
"public_baseurl": "https://example.com", | ||
} | ||
) | ||
def test_create_user_email_no_notif_for_new_users(self): | ||
""" | ||
Check that a new regular user is created successfully and | ||
got not an email pusher. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
self.hs.config.email_enable_notifs = False | ||
self.hs.config.email_notif_for_new_users = False | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
# Create user | ||
|
@@ -595,7 +748,6 @@ def test_set_password(self): | |
""" | ||
Test setting a new password for another user. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
|
||
# Change password | ||
body = json.dumps({"password": "hahaha"}) | ||
|
@@ -614,7 +766,6 @@ def test_set_displayname(self): | |
""" | ||
Test setting the displayname of another user. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
|
||
# Modify user | ||
body = json.dumps({"displayname": "foobar"}) | ||
|
@@ -645,7 +796,6 @@ def test_set_threepid(self): | |
""" | ||
Test setting threepid for an other user. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
|
||
# Delete old and add new threepid to user | ||
body = json.dumps( | ||
|
@@ -711,7 +861,6 @@ def test_set_user_as_admin(self): | |
""" | ||
Test setting the admin flag on a user. | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
|
||
# Set a user as an admin | ||
body = json.dumps({"admin": True}) | ||
|
@@ -743,7 +892,6 @@ def test_accidental_deactivation_prevention(self): | |
Ensure an account can't accidentally be deactivated by using a str value | ||
for the deactivated body parameter | ||
""" | ||
self.hs.config.registration_shared_secret = None | ||
url = "/_synapse/admin/v2/users/@bob:test" | ||
|
||
# Create user | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.