diff --git a/synapse/api/auth/__init__.py b/synapse/api/auth/__init__.py
index 234dcf1ca4..d5241afe73 100644
--- a/synapse/api/auth/__init__.py
+++ b/synapse/api/auth/__init__.py
@@ -18,7 +18,7 @@
# [This file includes modifications made by New Vector Limited]
#
#
-from typing import Optional, Tuple
+from typing import TYPE_CHECKING, Optional, Tuple
from typing_extensions import Protocol
@@ -28,6 +28,9 @@ from synapse.appservice import ApplicationService
from synapse.http.site import SynapseRequest
from synapse.types import Requester
+if TYPE_CHECKING:
+ from synapse.rest.admin.experimental_features import ExperimentalFeature
+
# guests always get this device id.
GUEST_DEVICE_ID = "guest_device"
@@ -87,6 +90,19 @@ class Auth(Protocol):
AuthError if access is denied for the user in the access token
"""
+ async def get_user_by_req_experimental_feature(
+ self,
+ request: SynapseRequest,
+ feature: "ExperimentalFeature",
+ allow_guest: bool = False,
+ allow_expired: bool = False,
+ allow_locked: bool = False,
+ ) -> Requester:
+ """Like `get_user_by_req`, except also checks if the user has access to
+ the experimental feature. If they don't returns a 404 unrecognized
+ request.
+ """
+
async def validate_appservice_can_control_user_id(
self, app_service: ApplicationService, user_id: str
) -> None:
diff --git a/synapse/api/auth/internal.py b/synapse/api/auth/internal.py
index 2878f3e6e9..9fd4db68e1 100644
--- a/synapse/api/auth/internal.py
+++ b/synapse/api/auth/internal.py
@@ -28,6 +28,7 @@ from synapse.api.errors import (
Codes,
InvalidClientTokenError,
MissingClientTokenError,
+ UnrecognizedRequestError,
)
from synapse.http.site import SynapseRequest
from synapse.logging.opentracing import active_span, force_tracing, start_active_span
@@ -38,8 +39,10 @@ from . import GUEST_DEVICE_ID
from .base import BaseAuth
if TYPE_CHECKING:
+ from synapse.rest.admin.experimental_features import ExperimentalFeature
from synapse.server import HomeServer
+
logger = logging.getLogger(__name__)
@@ -106,6 +109,32 @@ class InternalAuth(BaseAuth):
parent_span.set_tag("appservice_id", requester.app_service.id)
return requester
+ async def get_user_by_req_experimental_feature(
+ self,
+ request: SynapseRequest,
+ feature: "ExperimentalFeature",
+ allow_guest: bool = False,
+ allow_expired: bool = False,
+ allow_locked: bool = False,
+ ) -> Requester:
+ try:
+ requester = await self.get_user_by_req(
+ request,
+ allow_guest=allow_guest,
+ allow_expired=allow_expired,
+ allow_locked=allow_locked,
+ )
+ if await self.store.is_feature_enabled(requester.user.to_string(), feature):
+ return requester
+
+ raise UnrecognizedRequestError(code=404)
+ except (AuthError, InvalidClientTokenError):
+ if feature.is_globally_enabled(self.hs.config):
+ # If its globally enabled then return the auth error
+ raise
+
+ raise UnrecognizedRequestError(code=404)
+
@cancellable
async def _wrapped_get_user_by_req(
self,
diff --git a/synapse/api/auth/msc3861_delegated.py b/synapse/api/auth/msc3861_delegated.py
index 3146e1577c..f61b39ded7 100644
--- a/synapse/api/auth/msc3861_delegated.py
+++ b/synapse/api/auth/msc3861_delegated.py
@@ -40,6 +40,7 @@ from synapse.api.errors import (
OAuthInsufficientScopeError,
StoreError,
SynapseError,
+ UnrecognizedRequestError,
)
from synapse.http.site import SynapseRequest
from synapse.logging.context import make_deferred_yieldable
@@ -48,6 +49,7 @@ from synapse.util import json_decoder
from synapse.util.caches.cached_call import RetryOnExceptionCachedCall
if TYPE_CHECKING:
+ from synapse.rest.admin.experimental_features import ExperimentalFeature
from synapse.server import HomeServer
logger = logging.getLogger(__name__)
@@ -245,6 +247,32 @@ class MSC3861DelegatedAuth(BaseAuth):
return requester
+ async def get_user_by_req_experimental_feature(
+ self,
+ request: SynapseRequest,
+ feature: "ExperimentalFeature",
+ allow_guest: bool = False,
+ allow_expired: bool = False,
+ allow_locked: bool = False,
+ ) -> Requester:
+ try:
+ requester = await self.get_user_by_req(
+ request,
+ allow_guest=allow_guest,
+ allow_expired=allow_expired,
+ allow_locked=allow_locked,
+ )
+ if await self.store.is_feature_enabled(requester.user.to_string(), feature):
+ return requester
+
+ raise UnrecognizedRequestError(code=404)
+ except (AuthError, InvalidClientTokenError):
+ if feature.is_globally_enabled(self.hs.config):
+ # If its globally enabled then return the auth error
+ raise
+
+ raise UnrecognizedRequestError(code=404)
+
async def get_user_by_access_token(
self,
token: str,
|