@@ -2159,6 +2159,155 @@ public void testFailureStoreAccessWithApiKeys() throws Exception {
21592159 expectThrowsWithApiKey (apiKey , new Search ("test1" ), 403 );
21602160 }
21612161
2162+ public void testFieldCapabilities () throws Exception {
2163+ setupDataStream ();
2164+
2165+ final Tuple <String , String > backingIndices = getSingleDataAndFailureIndices ("test1" );
2166+ final String dataIndexName = backingIndices .v1 ();
2167+ final String failureIndexName = backingIndices .v2 ();
2168+
2169+ createUser ("user" , PASSWORD , "role" );
2170+ upsertRole ("""
2171+ {
2172+ "cluster": ["all"],
2173+ "indices": [
2174+ {
2175+ "names": ["test*"],
2176+ "privileges": ["read"]
2177+ }
2178+ ]
2179+ }""" , "role" );
2180+
2181+ {
2182+ expectThrows (() -> performRequest ("user" , new Request ("POST" , "/test1::failures/_field_caps?fields=name" )), 403 );
2183+ assertFieldCapsResponseContainsIndexAndFields (
2184+ performRequest ("user" , new Request ("POST" , Strings .format ("/%s/_field_caps?fields=name" , "test1" ))),
2185+ dataIndexName ,
2186+ Set .of ("name" )
2187+ );
2188+ }
2189+
2190+ upsertRole ("""
2191+ {
2192+ "cluster": ["all"],
2193+ "indices": [
2194+ {
2195+ "names": ["test*"],
2196+ "privileges": ["read_failure_store"]
2197+ }
2198+ ]
2199+ }""" , "role" );
2200+
2201+ {
2202+ expectThrows (() -> performRequest ("user" , new Request ("POST" , "/test1/_field_caps?fields=name" )), 403 );
2203+ assertFieldCapsResponseContainsIndexAndFields (
2204+ performRequest ("user" , new Request ("POST" , "/test1::failures/_field_caps?fields=error.*" )),
2205+ failureIndexName ,
2206+ Set .of (
2207+ "error.message" ,
2208+ "error.pipeline_trace" ,
2209+ "error.processor_type" ,
2210+ "error.type" ,
2211+ "error.processor_tag" ,
2212+ "error.pipeline" ,
2213+ "error.stack_trace" ,
2214+ "error"
2215+ )
2216+ );
2217+ }
2218+
2219+ upsertRole ("""
2220+ {
2221+ "cluster": ["all"],
2222+ "indices": [
2223+ {
2224+ "names": ["test*"],
2225+ "privileges": ["read_failure_store"],
2226+ "field_security": {
2227+ "grant": ["error*"],
2228+ "except": ["error.message"]
2229+ }
2230+ }
2231+ ]
2232+ }""" , "role" );
2233+ {
2234+ expectThrows (() -> performRequest ("user" , new Request ("POST" , "/test1/_field_caps?fields=name" )), 403 );
2235+ assertFieldCapsResponseContainsIndexAndFields (
2236+ performRequest ("user" , new Request ("POST" , "/test1::failures/_field_caps?fields=error.*" )),
2237+ failureIndexName ,
2238+ Set .of (
2239+ "error.pipeline_trace" ,
2240+ "error.processor_type" ,
2241+ "error.type" ,
2242+ "error.processor_tag" ,
2243+ "error.pipeline" ,
2244+ "error.stack_trace" ,
2245+ "error"
2246+ )
2247+ );
2248+ }
2249+
2250+ upsertRole ("""
2251+ {
2252+ "cluster": ["all"],
2253+ "indices": [
2254+ {
2255+ "names": ["test*"],
2256+ "privileges": ["read_failure_store", "read"],
2257+ "field_security": {
2258+ "grant": ["error*", "name"],
2259+ "except": ["error.type"]
2260+ }
2261+ }
2262+ ]
2263+ }""" , "role" );
2264+ {
2265+ assertFieldCapsResponseContainsIndexAndFields (
2266+ performRequest ("user" , new Request ("POST" , "/test1/_field_caps?fields=name,age,email" )),
2267+ dataIndexName ,
2268+ Set .of ("name" )
2269+ );
2270+ assertFieldCapsResponseContainsIndexAndFields (
2271+ performRequest ("user" , new Request ("POST" , "/test1::failures/_field_caps?fields=error.*" )),
2272+ failureIndexName ,
2273+ Set .of (
2274+ "error.pipeline_trace" ,
2275+ "error.processor_type" ,
2276+ "error.message" ,
2277+ "error.processor_tag" ,
2278+ "error.pipeline" ,
2279+ "error.stack_trace" ,
2280+ "error"
2281+ )
2282+ );
2283+ }
2284+
2285+ upsertRole ("""
2286+ {
2287+ "cluster": ["all"],
2288+ "indices": [
2289+ {
2290+ "names": ["other*"],
2291+ "privileges": ["read_failure_store", "read"]
2292+ }
2293+ ]
2294+ }""" , "role" );
2295+ expectThrows (() -> performRequest ("user" , new Request ("POST" , "/test1/_field_caps?fields=name" )), 403 );
2296+ expectThrows (() -> performRequest ("user" , new Request ("POST" , "/test1::failures/_field_caps?fields=name" )), 403 );
2297+ }
2298+
2299+ private void assertFieldCapsResponseContainsIndexAndFields (Response fieldCapsResponse , String indexName , Set <String > expectedFields )
2300+ throws IOException {
2301+ assertOK (fieldCapsResponse );
2302+ ObjectPath objectPath = ObjectPath .createFromResponse (fieldCapsResponse );
2303+
2304+ List <String > indices = objectPath .evaluate ("indices" );
2305+ assertThat (indices , containsInAnyOrder (indexName ));
2306+
2307+ Map <String , Object > fields = objectPath .evaluate ("fields" );
2308+ assertThat (fields .keySet (), containsInAnyOrder (expectedFields .toArray ()));
2309+ }
2310+
21622311 public void testPit () throws Exception {
21632312 List <String > docIds = setupDataStream ();
21642313 String dataDocId = "1" ;
0 commit comments