@@ -2229,6 +2229,64 @@ public void testPit() throws Exception {
22292229 }
22302230 }
22312231
2232+ public void testScroll () throws Exception {
2233+ List <String > docIds = setupDataStream ();
2234+ String dataDocId = "1" ;
2235+ String failuresDocId = docIds .stream ().filter (id -> false == id .equals (dataDocId )).findFirst ().get ();
2236+
2237+ createUser ("user" , PASSWORD , "role" );
2238+ upsertRole ("""
2239+ {
2240+ "cluster": ["all"],
2241+ "indices": [
2242+ {
2243+ "names": ["test*"],
2244+ "privileges": ["read"]
2245+ }
2246+ ]
2247+ }""" , "role" );
2248+
2249+ {
2250+ // user has no access to failure store, searching failures should not work
2251+ expectThrows (
2252+ () -> performRequest ("user" , new Request ("POST" , Strings .format ("/%s/_search?scroll=1m" , "test1::failures" ))),
2253+ 403
2254+ );
2255+
2256+ // searching data should work
2257+ final String scrollId = performScrollSearchRequestAndAssertDocs ("test1" , dataDocId );
2258+
2259+ // further searches with scroll_id should work, but won't return any more hits
2260+ assertSearchHasNoHits (performScrollSearchRequest ("user" , scrollId ));
2261+
2262+ deleteScroll (scrollId );
2263+ }
2264+
2265+ upsertRole ("""
2266+ {
2267+ "cluster": ["all"],
2268+ "indices": [
2269+ {
2270+ "names": ["test*"],
2271+ "privileges": ["read_failure_store"]
2272+ }
2273+ ]
2274+ }""" , "role" );
2275+
2276+ {
2277+ // user has only read access to failure store, searching data should fail
2278+ expectThrows (() -> performRequest ("user" , new Request ("POST" , Strings .format ("/%s/_search?scroll=1m" , "test1" ))), 403 );
2279+
2280+ // searching failure store should work
2281+ final String scrollId = performScrollSearchRequestAndAssertDocs ("test1::failures" , failuresDocId );
2282+
2283+ // further searches with scroll_id should work, but won't return any more hits
2284+ assertSearchHasNoHits (performScrollSearchRequest ("user" , scrollId ));
2285+
2286+ deleteScroll (scrollId );
2287+ }
2288+ }
2289+
22322290 public void testDlsFls () throws Exception {
22332291 setupDataStream ();
22342292
@@ -2816,6 +2874,61 @@ protected void assertSearchResponseContainsExpectedIndicesAndFields(
28162874 }
28172875 }
28182876
2877+ private void deleteScroll (String scrollId ) throws IOException {
2878+ Request deleteScroll = new Request ("DELETE" , "/_search/scroll" );
2879+ deleteScroll .setJsonEntity (Strings .format ("""
2880+ {
2881+ "scroll_id": "%s"
2882+ }
2883+ """ , scrollId ));
2884+ Response deleteScrollResponse = performRequest ("user" , deleteScroll );
2885+ assertOK (deleteScrollResponse );
2886+ }
2887+
2888+ private String performScrollSearchRequestAndAssertDocs (String indexExpression , String docId ) throws IOException {
2889+ Response scrollResponse = performRequest ("user" , new Request ("POST" , Strings .format ("/%s/_search?scroll=1m" , indexExpression )));
2890+ assertOK (scrollResponse );
2891+
2892+ final SearchResponse searchResponse = SearchResponseUtils .parseSearchResponse (responseAsParser (scrollResponse ));
2893+ final String scrollId = searchResponse .getScrollId ();
2894+ assertThat (scrollId , notNullValue ());
2895+ try {
2896+ assertSearchContainsDocs (searchResponse , docId );
2897+ } finally {
2898+ searchResponse .decRef ();
2899+ }
2900+ return scrollId ;
2901+ }
2902+
2903+ private SearchResponse performScrollSearchRequest (String user , String scrollId ) throws IOException {
2904+ Request searchRequestWithScrollId = new Request ("POST" , "/_search/scroll" );
2905+ searchRequestWithScrollId .setJsonEntity (Strings .format ("""
2906+ {
2907+ "scroll": "1m",
2908+ "scroll_id": "%s"
2909+ }
2910+ """ , scrollId ));
2911+ Response response = performRequest (user , searchRequestWithScrollId );
2912+ assertOK (response );
2913+ return SearchResponseUtils .parseSearchResponse (responseAsParser (response ));
2914+ }
2915+
2916+ private static void assertSearchContainsDocs (SearchResponse searchResponse , String ... docIds ) {
2917+ SearchHit [] hits = searchResponse .getHits ().getHits ();
2918+ assertThat (hits .length , equalTo (docIds .length ));
2919+ List <String > actualDocIds = Arrays .stream (hits ).map (SearchHit ::getId ).toList ();
2920+ assertThat (actualDocIds , containsInAnyOrder (docIds ));
2921+ }
2922+
2923+ private static void assertSearchHasNoHits (SearchResponse searchResponse ) {
2924+ try {
2925+ SearchHit [] hits = searchResponse .getHits ().getHits ();
2926+ assertThat (hits .length , equalTo (0 ));
2927+ } finally {
2928+ searchResponse .decRef ();
2929+ }
2930+ }
2931+
28192932 static void addRandomPragmas (XContentBuilder builder ) throws IOException {
28202933 if (Build .current ().isSnapshot ()) {
28212934 Settings pragmas = randomPragmas ();
0 commit comments