Skip to content

Commit d849ff9

Browse files
Add security tests
1 parent fe8c080 commit d849ff9

File tree

2 files changed

+124
-68
lines changed
  • x-pack/plugin/esql

2 files changed

+124
-68
lines changed

x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java

Lines changed: 122 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -592,15 +592,20 @@ record Listen(long timestamp, String songId, double duration) {
592592
}
593593

594594
public void testLookupJoinIndexAllowed() throws Exception {
595+
testLookupJoinIndexAllowedHelper(false);
596+
testLookupJoinIndexAllowedHelper(true);
597+
}
598+
599+
private void testLookupJoinIndexAllowedHelper(boolean useExpressionJoin) throws Exception {
595600
assumeTrue(
596601
"Requires LOOKUP JOIN capability",
597602
hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName()))
598603
);
599604

600-
Response resp = runESQLCommand(
601-
"metadata1_read2",
602-
"ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org"
603-
);
605+
String query = useExpressionJoin
606+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, org"
607+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org";
608+
Response resp = runESQLCommand("metadata1_read2", query);
604609
assertOK(resp);
605610
Map<String, Object> respMap = entityAsMap(resp);
606611
assertThat(
@@ -610,25 +615,19 @@ public void testLookupJoinIndexAllowed() throws Exception {
610615
assertThat(respMap.get("values"), equalTo(List.of(List.of(40.0, "sales"))));
611616

612617
// user is not allowed to use the alias (but is allowed to use the index)
613-
expectThrows(
614-
ResponseException.class,
615-
() -> runESQLCommand(
616-
"metadata1_read2",
617-
"ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value | KEEP x, org"
618-
)
619-
);
618+
String aliasQuery = useExpressionJoin
619+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-second-alias ON value_left == value | KEEP x, org"
620+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value | KEEP x, org";
621+
expectThrows(ResponseException.class, () -> runESQLCommand("metadata1_read2", aliasQuery));
620622

621623
// user is not allowed to use the index (but is allowed to use the alias)
622-
expectThrows(
623-
ResponseException.class,
624-
() -> runESQLCommand("metadata1_alias_read2", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org")
625-
);
624+
String indexQuery = useExpressionJoin
625+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, org"
626+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org";
627+
expectThrows(ResponseException.class, () -> runESQLCommand("metadata1_alias_read2", indexQuery));
626628

627629
// user has permission on the alias, and can read the key
628-
resp = runESQLCommand(
629-
"metadata1_alias_read2",
630-
"ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value | KEEP x, org"
631-
);
630+
resp = runESQLCommand("metadata1_alias_read2", aliasQuery);
632631
assertOK(resp);
633632
respMap = entityAsMap(resp);
634633
assertThat(
@@ -638,10 +637,10 @@ public void testLookupJoinIndexAllowed() throws Exception {
638637
assertThat(respMap.get("values"), equalTo(List.of(List.of(40.0, "sales"))));
639638

640639
// user has permission on the alias, but can't read the key (doc level security at role level)
641-
resp = runESQLCommand(
642-
"metadata1_alias_read2",
643-
"ROW x = 32.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value | KEEP x, org"
644-
);
640+
String aliasQuery2 = useExpressionJoin
641+
? "ROW x = 32.0 | EVAL value_left = x | LOOKUP JOIN lookup-second-alias ON value_left == value | KEEP x, org"
642+
: "ROW x = 32.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value | KEEP x, org";
643+
resp = runESQLCommand("metadata1_alias_read2", aliasQuery2);
645644
assertOK(resp);
646645
respMap = entityAsMap(resp);
647646
assertThat(
@@ -656,7 +655,10 @@ public void testLookupJoinIndexAllowed() throws Exception {
656655
assertThat(row.get(1), is(nullValue()));
657656

658657
// user has permission on the alias, the alias has a filter that doesn't allow to see the value
659-
resp = runESQLCommand("alias_user1", "ROW x = 12.0 | EVAL value = x | LOOKUP JOIN lookup-first-alias ON value | KEEP x, org");
658+
String aliasQuery3 = useExpressionJoin
659+
? "ROW x = 12.0 | EVAL value_left = x | LOOKUP JOIN lookup-first-alias ON value_left == value | KEEP x, org"
660+
: "ROW x = 12.0 | EVAL value = x | LOOKUP JOIN lookup-first-alias ON value | KEEP x, org";
661+
resp = runESQLCommand("alias_user1", aliasQuery3);
660662
assertOK(resp);
661663
respMap = entityAsMap(resp);
662664
assertThat(
@@ -671,7 +673,10 @@ public void testLookupJoinIndexAllowed() throws Exception {
671673
assertThat(row.get(1), is(nullValue()));
672674

673675
// user has permission on the alias, the alias has a filter that allows to see the value
674-
resp = runESQLCommand("alias_user1", "ROW x = 31.0 | EVAL value = x | LOOKUP JOIN lookup-first-alias ON value | KEEP x, org");
676+
String aliasQuery4 = useExpressionJoin
677+
? "ROW x = 31.0 | EVAL value_left = x | LOOKUP JOIN lookup-first-alias ON value_left == value | KEEP x, org"
678+
: "ROW x = 31.0 | EVAL value = x | LOOKUP JOIN lookup-first-alias ON value | KEEP x, org";
679+
resp = runESQLCommand("alias_user1", aliasQuery4);
675680
assertOK(resp);
676681
respMap = entityAsMap(resp);
677682
assertThat(
@@ -683,12 +688,19 @@ public void testLookupJoinIndexAllowed() throws Exception {
683688

684689
@SuppressWarnings("unchecked")
685690
public void testLookupJoinDocLevelSecurity() throws Exception {
691+
testLookupJoinDocLevelSecurityHelper(false);
692+
testLookupJoinDocLevelSecurityHelper(true);
693+
}
694+
695+
private void testLookupJoinDocLevelSecurityHelper(boolean useExpressionJoin) throws Exception {
686696
assumeTrue(
687697
"Requires LOOKUP JOIN capability",
688698
hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName()))
689699
);
690-
691-
Response resp = runESQLCommand("dls_user", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org");
700+
String query = useExpressionJoin
701+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, org"
702+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org";
703+
Response resp = runESQLCommand("dls_user", query);
692704
assertOK(resp);
693705
Map<String, Object> respMap = entityAsMap(resp);
694706
assertThat(
@@ -698,7 +710,10 @@ public void testLookupJoinDocLevelSecurity() throws Exception {
698710

699711
assertThat(respMap.get("values"), equalTo(List.of(Arrays.asList(40.0, null))));
700712

701-
resp = runESQLCommand("dls_user", "ROW x = 32.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org");
713+
query = useExpressionJoin
714+
? "ROW x = 32.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, org"
715+
: "ROW x = 32.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org";
716+
resp = runESQLCommand("dls_user", query);
702717
assertOK(resp);
703718
respMap = entityAsMap(resp);
704719
assertThat(
@@ -709,7 +724,10 @@ public void testLookupJoinDocLevelSecurity() throws Exception {
709724

710725
// same, but with a user that has two dls roles that allow him more visibility
711726

712-
resp = runESQLCommand("dls_user2", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org");
727+
query = useExpressionJoin
728+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, org"
729+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org";
730+
resp = runESQLCommand("dls_user2", query);
713731
assertOK(resp);
714732
respMap = entityAsMap(resp);
715733
assertThat(
@@ -719,7 +737,10 @@ public void testLookupJoinDocLevelSecurity() throws Exception {
719737

720738
assertThat(respMap.get("values"), equalTo(List.of(Arrays.asList(40.0, "sales"))));
721739

722-
resp = runESQLCommand("dls_user2", "ROW x = 32.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org");
740+
query = useExpressionJoin
741+
? "ROW x = 32.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, org"
742+
: "ROW x = 32.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org";
743+
resp = runESQLCommand("dls_user2", query);
723744
assertOK(resp);
724745
respMap = entityAsMap(resp);
725746
assertThat(
@@ -732,12 +753,20 @@ public void testLookupJoinDocLevelSecurity() throws Exception {
732753

733754
@SuppressWarnings("unchecked")
734755
public void testLookupJoinFieldLevelSecurity() throws Exception {
756+
testLookupJoinFieldLevelSecurityHelper(false);
757+
testLookupJoinFieldLevelSecurityHelper(true);
758+
}
759+
760+
private void testLookupJoinFieldLevelSecurityHelper(boolean useExpressionJoin) throws Exception {
735761
assumeTrue(
736762
"Requires LOOKUP JOIN capability",
737763
hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName()))
738764
);
739765

740-
Response resp = runESQLCommand("fls_user2", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value");
766+
String query = useExpressionJoin
767+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, value, org"
768+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, value, org";
769+
Response resp = runESQLCommand("fls_user2", query);
741770
assertOK(resp);
742771
Map<String, Object> respMap = entityAsMap(resp);
743772
assertThat(
@@ -751,7 +780,10 @@ public void testLookupJoinFieldLevelSecurity() throws Exception {
751780
)
752781
);
753782

754-
resp = runESQLCommand("fls_user3", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value");
783+
String query2 = useExpressionJoin
784+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-user2 ON value_left == value | KEEP x, value, org, other"
785+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, value, org, other";
786+
resp = runESQLCommand("fls_user3", query2);
755787
assertOK(resp);
756788
respMap = entityAsMap(resp);
757789
assertThat(
@@ -767,7 +799,7 @@ public void testLookupJoinFieldLevelSecurity() throws Exception {
767799

768800
);
769801

770-
resp = runESQLCommand("fls_user4", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value");
802+
resp = runESQLCommand("fls_user4", query);
771803
assertOK(resp);
772804
respMap = entityAsMap(resp);
773805
assertThat(
@@ -781,21 +813,35 @@ public void testLookupJoinFieldLevelSecurity() throws Exception {
781813
)
782814
);
783815

784-
ResponseException error = expectThrows(
785-
ResponseException.class,
786-
() -> runESQLCommand("fls_user4_1", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value")
787-
);
788-
assertThat(error.getMessage(), containsString("Unknown column [value] in right side of join"));
816+
ResponseException error = expectThrows(ResponseException.class, () -> runESQLCommand("fls_user4_1", query));
789817
assertThat(error.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
818+
if (useExpressionJoin) {
819+
assertThat(
820+
error.getMessage(),
821+
containsString(
822+
"Join condition must be between one attribute on the left side and one attribute on the right side of the join"
823+
)
824+
);
825+
} else {
826+
assertThat(error.getMessage(), containsString("Unknown column [value] in right side of join"));
827+
}
790828
}
791829

792830
public void testLookupJoinFieldLevelSecurityOnAlias() throws Exception {
831+
testLookupJoinFieldLevelSecurityOnAliasHelper(false);
832+
testLookupJoinFieldLevelSecurityOnAliasHelper(true);
833+
}
834+
835+
private void testLookupJoinFieldLevelSecurityOnAliasHelper(boolean useExpressionJoin) throws Exception {
793836
assumeTrue(
794837
"Requires LOOKUP JOIN capability",
795838
hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName()))
796839
);
797840

798-
Response resp = runESQLCommand("fls_user2_alias", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value");
841+
String query = useExpressionJoin
842+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-second-alias ON value_left == value | KEEP x, value, org"
843+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value | KEEP x, value, org";
844+
Response resp = runESQLCommand("fls_user2_alias", query);
799845
assertOK(resp);
800846
Map<String, Object> respMap = entityAsMap(resp);
801847
assertThat(
@@ -809,7 +855,10 @@ public void testLookupJoinFieldLevelSecurityOnAlias() throws Exception {
809855
)
810856
);
811857

812-
resp = runESQLCommand("fls_user3_alias", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value");
858+
String query2 = useExpressionJoin
859+
? "ROW x = 40.0 | EVAL value_left = x | LOOKUP JOIN lookup-second-alias ON value_left == value | KEEP x, value, org, other"
860+
: "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value | KEEP x, value, org, other";
861+
resp = runESQLCommand("fls_user3_alias", query2);
813862
assertOK(resp);
814863
respMap = entityAsMap(resp);
815864
assertThat(
@@ -825,7 +874,7 @@ public void testLookupJoinFieldLevelSecurityOnAlias() throws Exception {
825874

826875
);
827876

828-
resp = runESQLCommand("fls_user4_alias", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value");
877+
resp = runESQLCommand("fls_user4_alias", query);
829878
assertOK(resp);
830879
respMap = entityAsMap(resp);
831880
assertThat(
@@ -839,48 +888,56 @@ public void testLookupJoinFieldLevelSecurityOnAlias() throws Exception {
839888
)
840889
);
841890

842-
ResponseException error = expectThrows(
843-
ResponseException.class,
844-
() -> runESQLCommand("fls_user4_1_alias", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value")
845-
);
846-
assertThat(error.getMessage(), containsString("Unknown column [value] in right side of join"));
891+
ResponseException error = expectThrows(ResponseException.class, () -> runESQLCommand("fls_user4_1_alias", query));
847892
assertThat(error.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
893+
if (useExpressionJoin) {
894+
assertThat(
895+
error.getMessage(),
896+
containsString(
897+
"Join condition must be between one attribute on the left side and one attribute on the right side of the join"
898+
)
899+
);
900+
} else {
901+
assertThat(error.getMessage(), containsString("Unknown column [value] in right side of join"));
902+
}
848903
}
849904

850905
public void testLookupJoinIndexForbidden() throws Exception {
906+
testLookupJoinIndexForbiddenHelper(false);
907+
testLookupJoinIndexForbiddenHelper(true);
908+
}
909+
910+
private void testLookupJoinIndexForbiddenHelper(boolean useExpressionJoin) throws Exception {
851911
assumeTrue(
852912
"Requires LOOKUP JOIN capability",
853913
hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName()))
854914
);
855915

856-
var resp = expectThrows(
857-
ResponseException.class,
858-
() -> runESQLCommand("metadata1_read2", "FROM lookup-user2 | EVAL value = 10.0 | LOOKUP JOIN lookup-user1 ON value | KEEP x")
859-
);
916+
String query1 = useExpressionJoin
917+
? "FROM lookup-user2 | EVAL value_left = 10.0 | LOOKUP JOIN lookup-user1 ON value_left == value | KEEP x"
918+
: "FROM lookup-user2 | EVAL value = 10.0 | LOOKUP JOIN lookup-user1 ON value | KEEP x";
919+
var resp = expectThrows(ResponseException.class, () -> runESQLCommand("metadata1_read2", query1));
860920
assertThat(resp.getMessage(), containsString("Unknown index [lookup-user1]"));
861921
assertThat(resp.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
862922

863-
resp = expectThrows(
864-
ResponseException.class,
865-
() -> runESQLCommand(
866-
"metadata1_read2",
867-
"FROM lookup-user2 | EVAL value = 10.0 | LOOKUP JOIN lookup-first-alias ON value | KEEP x"
868-
)
869-
);
923+
String query2 = useExpressionJoin
924+
? "FROM lookup-user2 | EVAL value_left = 10.0 | LOOKUP JOIN lookup-first-alias ON value_left == value | KEEP x"
925+
: "FROM lookup-user2 | EVAL value = 10.0 | LOOKUP JOIN lookup-first-alias ON value | KEEP x";
926+
resp = expectThrows(ResponseException.class, () -> runESQLCommand("metadata1_read2", query2));
870927
assertThat(resp.getMessage(), containsString("Unknown index [lookup-first-alias]"));
871928
assertThat(resp.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
872929

873-
resp = expectThrows(
874-
ResponseException.class,
875-
() -> runESQLCommand("metadata1_read2", "ROW x = 10.0 | EVAL value = x | LOOKUP JOIN lookup-user1 ON value | KEEP x")
876-
);
930+
String query3 = useExpressionJoin
931+
? "ROW x = 10.0 | EVAL value_left = x | LOOKUP JOIN lookup-user1 ON value_left == value | KEEP x"
932+
: "ROW x = 10.0 | EVAL value = x | LOOKUP JOIN lookup-user1 ON value | KEEP x";
933+
resp = expectThrows(ResponseException.class, () -> runESQLCommand("metadata1_read2", query3));
877934
assertThat(resp.getMessage(), containsString("Unknown index [lookup-user1]"));
878935
assertThat(resp.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
879936

880-
resp = expectThrows(
881-
ResponseException.class,
882-
() -> runESQLCommand("alias_user1", "ROW x = 10.0 | EVAL value = x | LOOKUP JOIN lookup-user1 ON value | KEEP x")
883-
);
937+
String query4 = useExpressionJoin
938+
? "ROW x = 10.0 | EVAL value_left = x | LOOKUP JOIN lookup-user1 ON value_left == value | KEEP x"
939+
: "ROW x = 10.0 | EVAL value = x | LOOKUP JOIN lookup-user1 ON value | KEEP x";
940+
resp = expectThrows(ResponseException.class, () -> runESQLCommand("alias_user1", query4));
884941
assertThat(resp.getMessage(), containsString("Unknown index [lookup-user1]"));
885942
assertThat(resp.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
886943
}

0 commit comments

Comments
 (0)