@@ -2378,6 +2378,64 @@ public void testPit() throws Exception {
23782378 }
23792379 }
23802380
2381+ public void testScroll () throws Exception {
2382+ List <String > docIds = setupDataStream ();
2383+ String dataDocId = "1" ;
2384+ String failuresDocId = docIds .stream ().filter (id -> false == id .equals (dataDocId )).findFirst ().get ();
2385+
2386+ createUser ("user" , PASSWORD , "role" );
2387+ upsertRole ("""
2388+ {
2389+ "cluster": ["all"],
2390+ "indices": [
2391+ {
2392+ "names": ["test*"],
2393+ "privileges": ["read"]
2394+ }
2395+ ]
2396+ }""" , "role" );
2397+
2398+ {
2399+ // user has no access to failure store, searching failures should not work
2400+ expectThrows (
2401+ () -> performRequest ("user" , new Request ("POST" , Strings .format ("/%s/_search?scroll=1m" , "test1::failures" ))),
2402+ 403
2403+ );
2404+
2405+ // searching data should work
2406+ final String scrollId = performScrollSearchRequestAndAssertDocs ("test1" , dataDocId );
2407+
2408+ // further searches with scroll_id should work, but won't return any more hits
2409+ assertSearchHasNoHits (performScrollSearchRequest ("user" , scrollId ));
2410+
2411+ deleteScroll (scrollId );
2412+ }
2413+
2414+ upsertRole ("""
2415+ {
2416+ "cluster": ["all"],
2417+ "indices": [
2418+ {
2419+ "names": ["test*"],
2420+ "privileges": ["read_failure_store"]
2421+ }
2422+ ]
2423+ }""" , "role" );
2424+
2425+ {
2426+ // user has only read access to failure store, searching data should fail
2427+ expectThrows (() -> performRequest ("user" , new Request ("POST" , Strings .format ("/%s/_search?scroll=1m" , "test1" ))), 403 );
2428+
2429+ // searching failure store should work
2430+ final String scrollId = performScrollSearchRequestAndAssertDocs ("test1::failures" , failuresDocId );
2431+
2432+ // further searches with scroll_id should work, but won't return any more hits
2433+ assertSearchHasNoHits (performScrollSearchRequest ("user" , scrollId ));
2434+
2435+ deleteScroll (scrollId );
2436+ }
2437+ }
2438+
23812439 public void testDlsFls () throws Exception {
23822440 setupDataStream ();
23832441
@@ -2965,6 +3023,61 @@ protected void assertSearchResponseContainsExpectedIndicesAndFields(
29653023 }
29663024 }
29673025
3026+ private void deleteScroll (String scrollId ) throws IOException {
3027+ Request deleteScroll = new Request ("DELETE" , "/_search/scroll" );
3028+ deleteScroll .setJsonEntity (Strings .format ("""
3029+ {
3030+ "scroll_id": "%s"
3031+ }
3032+ """ , scrollId ));
3033+ Response deleteScrollResponse = performRequest ("user" , deleteScroll );
3034+ assertOK (deleteScrollResponse );
3035+ }
3036+
3037+ private String performScrollSearchRequestAndAssertDocs (String indexExpression , String docId ) throws IOException {
3038+ Response scrollResponse = performRequest ("user" , new Request ("POST" , Strings .format ("/%s/_search?scroll=1m" , indexExpression )));
3039+ assertOK (scrollResponse );
3040+
3041+ final SearchResponse searchResponse = SearchResponseUtils .parseSearchResponse (responseAsParser (scrollResponse ));
3042+ final String scrollId = searchResponse .getScrollId ();
3043+ assertThat (scrollId , notNullValue ());
3044+ try {
3045+ assertSearchContainsDocs (searchResponse , docId );
3046+ } finally {
3047+ searchResponse .decRef ();
3048+ }
3049+ return scrollId ;
3050+ }
3051+
3052+ private SearchResponse performScrollSearchRequest (String user , String scrollId ) throws IOException {
3053+ Request searchRequestWithScrollId = new Request ("POST" , "/_search/scroll" );
3054+ searchRequestWithScrollId .setJsonEntity (Strings .format ("""
3055+ {
3056+ "scroll": "1m",
3057+ "scroll_id": "%s"
3058+ }
3059+ """ , scrollId ));
3060+ Response response = performRequest (user , searchRequestWithScrollId );
3061+ assertOK (response );
3062+ return SearchResponseUtils .parseSearchResponse (responseAsParser (response ));
3063+ }
3064+
3065+ private static void assertSearchContainsDocs (SearchResponse searchResponse , String ... docIds ) {
3066+ SearchHit [] hits = searchResponse .getHits ().getHits ();
3067+ assertThat (hits .length , equalTo (docIds .length ));
3068+ List <String > actualDocIds = Arrays .stream (hits ).map (SearchHit ::getId ).toList ();
3069+ assertThat (actualDocIds , containsInAnyOrder (docIds ));
3070+ }
3071+
3072+ private static void assertSearchHasNoHits (SearchResponse searchResponse ) {
3073+ try {
3074+ SearchHit [] hits = searchResponse .getHits ().getHits ();
3075+ assertThat (hits .length , equalTo (0 ));
3076+ } finally {
3077+ searchResponse .decRef ();
3078+ }
3079+ }
3080+
29683081 static void addRandomPragmas (XContentBuilder builder ) throws IOException {
29693082 if (Build .current ().isSnapshot ()) {
29703083 Settings pragmas = randomPragmas ();
0 commit comments