Skip to content

Commit b356195

Browse files
authored
fix: Ensure that numtracker headers are not re-used (#1202)
If the headers are only set when they are present but not cleared at the end of a plan (or when they're absent), a request with no headers following a request with headers will re-use the previous users credentials allowing unauthenticated access to running plans. Setting the headers to an empty map if none are present helps ensure tokens cannot be used by other users.
1 parent 0760be5 commit b356195

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

src/blueapi/service/interface.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,7 @@ def begin_task(
224224
task: WorkerTask, pass_through_headers: Mapping[str, str] | None = None
225225
) -> WorkerTask:
226226
"""Trigger a task. Will fail if the worker is busy"""
227-
if pass_through_headers:
228-
_try_configure_numtracker(pass_through_headers)
227+
_try_configure_numtracker(pass_through_headers or {})
229228

230229
if task.task_id is not None:
231230
worker().begin_task(task.task_id)

tests/unit_tests/service/test_interface.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,45 @@ def test_configure_numtracker():
418418
interface.teardown()
419419

420420

421+
@patch("blueapi.client.numtracker.requests.post")
422+
def test_headers_are_cleared(mock_post):
423+
mock_response = Mock()
424+
mock_post.return_value = mock_response
425+
mock_response.raise_for_status.side_effect = None
426+
mock_response.json.return_value = {
427+
"data": {
428+
"scan": {
429+
"scanNumber": 42,
430+
"directory": {
431+
"path": "/tmp",
432+
"instrument": "p46",
433+
"instrument_session": "cm12345-1",
434+
},
435+
"scanFile": "p46-42",
436+
}
437+
}
438+
}
439+
440+
conf = ApplicationConfig(
441+
numtracker=NumtrackerConfig(
442+
url=HttpUrl("https://numtracker.example.com/graphql")
443+
),
444+
env=EnvironmentConfig(metadata=MetadataConfig(instrument="p46")),
445+
)
446+
interface.set_config(conf)
447+
headers = {"foo": "bar"}
448+
449+
interface.begin_task(task=WorkerTask(task_id=None), pass_through_headers=headers)
450+
interface._update_scan_num({"instrument_session": "cm12345-1", "instrument": "p46"})
451+
mock_post.assert_called_once()
452+
assert mock_post.call_args.kwargs["headers"] == headers
453+
454+
interface.begin_task(task=WorkerTask(task_id=None))
455+
interface._update_scan_num({"instrument_session": "cm12345-1", "instrument": "p46"})
456+
assert mock_post.call_count == 2
457+
assert mock_post.call_args.kwargs["headers"] == {}
458+
459+
421460
def test_configure_numtracker_with_no_numtracker_config_fails():
422461
conf = ApplicationConfig(
423462
env=EnvironmentConfig(metadata=MetadataConfig(instrument="p46")),

0 commit comments

Comments
 (0)