Deny guest access on several endpoints
Second part for guest access, this adds a `WithAllowGuests()` option to
`MakeAuthAPI`, allowing guests to access the specified endpoints.
Endpoints taken from the
[spec](https://spec.matrix.org/v1.4/client-server-api/#client-behaviour-14)
and by checking Synapse endpoints for `allow_guest=true`.
MODIFY
clientapi/routing/routing.go
clientapi/routing/routing.go
@@ -252,7 +252,7 @@ func Setup(
return JoinRoomByIDOrAlias(
req, device, rsAPI, userAPI, vars["roomIDOrAlias"],
)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
if mscCfg.Enabled("msc2753") {
@@ -274,7 +274,7 @@ func Setup(
v3mux.Handle("/joined_rooms",
httputil.MakeAuthAPI("joined_rooms", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return GetJoinedRooms(req, device, rsAPI)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/join",
httputil.MakeAuthAPI(gomatrixserverlib.Join, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -288,7 +288,7 @@ func Setup(
return JoinRoomByIDOrAlias(
req, device, rsAPI, userAPI, vars["roomID"],
)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/leave",
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -302,7 +302,7 @@ func Setup(
return LeaveRoomByID(
req, device, rsAPI, vars["roomID"],
)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/unpeek",
httputil.MakeAuthAPI("unpeek", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -361,7 +361,7 @@ func Setup(
return util.ErrorResponse(err)
}
return SendEvent(req, device, vars["roomID"], vars["eventType"], nil, nil, cfg, rsAPI, nil)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}",
httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -372,7 +372,7 @@ func Setup(
txnID := vars["txnID"]
return SendEvent(req, device, vars["roomID"], vars["eventType"], &txnID,
nil, cfg, rsAPI, transactionsCache)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPut, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/state", httputil.MakeAuthAPI("room_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -381,7 +381,7 @@ func Setup(
return util.ErrorResponse(err)
}
return OnIncomingStateRequest(req.Context(), device, rsAPI, vars["roomID"])
- })).Methods(http.MethodGet, http.MethodOptions)
+ }, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/aliases", httputil.MakeAuthAPI("aliases", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
@@ -400,7 +400,7 @@ func Setup(
eventType := strings.TrimSuffix(vars["type"], "/")
eventFormat := req.URL.Query().Get("format") == "event"
return OnIncomingStateTypeRequest(req.Context(), device, rsAPI, vars["roomID"], eventType, "", eventFormat)
- })).Methods(http.MethodGet, http.MethodOptions)
+ }, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", httputil.MakeAuthAPI("room_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
@@ -409,7 +409,7 @@ func Setup(
}
eventFormat := req.URL.Query().Get("format") == "event"
return OnIncomingStateTypeRequest(req.Context(), device, rsAPI, vars["roomID"], vars["type"], vars["stateKey"], eventFormat)
- })).Methods(http.MethodGet, http.MethodOptions)
+ }, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/state/{eventType:[^/]+/?}",
httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -420,7 +420,7 @@ func Setup(
emptyString := ""
eventType := strings.TrimSuffix(vars["eventType"], "/")
return SendEvent(req, device, vars["roomID"], eventType, nil, &emptyString, cfg, rsAPI, nil)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPut, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/state/{eventType}/{stateKey}",
@@ -431,7 +431,7 @@ func Setup(
}
stateKey := vars["stateKey"]
return SendEvent(req, device, vars["roomID"], vars["eventType"], nil, &stateKey, cfg, rsAPI, nil)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPut, http.MethodOptions)
v3mux.Handle("/register", httputil.MakeExternalAPI("register", func(req *http.Request) util.JSONResponse {
@@ -575,7 +575,7 @@ func Setup(
}
txnID := vars["txnID"]
return SendToDevice(req, device, syncProducer, transactionsCache, vars["eventType"], &txnID)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPut, http.MethodOptions)
// This is only here because sytest refers to /unstable for this endpoint
@@ -589,7 +589,7 @@ func Setup(
}
txnID := vars["txnID"]
return SendToDevice(req, device, syncProducer, transactionsCache, vars["eventType"], &txnID)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPut, http.MethodOptions)
v3mux.Handle("/account/whoami",
@@ -598,7 +598,7 @@ func Setup(
return *r
}
return Whoami(req, device)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/account/password",
@@ -830,7 +830,7 @@ func Setup(
return util.ErrorResponse(err)
}
return SetDisplayName(req, userAPI, device, vars["userID"], cfg, rsAPI)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPut, http.MethodOptions)
// Browsers use the OPTIONS HTTP method to check if the CORS policy allows
// PUT requests, so we need to allow this method
@@ -871,7 +871,7 @@ func Setup(
v3mux.Handle("/thirdparty/protocols",
httputil.MakeAuthAPI("thirdparty_protocols", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return Protocols(req, asAPI, device, "")
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/thirdparty/protocol/{protocolID}",
@@ -881,7 +881,7 @@ func Setup(
return util.ErrorResponse(err)
}
return Protocols(req, asAPI, device, vars["protocolID"])
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/thirdparty/user/{protocolID}",
@@ -891,13 +891,13 @@ func Setup(
return util.ErrorResponse(err)
}
return User(req, asAPI, device, vars["protocolID"], req.URL.Query())
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/thirdparty/user",
httputil.MakeAuthAPI("thirdparty_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return User(req, asAPI, device, "", req.URL.Query())
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/thirdparty/location/{protocolID}",
@@ -907,13 +907,13 @@ func Setup(
return util.ErrorResponse(err)
}
return Location(req, asAPI, device, vars["protocolID"], req.URL.Query())
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/thirdparty/location",
httputil.MakeAuthAPI("thirdparty_location", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return Location(req, asAPI, device, "", req.URL.Query())
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/initialSync",
@@ -1054,7 +1054,7 @@ func Setup(
v3mux.Handle("/devices",
httputil.MakeAuthAPI("get_devices", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return GetDevicesByLocalpart(req, userAPI, device)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/devices/{deviceID}",
@@ -1064,7 +1064,7 @@ func Setup(
return util.ErrorResponse(err)
}
return GetDeviceByID(req, userAPI, device, vars["deviceID"])
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/devices/{deviceID}",
@@ -1074,7 +1074,7 @@ func Setup(
return util.ErrorResponse(err)
}
return UpdateDeviceByID(req, userAPI, device, vars["deviceID"])
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPut, http.MethodOptions)
v3mux.Handle("/devices/{deviceID}",
@@ -1116,21 +1116,21 @@ func Setup(
// Stub implementations for sytest
v3mux.Handle("/events",
- httputil.MakeExternalAPI("events", func(req *http.Request) util.JSONResponse {
+ httputil.MakeAuthAPI("events", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return util.JSONResponse{Code: http.StatusOK, JSON: map[string]interface{}{
"chunk": []interface{}{},
"start": "",
"end": "",
}}
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/initialSync",
- httputil.MakeExternalAPI("initial_sync", func(req *http.Request) util.JSONResponse {
+ httputil.MakeAuthAPI("initial_sync", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return util.JSONResponse{Code: http.StatusOK, JSON: map[string]interface{}{
"end": "",
}}
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/user/{userId}/rooms/{roomId}/tags",
@@ -1169,7 +1169,7 @@ func Setup(
return *r
}
return GetCapabilities(req, rsAPI)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
// Key Backup Versions (Metadata)
@@ -1350,7 +1350,7 @@ func Setup(
postDeviceSigningSignatures := httputil.MakeAuthAPI("post_device_signing_signatures", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return UploadCrossSigningDeviceSignatures(req, keyAPI, device)
- })
+ }, httputil.WithAllowGuests())
v3mux.Handle("/keys/device_signing/upload", postDeviceSigningKeys).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/keys/signatures/upload", postDeviceSigningSignatures).Methods(http.MethodPost, http.MethodOptions)
@@ -1362,22 +1362,22 @@ func Setup(
v3mux.Handle("/keys/upload/{deviceID}",
httputil.MakeAuthAPI("keys_upload", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return UploadKeys(req, keyAPI, device)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/keys/upload",
httputil.MakeAuthAPI("keys_upload", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return UploadKeys(req, keyAPI, device)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/keys/query",
httputil.MakeAuthAPI("keys_query", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return QueryKeys(req, keyAPI, device)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/keys/claim",
httputil.MakeAuthAPI("keys_claim", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return ClaimKeys(req, keyAPI)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/rooms/{roomId}/receipt/{receiptType}/{eventId}",
httputil.MakeAuthAPI(gomatrixserverlib.Join, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {

MODIFY
internal/httputil/httpapi.go
internal/httputil/httpapi.go
@@ -42,10 +42,26 @@ type BasicAuth struct {
Password string `yaml:"password"`
}
+type AuthAPIOpts struct {
+ GuestAccessAllowed bool
+}
+
+// AuthAPIOption is an option to MakeAuthAPI to add additional checks (e.g. guest access) to verify
+// the user is allowed to do specific things.
+type AuthAPIOption func(opts *AuthAPIOpts)
+
+// WithAllowGuests checks that guest users have access to this endpoint
+func WithAllowGuests() AuthAPIOption {
+ return func(opts *AuthAPIOpts) {
+ opts.GuestAccessAllowed = true
+ }
+}
+
// MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which authenticates the request.
func MakeAuthAPI(
metricsName string, userAPI userapi.QueryAcccessTokenAPI,
f func(*http.Request, *userapi.Device) util.JSONResponse,
+ checks ...AuthAPIOption,
) http.Handler {
h := func(req *http.Request) util.JSONResponse {
logger := util.GetLogger(req.Context())
@@ -76,6 +92,19 @@ func MakeAuthAPI(
}
}()
+ // apply additional checks, if any
+ opts := AuthAPIOpts{}
+ for _, opt := range checks {
+ opt(&opts)
+ }
+
+ if !opts.GuestAccessAllowed && device.AccountType == userapi.AccountTypeGuest {
+ return util.JSONResponse{
+ Code: http.StatusForbidden,
+ JSON: jsonerror.GuestAccessForbidden("Guest access not allowed"),
+ }
+ }
+
jsonRes := f(req, device)
// do not log 4xx as errors as they are client fails, not server fails
if hub != nil && jsonRes.Code >= 500 {

MODIFY
setup/mscs/msc2946/msc2946.go
setup/mscs/msc2946/msc2946.go
@@ -57,7 +57,7 @@ func Enable(
base *base.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, userAPI userapi.UserInternalAPI,
fsAPI fs.FederationInternalAPI, keyRing gomatrixserverlib.JSONVerifier, cache caching.SpaceSummaryRoomsCache,
) error {
- clientAPI := httputil.MakeAuthAPI("spaces", userAPI, spacesHandler(rsAPI, fsAPI, cache, base.Cfg.Global.ServerName))
+ clientAPI := httputil.MakeAuthAPI("spaces", userAPI, spacesHandler(rsAPI, fsAPI, cache, base.Cfg.Global.ServerName), httputil.WithAllowGuests())
base.PublicClientAPIMux.Handle("/v1/rooms/{roomID}/hierarchy", clientAPI).Methods(http.MethodGet, http.MethodOptions)
base.PublicClientAPIMux.Handle("/unstable/org.matrix.msc2946/rooms/{roomID}/hierarchy", clientAPI).Methods(http.MethodGet, http.MethodOptions)

MODIFY
syncapi/routing/routing.go
syncapi/routing/routing.go
@@ -51,7 +51,7 @@ func Setup(
// TODO: Add AS support for all handlers below.
v3mux.Handle("/sync", httputil.MakeAuthAPI("sync", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return srp.OnIncomingSyncRequest(req, device)
- })).Methods(http.MethodGet, http.MethodOptions)
+ }, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/messages", httputil.MakeAuthAPI("room_messages", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
@@ -59,7 +59,7 @@ func Setup(
return util.ErrorResponse(err)
}
return OnIncomingMessagesRequest(req, syncDB, vars["roomID"], device, rsAPI, cfg, srp, lazyLoadCache)
- })).Methods(http.MethodGet, http.MethodOptions)
+ }, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/event/{eventID}",
httputil.MakeAuthAPI("rooms_get_event", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -68,7 +68,7 @@ func Setup(
return util.ErrorResponse(err)
}
return GetEvent(req, device, vars["roomID"], vars["eventID"], cfg, syncDB, rsAPI)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/user/{userId}/filter",
@@ -93,7 +93,7 @@ func Setup(
v3mux.Handle("/keys/changes", httputil.MakeAuthAPI("keys_changes", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return srp.OnIncomingKeyChangeRequest(req, device)
- })).Methods(http.MethodGet, http.MethodOptions)
+ }, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomId}/context/{eventId}",
httputil.MakeAuthAPI(gomatrixserverlib.Join, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
@@ -108,7 +108,7 @@ func Setup(
vars["roomId"], vars["eventId"],
lazyLoadCache,
)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}",
@@ -122,7 +122,7 @@ func Setup(
req, device, syncDB, rsAPI,
vars["roomId"], vars["eventId"], "", "",
)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}",
@@ -136,7 +136,7 @@ func Setup(
req, device, syncDB, rsAPI,
vars["roomId"], vars["eventId"], vars["relType"], "",
)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}",
@@ -150,7 +150,7 @@ func Setup(
req, device, syncDB, rsAPI,
vars["roomId"], vars["eventId"], vars["relType"], vars["eventType"],
)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/search",
@@ -191,7 +191,7 @@ func Setup(
at := req.URL.Query().Get("at")
return GetMemberships(req, device, vars["roomID"], syncDB, rsAPI, false, membership, notMembership, at)
- }),
+ }, httputil.WithAllowGuests()),
).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/joined_members",

Deny guest access on several endpoints (#2873)

Second part for guest access, this adds a `WithAllowGuests()` option to
`MakeAuthAPI`, allowing guests to access the specified endpoints.
Endpoints taken from the
[spec](https://spec.matrix.org/v1.4/client-server-api/#client-behaviour-14)
and by checking Synapse endpoints for `allow_guest=true`.