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

Commit

Permalink
Require AppserviceRegistrationType (#9548)
Browse files Browse the repository at this point in the history
This change ensures that the appservice registration behaviour follows the spec. We decided to do this for Dendrite, so it made sense to also make a PR for synapse to correct the behaviour.
  • Loading branch information
Half-Shot committed Apr 12, 2021
1 parent 0b31121 commit e300ef6
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 23 deletions.
1 change: 1 addition & 0 deletions changelog.d/9548.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make `/_matrix/client/r0/register` expect a type of `m.login.application_service` when an Application Service registers a user, to align with [the relevant spec](https://spec.matrix.org/unstable/application-service-api/#server-admin-style-permissions).
5 changes: 5 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ class LoginType:
DUMMY = "m.login.dummy"


# This is used in the `type` parameter for /register when called by
# an appservice to register a new user.
APP_SERVICE_REGISTRATION_TYPE = "m.login.application_service"


class EventTypes:
Member = "m.room.member"
Create = "m.room.create"
Expand Down
23 changes: 16 additions & 7 deletions synapse/rest/client/v2_alpha/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import hmac
import logging
import random
Expand All @@ -22,7 +21,7 @@
import synapse
import synapse.api.auth
import synapse.types
from synapse.api.constants import LoginType
from synapse.api.constants import APP_SERVICE_REGISTRATION_TYPE, LoginType
from synapse.api.errors import (
Codes,
InteractiveAuthIncompleteError,
Expand Down Expand Up @@ -430,15 +429,20 @@ async def on_POST(self, request):
raise SynapseError(400, "Invalid username")
desired_username = body["username"]

appservice = None
if self.auth.has_access_token(request):
appservice = self.auth.get_appservice_by_req(request)

# fork off as soon as possible for ASes which have completely
# different registration flows to normal users

# == Application Service Registration ==
if appservice:
if body.get("type") == APP_SERVICE_REGISTRATION_TYPE:
if not self.auth.has_access_token(request):
raise SynapseError(
400,
"Appservice token must be provided when using a type of m.login.application_service",
)

# Verify the AS
self.auth.get_appservice_by_req(request)

# Set the desired user according to the AS API (which uses the
# 'user' key not 'username'). Since this is a new addition, we'll
# fallback to 'username' if they gave one.
Expand All @@ -459,6 +463,11 @@ async def on_POST(self, request):
)

return 200, result
elif self.auth.has_access_token(request):
raise SynapseError(
400,
"An access token should not be provided on requests to /register (except if type is m.login.application_service)",
)

# == Normal User Registration == (everyone else)
if not self._registration_enabled:
Expand Down
31 changes: 27 additions & 4 deletions tests/rest/client/v2_alpha/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import datetime
import json
import os

import pkg_resources

import synapse.rest.admin
from synapse.api.constants import LoginType
from synapse.api.constants import APP_SERVICE_REGISTRATION_TYPE, LoginType
from synapse.api.errors import Codes
from synapse.appservice import ApplicationService
from synapse.rest.client.v1 import login, logout
Expand Down Expand Up @@ -59,7 +58,9 @@ def test_POST_appservice_registration_valid(self):
)

self.hs.get_datastore().services_cache.append(appservice)
request_data = json.dumps({"username": "as_user_kermit"})
request_data = json.dumps(
{"username": "as_user_kermit", "type": APP_SERVICE_REGISTRATION_TYPE}
)

channel = self.make_request(
b"POST", self.url + b"?access_token=i_am_an_app_service", request_data
Expand All @@ -69,9 +70,31 @@ def test_POST_appservice_registration_valid(self):
det_data = {"user_id": user_id, "home_server": self.hs.hostname}
self.assertDictContainsSubset(det_data, channel.json_body)

def test_POST_appservice_registration_no_type(self):
as_token = "i_am_an_app_service"

appservice = ApplicationService(
as_token,
self.hs.config.server_name,
id="1234",
namespaces={"users": [{"regex": r"@as_user.*", "exclusive": True}]},
sender="@as:test",
)

self.hs.get_datastore().services_cache.append(appservice)
request_data = json.dumps({"username": "as_user_kermit"})

channel = self.make_request(
b"POST", self.url + b"?access_token=i_am_an_app_service", request_data
)

self.assertEquals(channel.result["code"], b"400", channel.result)

def test_POST_appservice_registration_invalid(self):
self.appservice = None # no application service exists
request_data = json.dumps({"username": "kermit"})
request_data = json.dumps(
{"username": "kermit", "type": APP_SERVICE_REGISTRATION_TYPE}
)
channel = self.make_request(
b"POST", self.url + b"?access_token=i_am_an_app_service", request_data
)
Expand Down
23 changes: 11 additions & 12 deletions tests/test_mau.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@

"""Tests REST events for /rooms paths."""

import json

from synapse.api.constants import LoginType
from synapse.api.constants import APP_SERVICE_REGISTRATION_TYPE, LoginType
from synapse.api.errors import Codes, HttpResponseException, SynapseError
from synapse.appservice import ApplicationService
from synapse.rest.client.v2_alpha import register, sync
Expand Down Expand Up @@ -113,7 +111,7 @@ def test_as_ignores_mau(self):
)
)

self.create_user("as_kermit4", token=as_token)
self.create_user("as_kermit4", token=as_token, appservice=True)

def test_allowed_after_a_month_mau(self):
# Create and sync so that the MAU counts get updated
Expand Down Expand Up @@ -232,14 +230,15 @@ def test_tracked_but_not_limited(self):
self.reactor.advance(100)
self.assertEqual(2, self.successResultOf(count))

def create_user(self, localpart, token=None):
request_data = json.dumps(
{
"username": localpart,
"password": "monkey",
"auth": {"type": LoginType.DUMMY},
}
)
def create_user(self, localpart, token=None, appservice=False):
request_data = {
"username": localpart,
"password": "monkey",
"auth": {"type": LoginType.DUMMY},
}

if appservice:
request_data["type"] = APP_SERVICE_REGISTRATION_TYPE

channel = self.make_request(
"POST",
Expand Down

0 comments on commit e300ef6

Please sign in to comment.