auth remote servers

This commit is contained in:
Kegan Dougal 2020-11-23 18:00:53 +00:00
parent dd063a2722
commit d3451b1ab8

View file

@ -123,9 +123,13 @@ type reqCtx struct {
rsAPI roomserver.RoomserverInternalAPI rsAPI roomserver.RoomserverInternalAPI
db Database db Database
req *EventRelationshipRequest req *EventRelationshipRequest
fsAPI fs.FederationSenderInternalAPI
userID string userID string
authorisedRoomIDs map[string]bool // events from these rooms can be returned
// federated request args
isFederatedRequest bool isFederatedRequest bool
serverName gomatrixserverlib.ServerName
fsAPI fs.FederationSenderInternalAPI
} }
func eventRelationshipHandler(db Database, rsAPI roomserver.RoomserverInternalAPI) func(*http.Request, *userapi.Device) util.JSONResponse { func eventRelationshipHandler(db Database, rsAPI roomserver.RoomserverInternalAPI) func(*http.Request, *userapi.Device) util.JSONResponse {
@ -172,11 +176,12 @@ func federatedEventRelationship(
rc := reqCtx{ rc := reqCtx{
ctx: ctx, ctx: ctx,
req: relation, req: relation,
userID: string(fedReq.Origin()),
rsAPI: rsAPI, rsAPI: rsAPI,
isFederatedRequest: true,
db: db, db: db,
// federation args
isFederatedRequest: true,
fsAPI: fsAPI, fsAPI: fsAPI,
serverName: fedReq.Origin(),
} }
res, resErr := rc.process() res, resErr := rc.process()
if resErr != nil { if resErr != nil {
@ -193,9 +198,8 @@ func (rc *reqCtx) process() (*EventRelationshipResponse, *util.JSONResponse) {
var res EventRelationshipResponse var res EventRelationshipResponse
var returnEvents []*gomatrixserverlib.HeaderedEvent var returnEvents []*gomatrixserverlib.HeaderedEvent
// Can the user see (according to history visibility) event_id? If no, reject the request, else continue. // Can the user see (according to history visibility) event_id? If no, reject the request, else continue.
// We should have the event being referenced so don't give any claimed room ID / servers event := rc.getLocalEvent(rc.req.EventID)
event := rc.getEventIfVisible(rc.req.EventID, "", nil) if event == nil || !rc.authorisedToSeeEvent(event) {
if event == nil {
return nil, &util.JSONResponse{ return nil, &util.JSONResponse{
Code: 403, Code: 403,
JSON: jsonerror.Forbidden("Event does not exist or you are not authorised to see it"), JSON: jsonerror.Forbidden("Event does not exist or you are not authorised to see it"),
@ -245,13 +249,12 @@ func (rc *reqCtx) process() (*EventRelationshipResponse, *util.JSONResponse) {
// If include_parent: true and there is a valid m.relationship field in the event, // If include_parent: true and there is a valid m.relationship field in the event,
// retrieve the referenced event. Apply history visibility check to that event and if it passes, add it to the response array. // retrieve the referenced event. Apply history visibility check to that event and if it passes, add it to the response array.
func (rc *reqCtx) includeParent(event *gomatrixserverlib.HeaderedEvent) (parent *gomatrixserverlib.HeaderedEvent) { func (rc *reqCtx) includeParent(childEvent *gomatrixserverlib.HeaderedEvent) (parent *gomatrixserverlib.HeaderedEvent) {
parentID, _, _ := parentChildEventIDs(event) parentID, _, _ := parentChildEventIDs(childEvent)
if parentID == "" { if parentID == "" {
return nil return nil
} }
claimedRoomID, claimedServers := roomIDAndServers(event) return rc.getLocalEventIfVisible(parentID)
return rc.getEventIfVisible(parentID, claimedRoomID, claimedServers)
} }
// If include_children: true, lookup all events which have event_id as an m.relationship // If include_children: true, lookup all events which have event_id as an m.relationship
@ -266,8 +269,7 @@ func (rc *reqCtx) includeChildren(db Database, parentID string, limit int, recen
} }
var childEvents []*gomatrixserverlib.HeaderedEvent var childEvents []*gomatrixserverlib.HeaderedEvent
for _, child := range children { for _, child := range children {
// in order for us to even know about the children the server must be joined to those rooms, hence pass no claimed room ID or servers. childEvent := rc.getLocalEventIfVisible(child.EventID)
childEvent := rc.getEventIfVisible(child.EventID, "", nil)
if childEvent != nil { if childEvent != nil {
childEvents = append(childEvents, childEvent) childEvents = append(childEvents, childEvent)
} }
@ -306,7 +308,7 @@ func walkThread(
// Process the event. // Process the event.
// TODO: Include edge information: room ID and servers // TODO: Include edge information: room ID and servers
event := rc.getEventIfVisible(wi.EventID, "", nil) event := rc.getLocalEventIfVisible(wi.EventID)
if event != nil { if event != nil {
result = append(result, event) result = append(result, event)
} }
@ -341,77 +343,101 @@ func (rc *reqCtx) MSC2836EventRelationships(eventID string, srv gomatrixserverli
} }
// TODO: // TODO: getRemoteEventIfVisible: if event ID is unknown, blindly attempt to join (which room? Origin, via who?) then hit /event_relationships.
// getEventIfVisible returns the event if it is visible to the user. Does not perform any federated requests.
// getEvent returns the event, retrieving it if necessary from a remote server. // authorisedToSeeEvent authenticates that the user or server is allowed to see this event. Returns true if allowed to
func (rc *reqCtx) getEventIfVisible(eventID string, claimedRoomID string, claimedServers []string) *gomatrixserverlib.HeaderedEvent { // see this request.
event, joinedToRoom := getEventIfVisible(rc.ctx, rc.rsAPI, eventID, rc.userID) func (rc *reqCtx) authorisedToSeeEvent(event *gomatrixserverlib.HeaderedEvent) bool {
if event != nil && joinedToRoom { authorised, ok := rc.authorisedRoomIDs[event.RoomID()]
if ok {
return authorised
}
if rc.isFederatedRequest {
// make sure the server is in this room
var res fs.QueryJoinedHostServerNamesInRoomResponse
err := rc.fsAPI.QueryJoinedHostServerNamesInRoom(rc.ctx, &fs.QueryJoinedHostServerNamesInRoomRequest{
RoomID: event.RoomID(),
}, &res)
if err != nil {
util.GetLogger(rc.ctx).WithError(err).Error("authenticateEvent: failed to QueryJoinedHostServerNamesInRoom")
return false
}
for _, srv := range res.ServerNames {
if srv == rc.serverName {
rc.authorisedRoomIDs[event.RoomID()] = true
return true
}
}
return false
}
// make sure the user is in this room
joinedToRoom, err := rc.allowedToSeeEvent(event.RoomID(), rc.userID)
if err != nil || !joinedToRoom {
return false
}
rc.authorisedRoomIDs[event.RoomID()] = true
return true
}
// getLocalEventIfVisible returns the event for the event ID given, by trying to auto-join rooms if not authorised
func (rc *reqCtx) getLocalEventIfVisible(eventID string) *gomatrixserverlib.HeaderedEvent {
event := rc.getLocalEvent(eventID)
if event == nil {
return nil
}
if rc.authorisedToSeeEvent(event) {
return event return event
} }
// either we don't have the event or we aren't joined to the room, regardless we should try joining if auto join is enabled if !rc.isFederatedRequest && rc.req.AutoJoin {
if !rc.req.AutoJoin { // attempt to join the room then recheck auth, but only for local users
return nil
}
// if we're doing this on behalf of a random server don't auto-join rooms regardless of what the request says
if rc.isFederatedRequest {
return nil
}
roomID := claimedRoomID
var servers []gomatrixserverlib.ServerName
if event != nil {
roomID = event.RoomID()
}
for _, s := range claimedServers {
servers = append(servers, gomatrixserverlib.ServerName(s))
}
var joinRes roomserver.PerformJoinResponse var joinRes roomserver.PerformJoinResponse
rc.rsAPI.PerformJoin(rc.ctx, &roomserver.PerformJoinRequest{ rc.rsAPI.PerformJoin(rc.ctx, &roomserver.PerformJoinRequest{
UserID: rc.userID, UserID: rc.userID,
Content: map[string]interface{}{}, Content: map[string]interface{}{},
RoomIDOrAlias: roomID, RoomIDOrAlias: event.RoomID(),
ServerNames: servers,
}, &joinRes) }, &joinRes)
if joinRes.Error != nil { if joinRes.Error != nil {
util.GetLogger(rc.ctx).WithError(joinRes.Error).WithField("room_id", roomID).Error("Failed to auto-join room") util.GetLogger(rc.ctx).WithError(joinRes.Error).WithField("room_id", event.RoomID()).Error("Failed to auto-join room")
return nil return nil
} }
if event != nil { delete(rc.authorisedRoomIDs, event.RoomID())
if rc.authorisedToSeeEvent(event) {
return event return event
} }
// TODO: hit /event_relationships on the server we joined via }
util.GetLogger(rc.ctx).Infof("joined room but need to fetch event TODO")
return nil return nil
} }
func getEventIfVisible(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI, eventID, userID string) (*gomatrixserverlib.HeaderedEvent, bool) { func (rc *reqCtx) allowedToSeeEvent(roomID, userID string) (bool, error) {
var queryEventsRes roomserver.QueryEventsByIDResponse
err := rsAPI.QueryEventsByID(ctx, &roomserver.QueryEventsByIDRequest{
EventIDs: []string{eventID},
}, &queryEventsRes)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("getEventIfVisible: failed to QueryEventsByID")
return nil, false
}
if len(queryEventsRes.Events) == 0 {
util.GetLogger(ctx).Infof("event does not exist")
return nil, false // event does not exist
}
event := queryEventsRes.Events[0]
// Allow events if the member is in the room // Allow events if the member is in the room
// TODO: This does not honour history_visibility // TODO: This does not honour history_visibility
// TODO: This does not honour m.room.create content // TODO: This does not honour m.room.create content
var queryMembershipRes roomserver.QueryMembershipForUserResponse var queryMembershipRes roomserver.QueryMembershipForUserResponse
err = rsAPI.QueryMembershipForUser(ctx, &roomserver.QueryMembershipForUserRequest{ err := rc.rsAPI.QueryMembershipForUser(rc.ctx, &roomserver.QueryMembershipForUserRequest{
RoomID: event.RoomID(), RoomID: roomID,
UserID: userID, UserID: userID,
}, &queryMembershipRes) }, &queryMembershipRes)
if err != nil { if err != nil {
util.GetLogger(ctx).WithError(err).Error("getEventIfVisible: failed to QueryMembershipForUser") util.GetLogger(rc.ctx).WithError(err).Error("allowedToSeeEvent: failed to QueryMembershipForUser")
return nil, false return false, err
} }
return event, queryMembershipRes.IsInRoom return queryMembershipRes.IsInRoom, nil
}
func (rc *reqCtx) getLocalEvent(eventID string) *gomatrixserverlib.HeaderedEvent {
var queryEventsRes roomserver.QueryEventsByIDResponse
err := rc.rsAPI.QueryEventsByID(rc.ctx, &roomserver.QueryEventsByIDRequest{
EventIDs: []string{eventID},
}, &queryEventsRes)
if err != nil {
util.GetLogger(rc.ctx).WithError(err).Error("getLocalEvent: failed to QueryEventsByID")
return nil
}
if len(queryEventsRes.Events) == 0 {
util.GetLogger(rc.ctx).Infof("getLocalEvent: event does not exist")
return nil // event does not exist
}
return queryEventsRes.Events[0]
} }
type walkInfo struct { type walkInfo struct {