Confine calendar connectors to configured origins
This commit is contained in:
@@ -23,12 +23,17 @@ class CalendarSyncSourceTests(unittest.TestCase):
|
||||
create_scope_tables(self.engine)
|
||||
Base.metadata.create_all(bind=self.engine)
|
||||
self.Session = sessionmaker(bind=self.engine)
|
||||
self.sessions = []
|
||||
|
||||
def tearDown(self) -> None:
|
||||
for session in reversed(self.sessions):
|
||||
session.close()
|
||||
Base.metadata.drop_all(bind=self.engine)
|
||||
self.engine.dispose()
|
||||
|
||||
def session_with_calendar(self):
|
||||
session = self.Session()
|
||||
self.sessions.append(session)
|
||||
session.add(Tenant(id="tenant-1", slug="tenant-1", name="Tenant"))
|
||||
calendar = create_calendar(session, tenant_id="tenant-1", user_id=None, payload=CalendarCollectionCreateRequest(name="Remote"))
|
||||
session.flush()
|
||||
@@ -166,6 +171,74 @@ END:VCALENDAR
|
||||
self.assertEqual(event.summary, "Graph item")
|
||||
self.assertIn("Bearer graph-token", request.call_args.kwargs["headers"]["Authorization"])
|
||||
|
||||
def test_graph_sync_rejects_cross_origin_continuation_url(self) -> None:
|
||||
session, calendar = self.session_with_calendar()
|
||||
source = create_sync_source(
|
||||
session,
|
||||
tenant_id="tenant-1",
|
||||
user_id=None,
|
||||
payload=CalendarSyncSourceCreateRequest(
|
||||
source_kind="graph",
|
||||
calendar_id=calendar.id,
|
||||
collection_url="me/calendar",
|
||||
auth_type="bearer",
|
||||
bearer_token="graph-token",
|
||||
),
|
||||
)
|
||||
payload = {
|
||||
"value": [],
|
||||
"@odata.nextLink": "https://attacker.example.test/collect?token=secret",
|
||||
}
|
||||
|
||||
with patch(
|
||||
"govoplan_calendar.backend.service.http_request",
|
||||
return_value=(200, {}, json.dumps(payload)),
|
||||
) as request:
|
||||
with self.assertRaisesRegex(CalendarError, "configured source origin"):
|
||||
sync_source(
|
||||
session,
|
||||
tenant_id="tenant-1",
|
||||
user_id=None,
|
||||
source_id=source.id,
|
||||
)
|
||||
|
||||
self.assertEqual(request.call_count, 1)
|
||||
self.assertEqual(source.last_status, "error")
|
||||
|
||||
def test_graph_sync_rejects_cross_origin_delta_url(self) -> None:
|
||||
session, calendar = self.session_with_calendar()
|
||||
source = create_sync_source(
|
||||
session,
|
||||
tenant_id="tenant-1",
|
||||
user_id=None,
|
||||
payload=CalendarSyncSourceCreateRequest(
|
||||
source_kind="graph",
|
||||
calendar_id=calendar.id,
|
||||
collection_url="me/calendar",
|
||||
auth_type="bearer",
|
||||
bearer_token="graph-token",
|
||||
),
|
||||
)
|
||||
payload = {
|
||||
"value": [],
|
||||
"@odata.deltaLink": "https://attacker.example.test/collect?token=secret",
|
||||
}
|
||||
|
||||
with patch(
|
||||
"govoplan_calendar.backend.service.http_request",
|
||||
return_value=(200, {}, json.dumps(payload)),
|
||||
) as request:
|
||||
with self.assertRaisesRegex(CalendarError, "configured source origin"):
|
||||
sync_source(
|
||||
session,
|
||||
tenant_id="tenant-1",
|
||||
user_id=None,
|
||||
source_id=source.id,
|
||||
)
|
||||
|
||||
self.assertEqual(request.call_count, 1)
|
||||
self.assertEqual(source.last_status, "error")
|
||||
|
||||
def test_ews_sync_imports_calendar_view_items(self) -> None:
|
||||
session, calendar = self.session_with_calendar()
|
||||
source = create_sync_source(
|
||||
|
||||
Reference in New Issue
Block a user