Skip to content

Commit 2090d48

Browse files
Add multi-index comma-separated source FGAC bypass tests
Regression tests for authorization bypass where PPL multi-index queries (source = idx1, idx2) only evaluated permissions on the first index, allowing unauthorized access to subsequent indices. Tests cover: - Authorized index first, unauthorized second (the bypass vector) - Backtick-quoted variant of the same - Unauthorized index first (control: should be denied) - Both indices authorized (positive case) Signed-off-by: Finnegan Carroll <carrofin@amazon.com> Signed-off-by: Finn Carroll <carrofin@amazon.com>
1 parent 0b96cfc commit 2090d48

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

integ-test/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,11 +502,11 @@ testClusters.analyticsEngineSecurityIT {
502502
plugin(getJobSchedulerPlugin())
503503
plugin(getArrowBasePlugin())
504504
plugin(getArrowFlightRpcPlugin())
505+
plugin(getCompositeEnginePlugin())
505506
plugin(getAnalyticsEnginePlugin())
506507
plugin(getAnalyticsBackendLucenePlugin())
507508
plugin(getAnalyticsBackendDatafusionPlugin())
508509
plugin(getParquetDataFormatPlugin())
509-
plugin(getCompositeEnginePlugin())
510510
plugin ":opensearch-sql-plugin"
511511
// Arrow Flight / streaming transport requirements
512512
jvmArgs '--add-opens=java.base/java.nio=ALL-UNNAMED'

integ-test/src/test/java/org/opensearch/sql/security/AnalyticsEngineSecurityIT.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,68 @@ public void testPPLQueryWithWildcardIndexPartialAccessDenied() throws IOExceptio
393393
assertEquals(403, e.getResponse().getStatusLine().getStatusCode());
394394
}
395395

396+
// --- Multi-index comma-separated source tests (CVE: authorization bypass) ---
397+
398+
@Test
399+
public void testPPLMultiIndexDeniedWhenSecondIndexUnauthorized() throws IOException {
400+
// ALLOWED_USER has access to TEST_INDEX but NOT FORBIDDEN_INDEX.
401+
// A comma-separated source listing an authorized index first followed by an unauthorized
402+
// index must be denied. Regression: previously only the first index was checked.
403+
ResponseException e =
404+
assertThrows(
405+
ResponseException.class,
406+
() ->
407+
executePPLAsUser(
408+
"source = " + TEST_INDEX + ", " + FORBIDDEN_INDEX + " | fields name, age",
409+
ALLOWED_USER));
410+
assertEquals(403, e.getResponse().getStatusLine().getStatusCode());
411+
}
412+
413+
@Test
414+
public void testPPLMultiIndexDeniedWithBackticksAuthorizedFirst() throws IOException {
415+
// Same bypass vector using backtick-quoted index names.
416+
ResponseException e =
417+
assertThrows(
418+
ResponseException.class,
419+
() ->
420+
executePPLAsUser(
421+
"source = `" + TEST_INDEX + "`, `" + FORBIDDEN_INDEX + "` | fields name, age",
422+
ALLOWED_USER));
423+
assertEquals(403, e.getResponse().getStatusLine().getStatusCode());
424+
}
425+
426+
@Test
427+
public void testPPLMultiIndexDeniedWithUnauthorizedFirst() throws IOException {
428+
// Unauthorized index listed first — should also be denied.
429+
ResponseException e =
430+
assertThrows(
431+
ResponseException.class,
432+
() ->
433+
executePPLAsUser(
434+
"source = " + FORBIDDEN_INDEX + ", " + TEST_INDEX + " | fields name, age",
435+
ALLOWED_USER));
436+
assertEquals(403, e.getResponse().getStatusLine().getStatusCode());
437+
}
438+
439+
@Test
440+
public void testPPLMultiIndexAllowedWhenAllAuthorized() throws IOException {
441+
// ALLOWED_USER has access to TEST_INDEX. TEST_INDEX_2 is also covered by the
442+
// wildcard user's pattern but let's use allowed_user with both permitted indices.
443+
// Use WILDCARD_USER who has "analytics_security*" covering both TEST_INDEX and TEST_INDEX_2.
444+
try {
445+
JSONObject result =
446+
executePPLAsUser(
447+
"source = " + TEST_INDEX + ", " + TEST_INDEX_2 + " | fields name, age",
448+
WILDCARD_USER);
449+
assertTrue("Expected datarows in response", result.has("datarows"));
450+
} catch (ResponseException e) {
451+
assertNotEquals(
452+
"Expected auth to pass (not 403) when all indices are authorized",
453+
403,
454+
e.getResponse().getStatusLine().getStatusCode());
455+
}
456+
}
457+
396458
@Test
397459
public void testSQLQueryAllowedForAuthorizedUser() throws IOException {
398460
try {

0 commit comments

Comments
 (0)