Skip to content

Commit fe53b58

Browse files
committed
Container scoping for NAb
1 parent 21b7858 commit fe53b58

5 files changed

Lines changed: 91 additions & 146 deletions

File tree

flow/src/org/labkey/flow/persist/AbstractContainerScopingTest.java

Lines changed: 0 additions & 146 deletions
This file was deleted.

flow/src/org/labkey/flow/persist/FlowManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.labkey.api.query.QueryService;
5959
import org.labkey.api.query.UserSchema;
6060
import org.labkey.api.security.User;
61+
import org.labkey.api.security.permissions.AbstractContainerScopingTest;
6162
import org.labkey.api.security.roles.EditorRole;
6263
import org.labkey.api.security.roles.ReaderRole;
6364
import org.labkey.api.util.DateUtil;

nab/src/org/labkey/nab/NabAssayController.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,11 @@ public ModelAndView getView(RenderAssayForm form, BindException errors) throws E
234234
{
235235
throw new NotFoundException("Run " + form.getRowId() + " does not exist.");
236236
}
237+
238+
// GitHub Issue #1892: getExpRun() resolves by global rowId; ensure the run belongs to the current container
239+
if (!run.getContainer().equals(getContainer()))
240+
throw new NotFoundException("Run " + form.getRowId() + " does not exist.");
241+
237242
File file = getDataHandler(run).getDataFile(run);
238243
if (file == null)
239244
{
@@ -449,6 +454,10 @@ public void validateCommand(DeleteRunForm form, Errors errors)
449454
if (_run == null)
450455
throw new NotFoundException("Run " + form.getRowId() + " does not exist.");
451456

457+
// GitHub Issue #1892: getExpRun() resolves by global rowId; ensure the run belongs to the current container
458+
if (!_run.getContainer().equals(getContainer()))
459+
throw new NotFoundException("Run " + form.getRowId() + " does not exist.");
460+
452461
if (form.isReupload())
453462
{
454463
_file = getDataHandler(_run).getDataFile(_run);

nab/src/org/labkey/nab/NabManager.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616

1717
package org.labkey.nab;
1818

19+
import jakarta.servlet.http.HttpServletResponse;
1920
import org.apache.logging.log4j.LogManager;
2021
import org.apache.logging.log4j.Logger;
22+
import org.junit.Before;
23+
import org.junit.Test;
2124
import org.labkey.api.assay.AssayService;
2225
import org.labkey.api.data.ColumnInfo;
2326
import org.labkey.api.data.Container;
@@ -38,13 +41,18 @@
3841
import org.labkey.api.query.FieldKey;
3942
import org.labkey.api.query.QueryService;
4043
import org.labkey.api.security.User;
44+
import org.labkey.api.security.permissions.AbstractContainerScopingTest;
45+
import org.labkey.api.security.roles.EditorRole;
46+
import org.labkey.api.security.roles.ReaderRole;
47+
import org.labkey.api.view.ActionURL;
4148
import org.labkey.api.study.Dataset;
4249
import org.labkey.api.study.Study;
4350
import org.labkey.api.study.StudyService;
4451
import org.labkey.api.util.PageFlowUtil;
4552
import org.labkey.api.util.Pair;
4653
import org.labkey.nab.query.NabProtocolSchema;
4754
import org.labkey.nab.query.NabRunDataTable;
55+
import org.springframework.mock.web.MockHttpServletResponse;
4856

4957
import java.sql.SQLException;
5058
import java.util.Collection;
@@ -206,4 +214,70 @@ public void getDataPropertiesFromNabRunData(NabRunDataTable nabRunDataTable, Str
206214
throw new RuntimeSQLException(e);
207215
}
208216
}
217+
218+
public static class ContainerScopingTestCase extends AbstractContainerScopingTest
219+
{
220+
private Container _folderA;
221+
private Container _folderB;
222+
private User _admin;
223+
224+
@Before
225+
public void setup()
226+
{
227+
_admin = getAdmin();
228+
_folderA = createContainer("A");
229+
_folderB = createContainer("B");
230+
}
231+
232+
@Test
233+
public void testDeleteRunContainerScoping() throws Exception
234+
{
235+
// Regression test for NAB-1. NabAssayController.DeleteRunAction resolves a
236+
// run via ExperimentService.getExpRun(rowId) from a global rowId and then deletes it.
237+
ExpProtocol protocol = ExperimentService.get().ensureSampleDerivationProtocol(_admin);
238+
ExpRun run = ExperimentService.get().createExperimentRun(_folderB, "scope-test-run");
239+
run.setProtocol(protocol);
240+
run.save(_admin);
241+
int rowId = run.getRowId();
242+
243+
ActionURL foreignUrl = new ActionURL(NabAssayController.DeleteRunAction.class, _folderA)
244+
.addParameter("rowId", rowId);
245+
246+
User deleterAonly = createUserInRole(_folderA, EditorRole.class);
247+
assertStatus(HttpServletResponse.SC_NOT_FOUND, post(foreignUrl, deleterAonly));
248+
assertNotNull("Foreign-container run must not be deleted", ExperimentService.get().getExpRun(rowId));
249+
250+
ActionURL ownUrl = new ActionURL(NabAssayController.DeleteRunAction.class, _folderB)
251+
.addParameter("rowId", rowId);
252+
assertStatus(HttpServletResponse.SC_FOUND, post(ownUrl, _admin));
253+
assertNull("Run should have been deleted from its own container", ExperimentService.get().getExpRun(rowId));
254+
}
255+
256+
@Test
257+
public void testDownloadDatafileContainerScoping() throws Exception
258+
{
259+
// Regression test for NAB-2. NabAssayController.DownloadDatafileAction resolves a run via
260+
// ExperimentService.getExpRun(rowId) from a global rowId
261+
ExpProtocol protocol = ExperimentService.get().ensureSampleDerivationProtocol(_admin);
262+
ExpRun run = ExperimentService.get().createExperimentRun(_folderB, "scope-test-download-run");
263+
run.setProtocol(protocol);
264+
run.save(_admin);
265+
int rowId = run.getRowId();
266+
267+
User readerAonly = createUserInRole(_folderA, ReaderRole.class);
268+
ActionURL foreignUrl = new ActionURL(NabAssayController.DownloadDatafileAction.class, _folderA)
269+
.addParameter("rowId", rowId);
270+
MockHttpServletResponse foreignResponse = get(foreignUrl, readerAonly);
271+
assertStatus(HttpServletResponse.SC_NOT_FOUND, foreignResponse);
272+
assertTrue("Foreign-container download must be rejected by the container check",
273+
foreignResponse.getContentAsString().contains("does not exist"));
274+
275+
ActionURL ownUrl = new ActionURL(NabAssayController.DownloadDatafileAction.class, _folderB)
276+
.addParameter("rowId", rowId);
277+
MockHttpServletResponse ownResponse = get(ownUrl, _admin);
278+
assertStatus(HttpServletResponse.SC_NOT_FOUND, ownResponse);
279+
assertTrue("Same-container request should advance past the container check to the data handler",
280+
ownResponse.getContentAsString().contains("is not a NAb run"));
281+
}
282+
}
209283
}

nab/src/org/labkey/nab/NabModule.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,11 @@ public Set<Class> getUnitTests()
122122
{
123123
return Set.of(PlateParserTests.class);
124124
}
125+
126+
@NotNull
127+
@Override
128+
public Set<Class> getIntegrationTests()
129+
{
130+
return Set.of(NabManager.ContainerScopingTestCase.class);
131+
}
125132
}

0 commit comments

Comments
 (0)